<?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:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Chris Jensen]]></title><description><![CDATA[Software Engineer specializing in HIPAA implementation]]></description><link>https://chrisjensen.dev/</link><image><url>https://chrisjensen.dev/favicon.png</url><title>Chris Jensen</title><link>https://chrisjensen.dev/</link></image><generator>Ghost 5.61</generator><lastBuildDate>Mon, 04 May 2026 12:12:34 GMT</lastBuildDate><atom:link href="https://chrisjensen.dev/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Automating Your Workflow with GitHub Actions: A Practical Guide]]></title><description><![CDATA[<p>In the ever-evolving landscape of software development, efficiency and automation are the keystones that keep the wheels turning. Today, I&apos;m excited to share with you a powerful tool that has significantly streamlined my development process: GitHub Actions. Whether you&apos;re looking to enhance your continuous integration (CI)</p>]]></description><link>https://chrisjensen.dev/github-actions/</link><guid isPermaLink="false">6516ca751351cf000747a50c</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Sat, 24 Feb 2024 12:45:37 GMT</pubDate><media:content url="https://chrisjensen.dev/content/images/2024/02/IMG_0039.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://chrisjensen.dev/content/images/2024/02/IMG_0039.jpeg" alt="Automating Your Workflow with GitHub Actions: A Practical Guide"><p>In the ever-evolving landscape of software development, efficiency and automation are the keystones that keep the wheels turning. Today, I&apos;m excited to share with you a powerful tool that has significantly streamlined my development process: GitHub Actions. Whether you&apos;re looking to enhance your continuous integration (CI) and continuous delivery (CD) processes, or simply automate repetitive tasks, GitHub Actions can transform the way you approach development workflows.</p>
<h2 id="what-are-github-actions">What Are GitHub Actions?</h2>
<p>At its core, GitHub Actions is an automation powerhouse, provided by GitHub, that allows you to automate your software workflows directly within your repository. What makes it stand out is its event-driven nature, enabling actions to be triggered by specific GitHub events like a push, a pull request, or on a scheduled basis. This flexibility means you can automate just about anything, from building and testing your code to deploying it.</p>
<h2 id="setting-up-github-actions">Setting Up GitHub Actions</h2>
<p>The beauty of GitHub Actions lies in its simplicity. You define your workflows in YAML files within the <code>.github/workflows</code> directory of your repository. These workflows can be as simple or complex as you need, orchestrating every step of your build, test, and deployment processes.</p>
<p>Here&apos;s a step-by-step guide to get you started:</p>
<ol><li><strong>Navigate to the <code>.github/workflows</code> directory</strong>: This is where all your workflow files will live. If it doesn&#x2019;t exist yet, now&#x2019;s the time to create it.</li><li><strong>Create a new YAML file</strong>: Name it something descriptive, like <code>ci.yml</code>, to indicate its purpose. This file will contain the configuration for your workflow.</li><li><strong>Define your workflow</strong>: Start with specifying the events that will trigger this workflow. It could be on a push or pull request to specific branches, or even a scheduled event. Then, outline the jobs and steps that should be executed. Here&apos;s a basic example:</li></ol>
<pre><code class="language-yaml">name: CI Workflow
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Run a script
      run: echo Hello, world!
</code></pre>
<h2 id="testing-github-actions-locally-with-act">Testing GitHub Actions Locally with <code>act</code></h2>
<p>Before pushing your workflows to the live repository, you&apos;ll want to test them to ensure they work as expected. Enter <code>act</code>, a tool that allows you to run your GitHub Actions locally. This is especially useful for debugging and iterating on your workflows without the wait time associated with pushing changes.</p>
<h3 id="getting-started-with-act">Getting Started with <code>act</code></h3>
<ol><li><strong>Install <code>act</code></strong>: If you&apos;re using a Mac, simply run <code>brew install act</code> in your terminal. This will install the <code>act</code> tool, which simulates GitHub Actions on your local machine.</li><li><strong>Run your workflow</strong>: With <code>act</code>, you can trigger your workflow by simulating a GitHub event. For example, to simulate a push event, you&apos;d use:</li></ol>
<pre><code class="language-bash">act push -W .github/workflows/your_workflow.yml --secret-file .env.local --container-architecture linux/amd64
</code></pre>
<p>This command allows you to specify which workflow to run, simulate secret variables, and ensure compatibility with your machine&apos;s architecture.</p>
<h2 id="managing-secrets-and-variables">Managing Secrets and Variables</h2>
<p>Keeping sensitive information secure while automating your workflows is crucial. GitHub Actions allows you to use &apos;secrets&apos; for sensitive data and environment variables for non-sensitive data. Secrets are encrypted and can be added to your repository or organization settings, ensuring they are not exposed in logs or workflow files.</p>
<h2 id="conclusion">Conclusion</h2>
<p>GitHub Actions offers a robust, flexible platform for automating software workflows, significantly reducing the friction in the CI/CD process. By leveraging GitHub Actions and tools like <code>act</code> for local testing, developers can ensure their workflows are efficient, secure, and error-free.</p>
<p>Remember, the key to mastering GitHub Actions is experimentation and iteration. Don&apos;t be afraid to explore the vast ecosystem of actions available in the GitHub Marketplace and to share your custom actions with the community.</p>
<p>Happy automating!</p>]]></content:encoded></item><item><title><![CDATA[Don’t keep ‘em separated]]></title><description><![CDATA[<p>Languages that is.  Separation of concerns has often been taught that the languages and technologies are where we should separate our concerns.  In my 10+ years doing development, the amount of times I have needed my SQL separate from my backend code, or my CSS separate from my HTML code</p>]]></description><link>https://chrisjensen.dev/you-shouldnt-keep-em-separated/</link><guid isPermaLink="false">65c39d891351cf000747a9f8</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Sat, 17 Feb 2024 12:45:55 GMT</pubDate><media:content url="https://chrisjensen.dev/content/images/2024/02/IMG_0036.png" medium="image"/><content:encoded><![CDATA[<img src="https://chrisjensen.dev/content/images/2024/02/IMG_0036.png" alt="Don&#x2019;t keep &#x2018;em separated"><p>Languages that is.  Separation of concerns has often been taught that the languages and technologies are where we should separate our concerns.  In my 10+ years doing development, the amount of times I have needed my SQL separate from my backend code, or my CSS separate from my HTML code has been next to never.  If you are separating your concerns this way, consider a new approach.  Separation my job or feature.  </p>
<h3 id="understanding-separation-of-concerns">Understanding Separation of Concerns</h3>
<p>At its heart, the Separation of Concerns (SoC) is a design principle for organizing software into distinct sections, where each section addresses a separate &#x2018;concern&#x2019;. A concern is essentially any piece of interest or focus in a program. Why does this matter? Because, in the sprawling complexity of modern web development, keeping our code clean, understandable, and manageable is not just a luxury; it&#x2019;s a necessity.</p>
<h3 id="the-importance-of-separation-of-concerns">The Importance of Separation of Concerns</h3>
<p>SoC is not just about writing code; it&#x2019;s about writing stories. Each piece of your application tells a part of the story, and SoC ensures that these stories remain distinct and coherent. This clarity is not for the computer&#x2019;s benefit&#x2014;it doesn&#x2019;t care how tangled our narratives become&#x2014;but for us, the humans who spend more time reading code than writing it.</p>
<p>By dividing our applications into manageable, focused areas, we drastically improve our ability to maintain and evolve our codebase. Changes in one area, such as the data model, have minimal impact on others, like the UI. This isolation reduces bugs, simplifies debugging, and speeds up development, as teams can work on separate concerns simultaneously without stepping on each other&#x2019;s toes.</p>
<h3 id="the-misconception-of-language-based-separation-in-web-development">The Misconception of Language-Based Separation in Web Development</h3>
<p>Traditionally, we&#x2019;ve been taught to split our concerns by language: HTML for structure, CSS for presentation, and JavaScript for behavior. While this approach seems logical, it fundamentally misunderstands the nature of our work. We don&#x2019;t create websites or apps by neatly compartmentalizing structure, style, and logic. Our work is messier, intertwined, and ultimately, more holistic.</p>
<p>Take Angular, for instance. Angular&#x2019;s component-based architecture encourages developers to think about UIs as a collection of isolated units. However, each component intertwines HTML, CSS, and JavaScript, challenging the traditional SoC model. Critics argue this blending muddles concerns, but I&#x2019;d argue the opposite. Angular understands that the real &#x2018;concern&#x2019; is the component itself&#x2014;its functionality, appearance, and behavior as a cohesive unit. The issue with Angular, and similar frameworks, lies not in their lack of separation but in how they define a &#x2018;concern.&#x2019;</p>
<h3 id="reframing-separation-of-concerns-finishing-jobs-not-tasks">Reframing Separation of Concerns: Finishing Jobs, Not Tasks</h3>
<p>The true power of SoC emerges when we focus on completing &#x2018;jobs&#x2019; rather than performing &#x2018;tasks&#x2019;. Consider a developer tasked with adding a feature to a web application. If we adhere too rigidly to language-based separation, we risk fragmenting their focus across disparate files and folders, losing sight of the job&#x2019;s overarching goal.</p>
<p>Instead, imagine if our focus shifts to finishing a specific job, such as implementing a user authentication feature. This feature spans multiple &#x2018;concerns&#x2019;&#x2014;UI elements, styling, validation logic&#x2014;but it&#x2019;s a single, coherent job. By grouping all related aspects of this job together, developers can think in terms of features, not files, leading to more intuitive and maintainable codebases.</p>
<p>This approach doesn&#x2019;t dismiss SoC; rather, it redefines it. It encourages us to ask: &#x201C;What job am I trying to finish?&#x201D; rather than &#x201C;What specific task am I performing?&#x201D; This mindset shift can lead to more effective organization of code, reducing the cognitive load on developers and enhancing collaboration within teams.</p>
<h3 id="conclusion">Conclusion</h3>
<p>Separation of Concerns is a foundational principle in software engineering, but its true essence often gets lost in translation. It&#x2019;s not about segregating code by languages or technologies but about organizing it in a way that reflects the real-world jobs we&#x2019;re trying to accomplish. As web development evolves, so too should our understanding and application of SoC. By focusing on finishing jobs rather than ticking off tasks, we can create more robust, intuitive, and maintainable applications that stand the test of time.</p>
<p>In the spirit of continuous learning and improvement, let&#x2019;s challenge ourselves to rethink our approach to SoC, embracing the complexity and nuance of building modern web applications. Together, we can write not just better code, but better stories.</p>]]></content:encoded></item><item><title><![CDATA[Why Comparing Frameworks Like Rails, Laravel, .NET, and Java is Usually the Wrong Question]]></title><description><![CDATA[<p>In the world of software development, the debate over which framework or language reigns supreme is as old as the field itself. Whether it&apos;s Rails vs. Laravel, .NET vs. Java, or any other comparison, the conversation often boils down to one question: which is faster? But if there&</p>]]></description><link>https://chrisjensen.dev/why-comparing-frameworks-like-rails-laravel-net-and-java-is-usually-the-wrong-question/</link><guid isPermaLink="false">65c405961351cf000747aa27</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Fri, 09 Feb 2024 12:45:05 GMT</pubDate><media:content url="https://chrisjensen.dev/content/images/2024/02/IMG_0038.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://chrisjensen.dev/content/images/2024/02/IMG_0038.jpeg" alt="Why Comparing Frameworks Like Rails, Laravel, .NET, and Java is Usually the Wrong Question"><p>In the world of software development, the debate over which framework or language reigns supreme is as old as the field itself. Whether it&apos;s Rails vs. Laravel, .NET vs. Java, or any other comparison, the conversation often boils down to one question: which is faster? But if there&apos;s one thing I&apos;ve learned over the years, it&apos;s that this is usually the wrong question to ask. Let me tell you why.</p>
<h4 id="changing-your-framework-now-won%E2%80%99t-solve-your-problems">Changing Your Framework Now Won&#x2019;t Solve Your Problems</h4>
<p>Throughout my career, I&apos;ve been a part of many teams: team .NET, team CodeIgniter, team Django, and, most recently, team Node.js. Each switch was made in the belief that the new framework or language offered a recruitment advantage, better documentation, or simply a &quot;better way&quot; of doing things. However, the real issue often lay not with the technology itself but with our understanding and usage of it.</p>
<h5 id="quick-story">Quick Story</h5>
<p>I once joined a company as a fervent supporter of modern JavaScript, only to find myself working with what I considered &quot;old technology&quot;: Rails. The codebase was outdated, cluttered with custom implementations, and frankly, a nightmare to debug. My initial disdain for Rails was palpable.</p>
<p>However, six months in, a leadership change and a dedicated effort to update and optimize our Rails application turned my opinion on its head. Our once sluggish app became significantly more responsive and easier to work with, proving that the problem wasn&apos;t Rails itself but how we were using it. Despite my early reservations, I became a proponent of the framework, even if it wasn&apos;t my top recommendation.</p>
<p>Fast forward two years, and our application, now paired with a React front end and a streamlined Rails API, was more efficient and performant than ever. This transformation wasn&apos;t the result of abandoning Rails but rather embracing it fully&#x2014;learning its intricacies, monitoring its performance, and dedicating time to address its issues.</p>
<h4 id="turbo-pascal-might-be-dead-actually-so-there-are-exceptions">Turbo Pascal Might Be Dead, Actually, So There Are Exceptions</h4>
<p>While my journey with Rails illustrates the benefits of digging deeper into your current framework, I acknowledge that there are exceptions. Technologies do become obsolete, and there are legitimate reasons for switching frameworks or languages:</p>
<ol><li><strong>Probably never:</strong> As a rule of thumb, switching should be a last resort, not a first step.</li><li><strong>Recruitment challenges:</strong> If finding talent for your technology stack is becoming increasingly difficult, it may be time to consider alternatives.</li><li><strong>Technical limitations:</strong> When your current language or framework cannot adequately support the solutions your projects require, a switch becomes necessary.</li></ol>
<h4 id="conclusion">Conclusion</h4>
<p>The allure of switching to a &quot;better&quot; framework or language is strong, especially when faced with performance issues or the latest tech trends. However, more often than not, the key to improvement lies not in the tools themselves but in how we use them. Deep knowledge of your current stack, performance monitoring, and continuous optimization are crucial. Only in specific circumstances&#x2014;such as recruitment difficulties or technical limitations&#x2014;should a complete switch be considered. Remember, the grass isn&apos;t always greener on the other side; sometimes, you just need to water the grass you&apos;re standing on.</p>]]></content:encoded></item><item><title><![CDATA[RCLI (Our CLI) - A bash only CLI]]></title><description><![CDATA[<p><strong>RCLI: Build your own CLI, and automate your workflows</strong> &#x2728;&#x1F5A5;&#xFE0F;</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/sec0ndhand/rcli?ref=chrisjensen.dev"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - sec0ndhand/rcli: (Our CLI) A simple cli tool, written in bash to help document repeatable tasks.</div><div class="kg-bookmark-description">(Our CLI) A simple cli tool, written in bash to help document repeatable tasks. - GitHub - sec0ndhand/rcli: (Our</div></div></a></figure>]]></description><link>https://chrisjensen.dev/simplecli-build-your-own-cli/</link><guid isPermaLink="false">6520dd4a1351cf000747a6e9</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Wed, 01 Nov 2023 13:23:21 GMT</pubDate><content:encoded><![CDATA[<p><strong>RCLI: Build your own CLI, and automate your workflows</strong> &#x2728;&#x1F5A5;&#xFE0F;</p>
<figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/sec0ndhand/rcli?ref=chrisjensen.dev"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - sec0ndhand/rcli: (Our CLI) A simple cli tool, written in bash to help document repeatable tasks.</div><div class="kg-bookmark-description">(Our CLI) A simple cli tool, written in bash to help document repeatable tasks. - GitHub - sec0ndhand/rcli: (Our CLI) A simple cli tool, written in bash to help document repeatable tasks.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">sec0ndhand</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/baeba3c14a90f3709ad0a35c83ca6f3b8cee63082b05b077b7d4fef8560c49eb/sec0ndhand/rcli" alt></div></a></figure>
<p>We all know we should document our organization&apos;s infrastructure.  It&#x2019;s a crucial part of maintaining consistency, ensuring everyone is on the same page, and simplifying onboarding of new team members. RCLI takes this a step further, offering a Git-based documentation solution that doubles as an easy-to-use CLI for your dev team, especially for running routine infrastructure-related tasks.</p>
<hr>
<h2 id="i-dont-remember-how-we-set-it-up">I don&apos;t remember how we set it up</h2>
<p>This happens all too often.  We set up a new cool thing, pass it on to the team, and it&apos;s 3 months later and no one remembers what we did.  There are a lot of tools to help us handle these things now including Docker, Kubernetes, and Terraform.  But many things aren&apos;t within the scope of them, and you end up saving those bash and SQL (squeal) scripts to your computer, never to be found again.</p>
<p>I remember having to onboard a new Software Engineer, and it taking 3 days (3 DAYS!) to set up his computer and that doesn&apos;t even take into account the multiple sessions running through the DB schema and code.  This is a lot of time, and can be troublesome when everyone&apos;s computer is setup slightly different. How much time do you spend getting them up to speed on what tools to install?  In many organizations it takes multiple days to get their computer up and running, including getting emails set up, installing software, granting access to Github, Jira, and Slack.  </p>
<p>Then 2 months go by and we want to enable them to make some changes on the staging VM (really we are too busy to run that one thing only we know how to do), but we need to add their SSH key to the host, and get them setup on their machine, send them the URL for it in Slack, and show them how to use the different custom grep commands that you have saved on your machine to find that weird scenario they will need to look for.</p>
<p>Well, 4 months roll by and the business needs some sensitive data pulled, but you don&apos;t want to open an endpoint on the public server for security reasons, so you save a SQL query in file somewhere on your local computer that will never be found by anyone else, including yourself 2 months from now when you need to run it again.</p>
<p>A lot of this type of information only gets conveyed in onboarding, when your new Software Engineer has had to retain all their information including compensation, benefits, team structure, parking rules, meeting etiquette, and how to request their next day off.  It&apos;s no wonder many of us feel like we are the only ones who can deploy, debug or help with anything in production.  We don&apos;t create processes that enable our teams to take the load from us.  Instead we create docs in Jira, Google Sheets, that one Docusaurus site your boss made, the Readme.md in each repo, but isn&apos;t there on the one that they need and send Slack messages telling them to read the out of date docs.</p>
<p>The reality is, a dev isn&apos;t going to remember all the things you told them, and especially the part where they could break production, nor the thing they only have to do once to get their infrastructure up and running like <code>docker-compose up</code>.  Even if you send them a link to the documentation, they likely won&apos;t read it, ask any open source maintainer.</p>
<h2 id="infrequent-business-request-commands-as-code">Infrequent business request commands as code</h2>
<p>Not quite as catchy as Infrastructure As Code (IaC) but the concept is still the same.  I know, it feels good when Greg from accounting comes and asks you to run that report that you ran for him last quarter, but you not sharing that SQL script you wrote in an afternoon isn&apos;t going to buy you the job security that you think it does.</p>
<p>Many of us do this &quot;skunkworks&quot; or &quot;side of table&quot; requests because it feels good to be wanted.  It feels good to fix something for the business, and have Greg give you the &quot;Good job Bro&quot; that we all want to hear.  But, it really should be on your sprint (if you are sprinting) and it really should be documented how you wrote that thing for your Bro Greg.</p>
<p>Adding the SQL command to a git repo solves the problem of having a process and allowing others to run it, decreasing the need for you or your memory of where you put that command.  If you simplified where it ran, like in a CLI, even better since it would be minimal work to get an entry point to be able to run the script.</p>
<p>This is what RCLI tries to solve, the requests that go outside of the normal business needs, that don&apos;t deserve a designer, product, and full UI just to get the number of last year&apos;s users named Chris.  That&apos;s not a real report, but it should be.  You write the report or script once, submit a PR like anything else and now it&apos;s documented, and operationalized.</p>
<h2 id="simplifying-command-line-usage-with-rcli-%F0%9F%96%A5%EF%B8%8F%F0%9F%92%A1">Simplifying Command Line Usage with RCLI &#x1F5A5;&#xFE0F;&#x1F4A1;</h2>
<p>RCLI makes creating a lightweight, and efficient command line utility straightforward. It makes it easy to consolidate and execute common tasks without the overhead of additional runtimes.</p>
<p>In a typical business you frequently need to connect to various services, be it a virtual machine in the cloud or a local Docker container. RCLI enables you to streamline these tasks into simple commands.  You could, for example, connect to a production host, with a command like the following:</p>
<p><code>mycli host prod</code></p>
<p>To accomplish this, let&apos;s use RCLI.  To get started, we can follow the readme.md and create our own CLI named mycli using the following command:</p>
<pre><code class="language-bash">curl -fsSL https://raw.githubusercontent.com/sec0ndhand/rcli/main/install.sh | bash -s -- mycli
</code></pre>

<p>This will create a new folder named <code>mycli</code> with the <code>rcli</code> cloned inside of it.  </p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/10/install.gif" class="kg-image" alt loading="lazy" width="640" height="296" srcset="https://chrisjensen.dev/content/images/size/w600/2023/10/install.gif 600w, https://chrisjensen.dev/content/images/2023/10/install.gif 640w"><figcaption><span style="white-space: pre-wrap;">creation, of mycli, including running the mycli help command</span></figcaption></figure>
<p>Now we are ready to create the command <code>host prod</code> and we will do it using the built in <code>create-command</code> that will set up the scaffolding for us.  To do this run the following command:</p>
<pre><code class="language-bash">mycli create-command host prod
</code></pre>

<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/create-command.gif" class="kg-image" alt loading="lazy" width="640" height="296" srcset="https://chrisjensen.dev/content/images/size/w600/2023/10/create-command.gif 600w, https://chrisjensen.dev/content/images/2023/10/create-command.gif 640w"></figure>
<p>You will now have a command that you can edit that can be called as <code>mycli host prod</code> and allow you to document in code how to connect to your host in production.</p>
<div class="kg-card kg-callout-card kg-callout-card-red"><div class="kg-callout-emoji">&#x1F6AB;</div><div class="kg-callout-text">Remember that you shouldn&apos;t commit credentials to your repo, as it can be a security risk. This should be used for documenting the steps, and if needed use a .env file to store things locally for each developer.</div></div>
<h2 id="wrapping-it-up">Wrapping It Up</h2>
<p>RCLI operationalizes many of the one off, hard to publish commands.  It provides a way to make something repeatable that usually wasn&apos;t in the past.  Previously one of the organizations I was affiliated with was very reliant on Heroku.  Their dev experience is great for shipping small apps, but we had requirements that required us to move to AWS.  With this tool, we were able to mimic some of the magic that Heroku has with their CLI and operationalized our solution for the whole engineering organization.</p>
<p>I should say, this tool was inspired by many of the great simple open source projects that I have used.  Oh-My-Zsh, Dokku, and Kubernetes (K8s) are the projects I took a lot of inspiration from.  Dokku the most prevalent.  Check them out, it is the right sized tool for most startups that don&apos;t have dynamic load, and can&apos;t embrace Lambda or Functions yet.</p>
<p>I hope this helps tool helps you, or your engineering organization document the things you do on a regular basis, and in the end helps you ship more value to your customers.</p>]]></content:encoded></item><item><title><![CDATA[Rails: From debug to deployment]]></title><description><![CDATA[<p>TLDR: this repo has the <a href="https://github.com/sec0ndhand/rails-debug-template/tree/36108f6d5dba15293c82e780247f52b54fb03012?ref=chrisjensen.dev" rel="noreferrer">starting point</a>, and this is it <a href="https://github.com/sec0ndhand/rails-debug-template/tree/main?ref=chrisjensen.dev" rel="noreferrer">completed project</a>.</p>
<p>I have used many languages to make apps over the years.  After .NET and some node development, I found myself in a job using rails.  ICK! RAILS! I thought.  This is old, antiquated, and hard to use!</p>]]></description><link>https://chrisjensen.dev/rails-from-debug-to-deployment/</link><guid isPermaLink="false">652324161351cf000747a6fd</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Tue, 17 Oct 2023 13:12:05 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1522776851755-3914469f0ca2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fHJ1Ynl8ZW58MHx8fHwxNjk2OTE0MDc4fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1522776851755-3914469f0ca2?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDR8fHJ1Ynl8ZW58MHx8fHwxNjk2OTE0MDc4fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Rails: From debug to deployment"><p>TLDR: this repo has the <a href="https://github.com/sec0ndhand/rails-debug-template/tree/36108f6d5dba15293c82e780247f52b54fb03012?ref=chrisjensen.dev" rel="noreferrer">starting point</a>, and this is it <a href="https://github.com/sec0ndhand/rails-debug-template/tree/main?ref=chrisjensen.dev" rel="noreferrer">completed project</a>.</p>
<p>I have used many languages to make apps over the years.  After .NET and some node development, I found myself in a job using rails.  ICK! RAILS! I thought.  This is old, antiquated, and hard to use!</p>
<p>Well, 3 years later I changed my mind.  Many of the issues I had with Rails came from the old code base that I was working in.  My mentor and boss when I started removed over 200K lines of code before he left, and I removed 220K lines before I left. Removing the baggage made it better, and really, using it for backend development for a REST API really made me like it.  It&apos;s no-nonsense and handles things like database migrations, uploading to S3, and delayed tasks really well.</p>
<p>So let&apos;s get your mac setup for Rails using dev containers, so you don&apos;t hate it, like I did. </p>
<h2 id="1-setting-up-your-mac-for-rails-development">1. Setting Up Your Mac for Rails Development</h2>
<h3 id="11-install-homebrew">1.1 Install Homebrew</h3>
<p>Before diving into anything else, ensure you have Homebrew installed on your Mac. It&apos;s a package manager that will simplify software installations.</p>
<p><code>/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;<br></code></p>
<h3 id="12-install-docker">1.2 Install Docker</h3>
<p>With <a href="https://brew.sh/?ref=chrisjensen.dev" rel="noreferrer">Homebrew</a>, installing Docker is as easy as:</p>
<p><code>brew install --cask docker<br></code></p>
<h2 id="2-setting-up-the-rails-project-with-docker">2. Setting Up the Rails Project with Docker</h2>
<h3 id="21-dockerfile">2.1 Dockerfile</h3>
<p>Create a <code>Dockerfile.local</code> for your Rails project:</p>
<pre><code class="language-dockerfile">FROM ruby:3.2.1
ENV ROOT=&quot;/myapp&quot;
ENV LANG=C.UTF-8
ENV TZ=UTC

# Install essential libraries
RUN apt-get update -qq &amp;&amp; apt-get install -y nodejs postgresql-client

RUN mkdir ${ROOT}
WORKDIR ${ROOT}

</code></pre>

<p>This will be used in creating the dev container.  Don&apos;t worry about the production dockerfile, Rails 7.1 ships with one and we will use that later.</p>
<h3 id="22-docker-compose">2.2 Docker Compose</h3>
<p>Create a <code>docker-compose.yml</code> file to set up the services used for your development container.  We will need the application container, or web container, and a database.  We will use postgres as it is well regarded in the rails community.</p>
<pre><code class="language-yaml">version: &apos;3&apos;
services:
  web:
    build:
      context: .
      dockerfile: dockerfile.local
    command: bundle exec rails s -p 3000 -b &apos;0.0.0.0 --port 1234 --dispatcher-port 26162 -- bin/rails s&apos;
    volumes:
      - .:/myapp
    ports:
      - &quot;3000:3000&quot;
    depends_on:
      - db
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data

</code></pre>

<p></p>
<h2 id="3-setting-up-vs-code-remote-debugging">3. Setting Up VS Code Remote Debugging</h2>
<h3 id="31-install-remote-debugging">3.1 Install remote debugging</h3>
<p>First we need to set up the environment to default to using docker.  Go to VS Code and install the plugin below:</p>
<figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack&amp;ref=chrisjensen.dev"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Remote Development - Visual Studio Marketplace</div><div class="kg-bookmark-description">Extension for Visual Studio Code - An extension pack that lets you open any folder in a container, on a remote machine, or in WSL and take advantage of VS Code&#x2019;s full feature set.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://marketplace.visualstudio.com/favicon.ico" alt="Rails: From debug to deployment"><span class="kg-bookmark-author">Visual Studio Marketplace</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ms-vscode-remote.gallerycdn.vsassets.io/extensions/ms-vscode-remote/vscode-remote-extensionpack/0.24.0/1676623622375/Microsoft.VisualStudio.Services.Icons.Default" alt="Rails: From debug to deployment"></div></a><figcaption><p dir="ltr"><span style="white-space: pre-wrap;">(At the time of this writing there is a bug with the most recent version of this plugin pre-release 0.317, and version 0.311 will need to be used.)</span></p></figcaption></figure>
<p>Once installed, create a folder named <code>.devcontainer</code> at the root of your project.  It will hold the setup files to allow for debugging and coding inside that container.</p>
<p>Next we will add the <code>/.devcontainer/devcontainer.json</code> file to the project.  This will set up the dev environment for you and the other devs on your team.  We will add the plugins we want to use as well as the working directory of the project within the container.  Most settings to get setup will be inside of this file.  Here are the ones to get started:</p>
<pre><code class="language-json">{
	&quot;name&quot;: &quot;Existing Docker Compose&quot;,
	&quot;dockerComposeFile&quot;: [
		&quot;../docker-compose.yml&quot;,
		&quot;docker-compose.yml&quot;
	],
	&quot;service&quot;: &quot;web&quot;,
	&quot;workspaceFolder&quot;: &quot;/myapp&quot;,
	&quot;customizations&quot;: {
		&quot;vscode&quot;: {
			&quot;extensions&quot;: [
				&quot;castwide.solargraph&quot;, // solargraph
				&quot;rebornix.Ruby&quot;, // Ruby
				&quot;misogi.ruby-rubocop&quot;, // Rubocop
				&quot;KoichiSasada.vscode-rdbg&quot; // Ruby Debug
			]
		}
	}
}
</code></pre>

<p>Add another docker-compose file at <code>./devcontainer/docker-compose.yml</code></p>
<p>and put this in it:</p>
<pre><code class="language-yaml">version: &apos;3&apos;
services:
  web:
    command: /bin/sh -c &quot;while sleep 1000; do :; done&quot;
</code></pre>

<h3 id="32-start-the-container">3.2 Start the container</h3>
<p>Now we are going to run some rails commands and we will need to have rails available.  We are avoiding rails being installed on your computer, so we will need to get the container up and going.  Once the files above are saved, each time you open the folder you will be greeted with a pop up that will ask you if you want to launch inside of the container.</p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/image.png" class="kg-image" alt="Rails: From debug to deployment" loading="lazy" width="1214" height="518" srcset="https://chrisjensen.dev/content/images/size/w600/2023/10/image.png 600w, https://chrisjensen.dev/content/images/size/w1000/2023/10/image.png 1000w, https://chrisjensen.dev/content/images/2023/10/image.png 1214w" sizes="(min-width: 720px) 720px"></figure>
<p>However, it may not do that after you just barely created those files, so lets open it another way.  In the lower left hand corner you can click on the green or blue square with <code>&gt;&lt;</code> </p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/image-1.png" class="kg-image" alt="Rails: From debug to deployment" loading="lazy" width="568" height="126"></figure>
<p>and run <code>Reopen in container</code> (shown below) and it will attempt to run <code>docker compose</code> for you and connect to the container.</p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/image-2.png" class="kg-image" alt="Rails: From debug to deployment" loading="lazy" width="1296" height="586" srcset="https://chrisjensen.dev/content/images/size/w600/2023/10/image-2.png 600w, https://chrisjensen.dev/content/images/size/w1000/2023/10/image-2.png 1000w, https://chrisjensen.dev/content/images/2023/10/image-2.png 1296w" sizes="(min-width: 720px) 720px"></figure>
<p>You should be connected to the container at this point and ready to run commands in the container from your terminal.  To open a terminal in VS code type <code>control + ` </code> and it should say your folder is myapp.</p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/image-3.png" class="kg-image" alt="Rails: From debug to deployment" loading="lazy" width="458" height="128"></figure>
<div class="kg-card kg-callout-card kg-callout-card-blue"><div class="kg-callout-emoji">&#x1F6A7;</div><div class="kg-callout-text">If you run into problems launching, you may have got some parts wrong and will need to debug your docker setup. Run docker compose up -d to run the containers manually. Look inside of the logs in docker desktop for any issues that may arise.</div></div>
<p></p>
<h3 id="33-set-up-rails-project-if-you-dont-already-have-one">3.3 Set up rails project if you don&apos;t already have one</h3>
<p>At this point we need something to debug.  We will need rails, at the time of writing Rails 7.1.0 was just released, so we will be using that version.  So let&apos;s install rails <code>gem install rails</code>.</p>
<p>Now, let&apos;s add the default rails app by running <code>rails new .</code> inside the folder.</p>
<p>If you are using the folder that I made for this article, allow all files to be overridden upon creation.</p>
<h3 id="34-debug-configuration">3.4 Debug Configuration</h3>
<p>Create or edit the <code>.vscode/launch.json</code> file with the following configuration:</p>
<pre><code class="language-json">        {
            //Start Rails server
            &quot;name&quot;: &quot;Debug Rails&quot;,
            &quot;type&quot;: &quot;rdbg&quot;,
            &quot;request&quot;: &quot;launch&quot;,
            // &quot;command&quot;: &quot;bundle exec rails&quot;, #bundle exec rails won&apos;t stop in the debugger
            &quot;command&quot;: &quot;bin/rails&quot;,
            &quot;script&quot;: &quot;s&quot;,
            &quot;args&quot;: [&quot;-b&quot;,&quot;0.0.0.0&quot;],
        },
        {
            // Run tests on the active rspec file
            &quot;name&quot;: &quot;Debug Rspec with current file&quot;,
            &quot;type&quot;: &quot;rdbg&quot;,
            &quot;request&quot;: &quot;launch&quot;,
            &quot;command&quot;: &quot;bundle exec rspec&quot;,
            &quot;script&quot;: &quot;${file}&quot;,
            &quot;args&quot;: [],
             // Confirm the executed command in the window. Make it easy to specify options such as execution of
            &quot;askParameters&quot;: true
        }
</code></pre>

<p>Save the file and click on the run and debug menu (play button with a bug on the left):<br></p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/10/image-4.png" class="kg-image" alt="Rails: From debug to deployment" loading="lazy" width="776" height="570" srcset="https://chrisjensen.dev/content/images/size/w600/2023/10/image-4.png 600w, https://chrisjensen.dev/content/images/2023/10/image-4.png 776w" sizes="(min-width: 720px) 720px"></figure>
<p>Click on the play button that reads <code>Debug Rails</code> which will start the application so you can see it on <code>localhost:3000</code> and it is in debug mode.  Find <code>config/pplication.rb</code></p>
<p>and add a debug point.  Load the project in a browser, and watch the break point catch.   This will give you full debugging capability as you develop.</p>
<p></p>
<h2 id="4-github-actions-linting-docker-image">4. GitHub Actions Linting &amp; Docker Image</h2>
<h3 id="41-create-workflow-for-linting">4.1 Create Workflow for linting</h3>
<p>In your repository, create a <code>.github/workflows/rubocop.yml</code>:</p>
<pre><code class="language-yaml">name: Rubocop

on:
  pull_request:
  push:
    branches:
      - &apos;main&apos;

jobs:
  build:
    name: CI Rubocop
    runs-on: ubuntu-latest
    env:
      api-dir: ./

    services:
      postgres:
        image: postgres
        ports: [&quot;5432:5432&quot;]
        env:
          POSTGRES_HOST_AUTH_METHOD: trust
        options: &gt;-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

      redis:
        image: redis:alpine
        ports: [&quot;6379:6379&quot;]

    steps:
      - uses: actions/checkout@v2
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.2.1
          bundler-cache: true
      - name: Install PostgreSQL
        run: sudo apt-get -yqq install libpq-dev
      - name: Run bundle install
        working-directory: ${{env.api-dir}}
        run: |
          gem install bundler
          bundle install --jobs 4 --retry 3
      - name: Setup Database
        working-directory: ${{env.api-dir}}
        env:
          RAILS_ENV: test
          PGHOST: localhost
          PGUSER: postgres
        run: bin/rails db:create db:schema:load
      - name: Check Rubocop Styles
        working-directory: ${{env.api-dir}}
        env:
          RAILS_ENV: test
          PGHOST: localhost
          PGUSER: postgres
          RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
        run: bundle exec rubocop

</code></pre>

<p>Now we need to add the rubocop gems to the project so that they run when they are in production.  Open up your <code>Gemfile</code> and look for the development section.  Make sure it looks like this:</p>
<pre><code class="language-ruby">group :development do
  # Use console on exceptions pages [https://github.com/rails/web-console]
  gem &apos;rubocop&apos;, require: false
  gem &apos;rubocop-discourse&apos;, require: false
  gem &apos;rubocop-performance&apos;, require: false
  gem &apos;rubocop-rails&apos;, require: false
  gem &apos;rubocop-rails_config&apos;, require: false
  gem &apos;rubocop-rake&apos;, require: false
  gem &apos;rubocop-rspec&apos;, require: false

  gem &apos;ruby-lsp&apos;, require: false
  gem &apos;ruby-lsp-rails&apos;
  gem &apos;web-console&apos;

  # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
  # gem &quot;rack-mini-profiler&quot;

  # Speed up commands on slow machines / big apps [https://github.com/rails/spring]
  # gem &quot;spring&quot;
end
</code></pre>

<h3 id="42-create-workflow-for-building-for-production">4.2 Create Workflow for building for production</h3>
<p>In your repository, create a <code>.github/workflows/build_and_push.yml</code>:</p>
<pre><code class="language-yaml">name: Build and Push Docker Image

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Build and push Docker image to GitHub Packages
      id: docker_build
      uses: docker/build-push-action@v2
      with:
        username: ${{ github.actor }}
        password: ${{ github.token }}
        registry: docker.pkg.github.com
        repository: ${{ github.repository }}
        tags: latest

</code></pre>

<h3 id="43-create-a-production-environment">4.3 Create a production environment</h3>
<p>If you want specifics, this will be covered in a separate post as it would get too long.  But you have some options once you have your docker image created.  There is Dokku, AWS App Engine, Kubernetes, Porter.run, and many others that can take a docker image and get it up and running.  Pick one, and get going, that is the key.  Dokku would be my pick for a small project as it is simple and easy to get going.</p>
<h2 id="5-wrapping-up">5. Wrapping Up</h2>
<p>Now, whenever you push to the <code>main</code> branch, GitHub Actions will automatically lint your ruby code and build your Docker image and push it to the GitHub image repository.</p>
<p>Now the reason why this is important comes down to running in an engineering team.  If you can remove friction from any process, you can help relationships, and ultimately remove excess meetings or at least &quot;check-ins.&quot;  By enabling rubocop, there are no more PR reviews that are &quot;I wish you would have used a ternary instead of if then&quot; or other opinions.  And the agreed upon code &quot;rules&quot; are built into the project.</p>
<p>The second part is building your project and having it ready for production.  By eliminating the friction of going to production, you will ship more often to your users.  In my experience, you don&apos;t actually go faster, but the size of your deployments go down, which lowers your risk of production bugs.</p>
<p>Rails is a great platform for creating a start up.  It has batteries included, and if you can EMBRACE it&apos;s conventions, it works really well.  When I hated Rails, I was trying to do things against it&apos;s conventions.  </p>
<p>Enough about Rails, this tutorial will get you a full debug environment, and everything setup for PRs and Production.  This really simplifies your engineering time, and will help you focus on shipping features to your users, and above all having a successful business.</p>]]></content:encoded></item><item><title><![CDATA[Docker replaced my DLL Hell]]></title><description><![CDATA[<p>I had just switched from my Electrical Engineering job, to IT.  Nine months in I was asked to get another computer setup for my co worker.  This was 2013, and we were using .Net 3.5, and Visual Basic (don&apos;t judge) to automate production processes, and I spent</p>]]></description><link>https://chrisjensen.dev/docker-replaced-my-dll-hell/</link><guid isPermaLink="false">6516c7be1351cf000747a4dd</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Tue, 10 Oct 2023 15:00:38 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1602587557695-9fa83da489c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDZ8fHdoYWxlfGVufDB8fHx8MTY5NjY0MTcyNHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1602587557695-9fa83da489c8?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDZ8fHdoYWxlfGVufDB8fHx8MTY5NjY0MTcyNHww&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Docker replaced my DLL Hell"><p>I had just switched from my Electrical Engineering job, to IT.  Nine months in I was asked to get another computer setup for my co worker.  This was 2013, and we were using .Net 3.5, and Visual Basic (don&apos;t judge) to automate production processes, and I spent 3 days in <a href="https://en.wikipedia.org/wiki/DLL_Hell?ref=chrisjensen.dev" rel="noreferrer">DLL hell</a> getting everything set up.  My boss hadn&apos;t documented the project, he was a team of 1 for the 6-ish years he had been writing this software.  And those 3 days fueled my love of Docker 2 years later when I started playing around with it.</p>
<p>Never again, would setting up a dev environment take 3 days.  I would write my infrastructure as code from then on, and save my headache of setting up servers and computers to run either <a href="https://www.gdpicture.com/?ref=chrisjensen.dev" rel="noreferrer">GD Picture</a>, or the <a href="https://www.nuget.org/packages/iTextSharp.LGPLv2.Core/?ref=chrisjensen.dev" rel="noreferrer">pre AGPL version of iTextSharp</a>.  I haven&apos;t done a lot of .NET since then, but they have adopted docker and a <a href="https://www.nuget.org/?ref=chrisjensen.dev" rel="noreferrer">package manager</a> first approach.  Both of those things help get a dev environment running faster, but let&apos;s focus on Docker.</p>
<h3 id="what-is-docker"><strong>What is Docker?</strong></h3>
<p><a href="https://github.com/veggiemonk/awesome-docker?ref=chrisjensen.dev" rel="noreferrer">Docker</a> is an open-source platform that enables developers to automate the deployment, scaling, and management of applications. Docker achieves this by using containerization, a lightweight form of virtualization. Unlike traditional virtual machines, Docker containers share the host system&apos;s OS, making them much more efficient and faster to start up. Each container runs as an isolated process in user space on the host operating system.</p>
<h3 id="motivation"><strong>Motivation</strong></h3>
<p>I use Docker for development for several reasons. First, Docker ensures consistency across all dev machines in an org, eliminating the &quot;it works on my machine&quot; problem. It also isolates the dependencies, and simplifies installation. Second, it allows the configuration to be committed to GIT and make changes through a PR process, allowing the use of a review process familiar to those who make software but use that process for infrastructure.&#xA0; Last, Docker seamlessly integrates with many popular continuous integration/continuous deployment tools, making it easier to set up a CI/CD pipeline.</p>
<h3 id="dockerfile"><strong>Dockerfile</strong></h3>
<p>A Dockerfile is a text file that Docker reads to build an image. It consists of a series of instructions, each creating a new layer in the image. Locally, layers are cached to help speed up build times.&#xA0; The typical instructions include <code>FROM</code> to specify the base image, <code>RUN</code> to execute commands, <code>COPY</code> or <code>ADD</code> to add files from the host machine, <code>WORKDIR</code> to set the working directory inside the image, and <code>CMD</code> or <code>ENTRYPOINT</code> to specify the command to run when a container starts. Each Dockerfile should ideally represent one executable application or service.  Check the <a href="https://docs.docker.com/engine/reference/builder/?ref=chrisjensen.dev" rel="noreferrer">documentation from Docker</a> for more.</p>
<h3 id="docker-image"><strong>Docker Image</strong></h3>
<p>A Docker image is a lightweight, standalone, executable package that includes everything needed to run a piece of software, including the code, a runtime, libraries, environment variables, and config files. Docker images are built from Dockerfiles, like I described above, and are the basis of containers. They can be stored and shared using Docker registries.  The most common is <a href="https://hub.docker.com/search?q=&amp;ref=chrisjensen.dev" rel="noreferrer">docker hub</a>, and if you need to send an image to production, a <a href="https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry?ref=chrisjensen.dev" rel="noreferrer">private registry</a> is a good option.</p>
<h3 id="container"><strong>Container</strong></h3>
<p>A Docker container is a running instance of a Docker image. Each container runs an application in isolation from other containers, providing a secure application platform. Containers are lightweight and fast, as they directly leverage the host machine&#x2019;s kernel, yet they maintain the isolation and resource constraints you would get from a full VM.&#xA0; On my local machine, using docker compose, I run multiple containers for Redis and Postgres.&#xA0; I might run other containers but they are subject to change.</p>
<h3 id="aws-docker-registry"><strong>AWS Docker Registry</strong></h3>
<p>Even if you don&apos;t use Github or Gitlab, you can create docker images and store them in AWS for your production environment to reference. The AWS Docker Registry, also known as Amazon Elastic Container Registry (ECR), is a fully-managed Docker container registry that allows developers to store, manage, and deploy Docker container images.&#xA0; It eliminates the need to operate your own container repositories or worry about scaling the underlying infrastructure. It is secure and provides resource-level control of each repository through integration with AWS Identity and Access Management (IAM).&#xA0; </p>
<h3 id="docker-compose"><strong>Docker Compose</strong></h3>
<p>Docker compose allows for multiple Docker containers to be ran at once, so they can all send requests to each other in the same network.  This allows us to simulate a production environment on our dev machines.&#xA0; The different containers, sometimes referred to as services, are usually defined in a <code>docker-compose.yml</code> file inside the project folder.&#xA0; Docker compose files can be used to run in production using other apps, using <a href="https://kompose.io/?ref=chrisjensen.dev" rel="noreferrer">Kompose</a> an open source software that translates docker compose files into Kubernetes (K8s) config files.  But before you do that you should probably look into <a href="https://www.nomadproject.io/?ref=chrisjensen.dev" rel="noreferrer">Nomad</a>, <a href="https://dokku.com/?ref=chrisjensen.dev" rel="noreferrer">Dokku</a> or <a href="https://www.heroku.com/?ref=chrisjensen.dev" rel="noreferrer">Heroku</a>.</p>
<div class="kg-card kg-callout-card kg-callout-card-red"><div class="kg-callout-emoji">&#x1F336;&#xFE0F;</div><div class="kg-callout-text"><i><em class="italic" style="white-space: pre-wrap;">&quot;If you have less than 20 engineers in your organization, don&apos;t use Kubernetes. </em></i><a href="https://aws.amazon.com/pm/lambda/?ref=chrisjensen.dev" rel="noreferrer"><i><em class="italic" style="white-space: pre-wrap;">Lambda</em></i></a><i><em class="italic" style="white-space: pre-wrap;">, </em></i><a href="https://www.nomadproject.io/?ref=chrisjensen.dev" rel="noreferrer">Nomad</a>, <a href="https://dokku.com/?ref=chrisjensen.dev" rel="noreferrer">Dokku</a>, and <a href="https://www.heroku.com/?ref=chrisjensen.dev" rel="noreferrer">Heroku</a><i><em class="italic" style="white-space: pre-wrap;"> are all better alternatives for small teams.&quot; </em></i>- Me</div></div>
<p><br>In a local docker-compose development environment, I primarily have three services: The App, Database, and <a href="https://docs.keydb.dev/?ref=chrisjensen.dev" rel="noreferrer">Redis</a>.  Sometimes there are some more specialized things like <a href="https://www.rabbitmq.com/?ref=chrisjensen.dev" rel="noreferrer">RabitMQ</a> or other open source projects, but the point is to run what is in production locally.  Docker-compose enables me to define and run these multi-container Docker applications, allowing me to spin up dependencies with a single command.</p>
<h3 id="your-dev-environment"><strong>Your Dev Environment</strong></h3>
<p>In my development environment, Docker is used to build, run, and manage my application including it&apos;s dependancies. After defining the services in a <code>docker-compose.yml</code> file, you can run from the terminal, in the project folder <code>docker compose up -d</code>  to start the underlying infrastructure. I even used docker to replace version managers, think Node Version Manager (NVM) or RBENV which is a ruby version manager.   This way you don&#x2019;t have to install ruby at a certain version, you can run your code in a container that has the specific version of your runtime installed.  If you set it up right, changes you make in code will be reflected in the running containers. This is enabled by using the volume mounts linking the containers to the local filesystem. </p>
<h3 id="docker-in-production"><strong>Docker in Production</strong></h3>
<p>The most popular way to deploy docker applications right now is probably Kubernetes.&#xA0; Kubernetes is a powerful and complex tool, that works like docker-compose.&#xA0; It allows for specifying multiple containers (pods) that run in services, so applications can autoscale.&#xA0; This is a use case for organizations and workloads that are highly volatile and require a lot of server resources, and a lot of developer resources.&#xA0; Most teams usage is pretty static, or at least predictable, so the benefits should outweigh the amount of time you will spend in deploying.</p>
<p>Currently in production, I leverage Docker via Dokku, the Docker-powered mini-Heroku. Dokku allows us to manage deployments, scale applications, and perform zero-downtime deployments, ships logs to s3 using vector, all while using the same Docker images I use in my dev environment. This ensures the environment my code runs in is consistent, from development to production. With Dokku, deploying  apps to production is as simple as pushing our code using Git.  Without a <a href="https://pro.dokku.com/?ref=chrisjensen.dev" rel="noreferrer">Dokku pro license</a>, you aren&apos;t able to auto scale.  As Dokku is meant to be used on 1 Debian server, but most of the time on a new project, that is all you need to get to production.</p>
<h3 id="summary"><strong>Summary</strong></h3>
<p>If you are just running a Typescript app, you don&apos;t need docker. Why did you read this far anyway?  If you need your API or server running locally, Docker can take a little extra time to set up.  But it operationalizes your setup.  Everytime your computer goes awry or you need to add another developer, it&apos;s easy to get set up.  You are only a few steps away from deploying to production.</p>
<p></p>]]></content:encoded></item><item><title><![CDATA[Micro front ends is an anti-pattern]]></title><description><![CDATA[Just look at the the big corporations, like ESPN.  They unified their apps into one in 2015. But, you should split your front end when...]]></description><link>https://chrisjensen.dev/micro-front-ends-is-an-antipattern/</link><guid isPermaLink="false">6516cbfe1351cf000747a523</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Thu, 05 Oct 2023 15:00:57 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1531986362435-16b427eb9c26?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDMwfHxtdWx0aXBsZSUyMGFwcHN8ZW58MHx8fHwxNjk2NDU1MDQ3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1531986362435-16b427eb9c26?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDMwfHxtdWx0aXBsZSUyMGFwcHN8ZW58MHx8fHwxNjk2NDU1MDQ3fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Micro front ends is an anti-pattern"><p>A few years ago, I got into watching my alma-matter&apos;s football games.  This opened my eyes to a world in which I was checking ESPN weekly and sometimes daily.  At the time ESPN had the <a href="https://apps.apple.com/us/app/espn-live-sports-scores/id317469184?ref=chrisjensen.dev" rel="noreferrer">ESPN app</a>, and <a href="https://en.wikipedia.org/wiki/WatchESPN?ref=chrisjensen.dev" rel="noreferrer">Watch ESPN</a> for streaming that I used.  There were also an ESPN fantasy sports app, among others in their portfolio.  A few years ago, they unified many of their offerings into the ESPN app, where you could find streaming, and many of their other functions.</p>
<p>As a user, this is better.  I know them as ESPN, and when I go to open an app about sports, I don&apos;t want to think, &quot;which department at ESPN would do that?  I should look for their corresponding app.&quot; No, as a user of ESPN, I just want ESPN.</p>
<p>This is the same with the micro front ends trends that some companies are adopting.  Looking at the problem they are trying to solve, I can understand, when you have hundreds of engineers and you need to ship updates to the front end without it affecting one another&apos;s code, it can be challenging.  So you reach for something like <a href="https://piral.io/?ref=chrisjensen.dev" rel="noreferrer">Piral</a> or <a href="https://single-spa.js.org/?ref=chrisjensen.dev" rel="noreferrer">SingleSPA</a> to enable multiple independent teams to ship to production.  Or maybe you are trying to solve, &quot;How can I ship both Angular and React on the same page?&quot; and you find Piral or micro-front-ends and decide it solves your problem.  And it will, that problem it will fix.</p>
<p>But let&apos;s look back to my experience using ESPN.  When I wanted to view a sporting event, the ESPN app had to push me to a different app, with a different login process, that didn&apos;t have any context of what I had just been reading or doing.  This didn&apos;t serve me as a Sports Enthusiast&#x2122;.  The problem that this is surfacing is Conway&apos;s Law, which states,</p>
<div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text">&quot;<i><em class="italic" style="white-space: pre-wrap;">organizations design systems that mirror their own communication structure</em></i>.&quot;</div></div>
<p>Or in other words, we had an ESPN streaming app not because Sports Enthusiasts&#x2122; wanted another ESPN app, we had a streaming app because ESPN had a separate team working on streaming.</p>
<h3 id="moving-forward">Moving Forward</h3>
<p>Let&apos;s look at what ESPN did.  They redesigned their main app, and they brought much of the functionality of each of the other apps to the main ESPN app.  This is very much inline with what they were doing on web already.  They had unified URI where every user went, and then each piece was cut out separately, but placed on the same domain, except 538, and few stand alone properties.  Notice on their website, they still have a streaming section, they have all the different sports, and they probably still have separate teams working on different projects.</p>
<p>Conway&apos;s law is still probably happening within their organization.  The difference, the user doesn&apos;t see Conway&apos;s law happening.  The added friction of a different app was great enough, that they integrated the streaming features in the main app in 2015 and sunset the streaming app in 2019.</p>
<p>&quot;<em>But micro front ends is on the same domain!&quot; </em> you might exclaim.  And I would agree, it is much better than having a separate app, or separate domains to visit.  But there is still some friction when none of your teams are coordinating UI updates, and not allowing design to make the best version possible for your users.</p>
<h3 id="process">Process</h3>
<ol><li>Create a sitemap of the features you want your users to experience. </li><li>Split teams based on persona --&gt; feature<ol><li>Usually a team of 4-5 engineers with at least one who has &quot;been there, done that&quot;</li></ol></li><li>Create a shared front end project, web or mobile, and split out the routes to the teams.  Changes for the routes under each team will be owned by them, and them only.</li><li>At least one designer or PM should have the responsibility to make sure the experience across the whole app is cohesive.</li><li>Require integration tests<ol><li>these should test that main functionality doesn&apos;t completely break</li><li>It should run after each PR is opened to ensure no conflicting code is written.</li></ol></li><li>Don&apos;t follow this process to a &quot;T&quot;.  Do what your user&apos;s need, and expect, but as a general rule don&apos;t split your front end.</li></ol>
<h3 id="when-you-should-split-your-front-end">When you should split your front end</h3>
<p>When your persona(s) differ greatly.  That&apos;s it.  When you need to address a persona that has different needs, that should be a big clue that you need to split your front end. </p>
<p>Consider most B2B SAAS products.  The individual you are selling to, is not often the person using your software.  At a previous company, we were having a lot of issues with deciding priority, figuring where each feature should live in the app, and were even shipping slower than we probably should have.</p>
<p>Our organizational problems seamed to melt away when we split the UI into 2.  The first was for the person we were selling to, and the second was for the person who was using the software.  By splitting by persona, and not by feature, we were able to map what each person needed, and focus on what they needed.  Our team&apos;s velocity jumped and it was clear where each new feature lived.</p>
<p>Now let&apos;s look at our ESPN app example, I was a Sports Enthusiats&#x2122; persona, just checking scores, and maybe catching a game here and there.  If they decided they wanted to have a platform for athletes to post about themselves, the portal which an athlete entered to put in information about themselves would definitely be a different persona.  But splitting between a Basketball Enthusiast&#x2122; and a Football Enthusiast&#x2122; probably wouldn&apos;t make sense as their needs are very similar.</p>
<h3 id="conclusion">Conclusion</h3>
<p>I love the idea of micro front ends, it does solve some problems for the organization.  It also allows for some autonomy for your engineering staff.  But that autonomy complicates sharing components when you pick different front end frameworks, and it breaks the flow of the user as they try to use your app.  These 2 issues will be costly for your business, and any need for a micro front end framework or other splitting the code base should be resisted, if not avoided.  The reality is you need to understand your user&apos;s use cases and adapt accordingly, before you add the unnecessary overhead of micro front ends.</p>]]></content:encoded></item><item><title><![CDATA[Queue the haters: the work queue in Redis]]></title><description><![CDATA[<p>If you are reading this, you probably work in B2B SAAS as no one else would ever choose to put a work queue in their software.&#xA0; Alas, most of us work on less than sexy features in seemingly boring jobs.&#xA0; But the reality is that those boring jobs</p>]]></description><link>https://chrisjensen.dev/the-work-queue-in-redis/</link><guid isPermaLink="false">651111771351cf000747a2ae</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Thu, 28 Sep 2023 22:49:01 GMT</pubDate><media:content url="https://chrisjensen.dev/content/images/2023/09/Artboard-2-20.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://chrisjensen.dev/content/images/2023/09/Artboard-2-20.jpg" alt="Queue the haters: the work queue in Redis"><p>If you are reading this, you probably work in B2B SAAS as no one else would ever choose to put a work queue in their software.&#xA0; Alas, most of us work on less than sexy features in seemingly boring jobs.&#xA0; But the reality is that those boring jobs are the ones that pay the bills.&#xA0; Businesses want to automate away their problems without throwing more people at them, so the work queue was born.</p>
<p>If you are looking for the code real quick, it&apos;s <a href="https://github.com/sec0ndhand/work-queue-example?ref=chrisjensen.dev" rel="noreferrer">right here.</a></p>
<p>I&#x2019;ve <a href="https://www.linkedin.com/in/chrisjensen23/?ref=chrisjensen.dev" rel="noreferrer">worked at a handful of companies</a> over the years, and almost all of them were in some way a B2B SAAS company.&#xA0; All of them had either built a work queue, or had a work queue on their road map.</p>
<p>What is a work queue?&#xA0; Good question, well you didn&#x2019;t ask it but I&#x2019;m going to tell you because you are reading this article.&#xA0; A work queue is a list of items that need to be completed by a group of individuals. To give you an example let&#x2019;s look at a restaurant.</p>
<p>There are multiple queues inside of a restaurant, and operating a restaurant is all about moving people through these queues as fast as you can.&#xA0; The more tables you turn over, the more money you make, and the more money you make the better chance you have at funding that midlife crisis full of sports cars and &#x201C;bitches&#x201D; or &#x201C;bros&#x201D; depending on which form of sexism you prefer.</p>
<p>Anyway, you have 4 main queues when you look at the journey of the customer.</p>
<ol><li>Seating queue</li><li>Ordering queue</li><li>Paying queue</li><li>GTFO queue</li></ol>
<p>I don&#x2019;t know if there is a real need for the 4th, but if I was turning tables that would absolutely be a metric for me.</p>
<p>The roles in a restaurant are clear, you have&#xA0;</p>
<ol><li>host(ess)</li><li>Server</li><li>Cook</li><li>Busser</li></ol>
<p>And they really are concerned about filling and emptying each of those queues.</p>
<p>If we were to represent this in software we would have a role or permission for each of these personas and a queue for each of the queue steps above.</p>
<h3 id="your-first-work-queue"><strong>Your first Work Queue</strong></h3>
<p>This is where the fun begins.&#xA0; I chose Redis, aka <a href="https://x.com/jordienr/status/1704150824581034345?s=20&amp;ref=chrisjensen.dev" rel="noreferrer">localstorage for servers</a>, because it helps solve problems on the backend well, and to be honest, it&#x2019;s the one that seemed to fit best.  We will be using <a href="https://github.com/sec0ndhand/sigue?ref=chrisjensen.dev" rel="noreferrer">Sigue</a>, a simple npm package used for GraphQL.&#xA0; GraphQL is like <a href="https://blog.postman.com/soap-api-definition/?ref=chrisjensen.dev" rel="noreferrer">SOAP</a> api standard, but unlike SOAP there are still people that like it.</p>
<h3 id="a-quick-note"><strong>A Quick Note</strong></h3>
<p>I did evaluate other technologies for this, at least instead of <a href="https://docs.keydb.dev/?ref=chrisjensen.dev" rel="noreferrer">Redis</a> (keyed).&#xA0; <a href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview?ref=chrisjensen.dev" rel="noreferrer">Azure service bus</a> being one of them.&#xA0; It has a cool <a href="https://learn.microsoft.com/en-us/rest/api/servicebus/peek-lock-message-non-destructive-read?ref=chrisjensen.dev" rel="noreferrer">Peek &amp; Lock</a> feature that would have worked very well for this, but the same connection, yes connection, has to be used to abandon or complete the message.&#xA0; This has limitations where our backend could have multiple instances running in either Kubernetes or as a serverless function.&#xA0; If you don&#x2019;t have this requirement and have only 1 webserver, Azure Service Bus could be a nice tool for this.</p>
<p><a href="https://kafka.apache.org/?ref=chrisjensen.dev" rel="noreferrer">Kafka</a> was also looked at, but since it looked to have mostly queues only, I stuck to Redis, something I know, and that has more datatypes, like <a href="https://redis.io/commands/zadd/?ref=chrisjensen.dev" rel="noreferrer">Sorted Sets</a>.</p>
<p></p>
<h3 id="the-pseudo-code"><strong>The Pseudo Code</strong></h3>
<p>Let&#x2019;s be real, I don&#x2019;t care about having all 4 queues represented, so we aren&#x2019;t going to go into each of them.&#xA0; We are only going to make the reservations queue.&#xA0; That queue will be what the hostess to keep track of who has and hasn&apos;t been seated.&#xA0; They will pull the name to look for the party with the reservation, then after 2 minutes if they aren&#x2019;t found they are placed back in the queue, or removed.</p>
<p>Let&apos;s start with a reservation, and let&apos;s make the data model for a reservation.  It first needs a name, phone number, and the amount of people that are in the group. We will store that in the database and not in the queue.  Sigue uses sequelize, so let&apos;s make that model.</p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/09/createReservation.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="320" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/createReservation.gif 600w, https://chrisjensen.dev/content/images/2023/09/createReservation.gif 640w"></figure>
<p>Next we need to make the queue.&#xA0; I am going to use the npm package ioredis to make connections with Redis, and handle the queues.&#xA0; Redis has a handful of datatypes, one is a list, which most people call a queue.&#xA0; And it simply takes in a string and moves them either in or out of the front or the back of the list.&#xA0; One of its limitations is the inability to reference each of the items in the list and update them, or delete them from the list.&#xA0; Nor can you update the items once in the list.&#xA0; Once they are in the list, they kind of just sit there until you need them.</p>
<p>Enter <a href="https://redis.io/docs/data-types/sorted-sets/?ref=chrisjensen.dev" rel="noreferrer">Sorted Sets</a>.&#xA0; A sorted set allows for the same concept of a queue but based on a score.&#xA0; That score determines the importance of the item, and makes it so you can insert items wherever you want in the queue and at any time.&#xA0; This fits our needs a little better.</p>
<p>This is a make believe example, but in the real world a work queue will generally have something that someone has to work on, and if they don&#x2019;t get it done, it needs to be released so someone else can work on it.&#xA0; Let&#x2019;s add that requirement to this queue.</p>
<p>So now we will have a sorted set named reservations.&#xA0; To implement the <a href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/message-transfers-locks-settlement?ref=chrisjensen.dev#peeklock" rel="noreferrer">Peek &amp; Lock like in Azure Service bus</a>, we will add another sorted set named reservations_delayed.&#xA0; Here is the Redis code that will be used to help us write to the queues as needed.  You can reference it over in the project repo.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><a href="https://github.com/sec0ndhand/work-queue-example/blob/main/src/redis-queue.js?ref=chrisjensen.dev"><img src="https://chrisjensen.dev/content/images/2023/09/addToQueue.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="320" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/addToQueue.gif 600w, https://chrisjensen.dev/content/images/2023/09/addToQueue.gif 640w"></a><figcaption><span style="white-space: pre-wrap;">adding the addToQueue function to redis-queue.js</span></figcaption></figure>
<p>Each reservation will be represented in the sorted set with it&#x2019;s id (primary key) and its score which in this case will be an <a href="https://en.wikipedia.org/wiki/Epoch_(computing)?ref=chrisjensen.dev" rel="noreferrer">epoch based date</a>.&#xA0; Basically, it&apos;s a date represented by a number, so the sooner you made your reservation, the sooner you will get seated.&#xA0;</p>
<p>Now we just need to hook it up to the API and add some testing.  Remember, I am using <a href="https://github.com/sec0ndhand/sigue?ref=chrisjensen.dev" rel="noreferrer">Sigue</a> right now, which helps get the server up and running.  Using Sigue, We will add 2 custom resolvers, one to get a new item, and one to complete the item once the server has found their party.</p>
<p>We still need to add a party to the queue once their reservation is created, so now let&apos;s add the addToQueue call to the afterSave hook on the model.  This should add the party to the queue.</p>
<figure class="kg-card kg-image-card"><img src="https://chrisjensen.dev/content/images/2023/09/model.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="320" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/model.gif 600w, https://chrisjensen.dev/content/images/2023/09/model.gif 640w"></figure>
<h3 id="the-graphql-queries">The GraphQL queries</h3>
<p>To write the graphQL queries let&apos;s use <a href="https://studio.apollographql.com/sandbox/explorer?ref=chrisjensen.dev" rel="noreferrer">Apollo&apos;s sandbox</a>.  We will need to start the server so that Apollo Sandbox can do view what is in the API.  Check out my blog next week where we cover Docker, but for now just run the <code>docker compose up -d</code> command to get Redis up and running.  Then we can start the node api server by running <code>npm start</code>, as shown below.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/starting_server.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="320" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/starting_server.gif 600w, https://chrisjensen.dev/content/images/2023/09/starting_server.gif 640w"><figcaption><span style="white-space: pre-wrap;">Starting Redis, and the node server</span></figcaption></figure>
<p>Once up and running you can type in your <code>http://127.0.0.1:4000/graphql</code> as your server, and if it is all setup correctly, you should be able to see the graphQL endpoints for your server, including the types that are returned.  This is meant to be used to explore an API, so feel free to poke around.  </p>
<h3 id="create-a-reservation">Create a reservation</h3>
<p>We will attempt to create a reservation, as if someone was taken in by the hostess.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/ApolloSandbox.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="366" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/ApolloSandbox.gif 600w, https://chrisjensen.dev/content/images/2023/09/ApolloSandbox.gif 640w"><figcaption><span style="white-space: pre-wrap;">Apollo Sandbox, running with the Queue</span></figcaption></figure>
<p>You can follow along by <a href="https://studio.apollographql.com/sandbox/explorer?endpoint=http%3A%2F%2Flocalhost%3A4000%2Fgraphql&amp;explorerURLState=N4IgJg9gxgrgtgUwHYBcQC4RxighigSwiQAIBhAJwXwQCUEBnBCgN3yKQAoASAcwogwADgGUCALwToSASVQAaEtyEALYlJIiUFAkl6LuYGgBUCiaQBEaB3BR1sANqfMkrKBAEoSwADqlyVDT0TKzsxJz8gkIA%2BgwSGnwCwmKSiqrq0spqSAiKRu7RhC6GJma5JLb2uA6FZZmVBI7Ont5%2BJO0kBGBtHZHCsfE97ek5QyT5CLWIY1CB7mAAgihjwhOLy-7tDY5TCD0Avn77IPIgbDq4AEYOjBggvv4%2BIH2igxgkAOzyPU8je%2B9PAAsAGYAKwAWg%2BADZAeCoQAOQEARie30e4FK0wBIAATAAGHHA8F4gCc4KRoNRPxA22qzSe0ie%2BMJxLJeJRICOJxADFmBCEaEwIH2QA&amp;ref=chrisjensen.dev" rel="noreferrer">clicking here</a>, or just setting up your own query for <code>CreateReservation</code>.  Once created you should be able to run it, and see the result:</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/CreatingReservation.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="1436" height="902" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/CreatingReservation.gif 600w, https://chrisjensen.dev/content/images/size/w1000/2023/09/CreatingReservation.gif 1000w, https://chrisjensen.dev/content/images/2023/09/CreatingReservation.gif 1436w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Creating a reservation in Apollo Sandbox</span></figcaption></figure>
<p>So that seems to have added it to the SQLite database that we are running locally.  And since we added the <code>addToQueue</code> function to the <code>afterSave</code> Sequelize lifecycle hook, we should be able to see the data in Redis as well.  I like to use <a href="https://tableplus.com/?ref=chrisjensen.dev" rel="noreferrer">TablePlus</a> for my data development, it is the best client I have found on the Mac for running SQL.  But it also has a Redis viewer.  Let&apos;s check to make sure the data is there.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/CheckInTablePlus.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="392" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/CheckInTablePlus.gif 600w, https://chrisjensen.dev/content/images/2023/09/CheckInTablePlus.gif 640w"><figcaption><span style="white-space: pre-wrap;">Checking the reservations queue in Table Plus</span></figcaption></figure>
<p>Sure enough, it&apos;s there as well as the one test reservation I ran before this.  </p>
<h3 id="a-table-is-ready">A table is ready</h3>
<p>Now let&apos;s pretend we called the group up for their reservation.  We will call the <code>getNext</code> graphQL query to do this.  This places them in a delayed queue until they are seated.  Let&apos;s run that graphQL query and then check on it in Redis.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/getNext.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="428" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/getNext.gif 600w, https://chrisjensen.dev/content/images/2023/09/getNext.gif 640w"><figcaption><span style="white-space: pre-wrap;">Running getNext in Apollo Sandbox</span></figcaption></figure>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/checkDelayed.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="428" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/checkDelayed.gif 600w, https://chrisjensen.dev/content/images/2023/09/checkDelayed.gif 640w"><figcaption><span style="white-space: pre-wrap;">Check the reservations in the delayed queue</span></figcaption></figure>
<h3 id="seating-the-party-at-the-restaurant">Seating the party at the restaurant</h3>
<p>Ok, as the hostess, let&apos;s pretend we seated the group and we need to remove them from the queue.  We will remove record 11 that represents the party that was just seated, and number 10 too.  And let&apos;s double check the delayed queue after we complete the records.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/completeReservations.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="428" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/completeReservations.gif 600w, https://chrisjensen.dev/content/images/2023/09/completeReservations.gif 640w"><figcaption><span style="white-space: pre-wrap;">Completing the 2 records in the delayed queue</span></figcaption></figure>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/check-delayed-deleted.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="428" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/check-delayed-deleted.gif 600w, https://chrisjensen.dev/content/images/2023/09/check-delayed-deleted.gif 640w"><figcaption><span style="white-space: pre-wrap;">Reloading the data in TablePlus, showing the delayed queue is gone</span></figcaption></figure>
<h3 id="ensuring-stability-with-testing">Ensuring stability with testing</h3>
<p>This is all fine and good, but this is tedious checking every part of this process.  Automating the test for this is the right thing to do if you want to ensure your code continues to run in the future, so to do that, we will run the tests that were written in mocha.  I prefer to run SOME integration tests over many unit tests.  These tests test the above flow.</p>
<p>To run the tests, in the terminal type <code>npm run test</code> and watch the output.</p>
<figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://chrisjensen.dev/content/images/2023/09/automatedTest.gif" class="kg-image" alt="Queue the haters: the work queue in Redis" loading="lazy" width="640" height="324" srcset="https://chrisjensen.dev/content/images/size/w600/2023/09/automatedTest.gif 600w, https://chrisjensen.dev/content/images/2023/09/automatedTest.gif 640w"><figcaption><span style="white-space: pre-wrap;">Running automated tests for the queue</span></figcaption></figure>
<h3 id="conclusion">Conclusion</h3>
<p>This could be a really good way to handle work queues, especially for large organizations with a lot of data.  Most of the time, this is probably overkill.  This can be implemented with a database and something like a status column.  </p>
<p>If you are a startup, please don&apos;t use Redis for this.  Get your work queue out the door, and know you can implement this in the future. </p>
<p>I added all of the steps because that is what a real feature would look like.  Concept to automated test.  As long as your CI/CD is set up, then you can trust this won&apos;t ever be a bug in the future.</p>
<p>And as always, get it out the door, but don&apos;t skip any steps.</p>]]></content:encoded></item><item><title><![CDATA[I hope you had the type of your life]]></title><description><![CDATA["Anders Hejlsberg has finally brought his vision of turbo pascal to our beloved javascript"]]></description><link>https://chrisjensen.dev/type-of-your-life/</link><guid isPermaLink="false">64fa97d76c2c120006b78b4a</guid><dc:creator><![CDATA[Chris Jensen]]></dc:creator><pubDate>Fri, 08 Sep 2023 05:40:42 GMT</pubDate><media:content url="https://chrisjensen.dev/content/images/2023/09/Artboard-1-20.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://chrisjensen.dev/content/images/2023/09/Artboard-1-20.jpg" alt="I hope you had the type of your life"><p>Creating types can be tedious.  As software engineers, unless you are DHH, we tend to dream in types:</p>
<figure class="kg-card kg-embed-card"><div><blockquote class="twitter-tweet"><p lang="en" dir="ltr">&quot;So farewell, TypeScript. May you bring much rigor and satisfaction to your tribe while letting the rest of us enjoy JavaScript in the glorious spirit it was originally designed: Free of strong typing.&quot; <a href="https://t.co/mCDhyrmEnu?ref=chrisjensen.dev">https://t.co/mCDhyrmEnu</a></p>&#x2014; DHH (@dhh) <a href="https://twitter.com/dhh/status/1699427078586716327?ref_src=twsrc%5Etfw&amp;ref=chrisjensen.dev">September 6, 2023</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div></figure>
<p>We make our database tables, we make our models in our favorite web framework, and if we love OOP on the back end we may even make DTOs, and even GraphQL types if you have GraphQL.  And then you have to make types in Typescript, and maybe even DTOs for your Typescript.  If you are lucky like me, you might even get to make those types again for your mobile app.  <a href="https://en.wikipedia.org/wiki/Anders_Hejlsberg?ref=chrisjensen.dev" rel="noreferrer">Anders Hejlsberg</a> has finally brought his vision of <a href="https://en.wikipedia.org/wiki/Turbo_Pascal?ref=chrisjensen.dev" rel="noreferrer">turbo pascal</a> to our beloved javascript.</p>
<p>We love our types, unless it is pre-2016, at that time we hated them, at least on js twitter:</p>
<figure class="kg-card kg-embed-card"><div><blockquote class="twitter-tweet"><p lang="en" dir="ltr">Meh, maybe it wasn&apos;t such a good idea adopting TS concepts. It compiles the following resulting in a perf deopt. :( <a href="https://t.co/dzAeQwZIwF?ref=chrisjensen.dev">pic.twitter.com/dzAeQwZIwF</a></p>&#x2014; Dominic Gannaway (@trueadm) <a href="https://twitter.com/trueadm/status/775088096216055810?ref_src=twsrc%5Etfw&amp;ref=chrisjensen.dev">September 11, 2016</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></div></figure>
<p>Let&apos;s just pretend that era didn&apos;t exist.  We love types again, errr, always have.  We need types all of the time, trust me.</p>
<p>This got me thinking, what is the reason for types in the first place?  What problem are we solving? Developer experience.  And heres a list of the main things types do:</p>
<ol>
<li>make refactoring names a breeze</li>
<li>communicate data design decisions</li>
<li>find bugs before runtime</li>
<li>help organize large code bases</li>
<li>improve intellisense</li>
</ol>

<p>This makes coding in my editor so much better, and I truly have embraced the typed world.  It has saved me countless times from coding a bug.  What is funny, is that we aren&apos;t very many years past a time when types weren&apos;t cool.  I loved types for my first few years, until I was convinced they weren&apos;t needed, so between 2017-2020 <a href="https://auth.campbellcloud.io/?ref=chrisjensen.dev" rel="noreferrer">I largely coded without types</a>, and most of the time it was a mess.  I should say I worked for a small company that I shipped a node.js project for, that I haphazardly threw together, with no code reviews, design, or automated tests.  I also worked on a node &#xB5;service project that had a &#xB5;service for every table.  But the mess wasn&apos;t always because of the lack of types, it also had to do with how fast I tried to ship things, and working code was paramount above maintainability on both of those projects.</p>
<p>I did learn that, for smaller projects, think 5 functions or so, types weren&apos;t needed.  You may not reap the benefits of fully typing in a file that you will only be touching for an hour.  You will spend more time messing with your types than shipping your value to your customer.  And only 1 or 2 items of the list above applies to this small of a project. But most projects are bigger than that, and types are nearly always needed.</p>
<p>So it doesn&apos;t matter if DHH removed the library from from turbo, as much of the JS ecosystem is moving to <a href="http://remix.run/?ref=chrisjensen.dev" rel="noreferrer">server side rendered</a> content, and Rails is likely past it&apos;s <a href="https://www.hey.com/?ref=chrisjensen.dev" rel="noreferrer">hey</a> day.  But we can appreciate DHH&apos;s thoughts, even if it is to help us re-examine our own opinions about our code.</p>]]></content:encoded></item></channel></rss>