<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ben Selby</title>
    <description>The latest articles on DEV Community by Ben Selby (@benmatselby).</description>
    <link>https://dev.to/benmatselby</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F595286%2F88fb71a7-2deb-4482-92ca-330cea9d07d2.jpg</url>
      <title>DEV Community: Ben Selby</title>
      <link>https://dev.to/benmatselby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/benmatselby"/>
    <language>en</language>
    <item>
      <title>Two weeks with the GitHub Coding Agent</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sun, 29 Jun 2025 13:51:44 +0000</pubDate>
      <link>https://dev.to/benmatselby/two-weeks-with-the-github-coding-agent-318p</link>
      <guid>https://dev.to/benmatselby/two-weeks-with-the-github-coding-agent-318p</guid>
      <description>&lt;p&gt;For the last two weeks, we've been learning to work with the new &lt;a href="https://github.blog/news-insights/product-news/github-copilot-meet-the-new-coding-agent/" rel="noopener noreferrer"&gt;GitHub Coding Agent&lt;/a&gt;. This is a shift for me. Moving from working with AI in my IDE, to actually delegating entire tasks to an agent that works asynchronously in the cloud. The aim is to be more efficient, and provide a bigger impact for the business.&lt;/p&gt;

&lt;p&gt;From now on we will call the GitHub Coding Agent "Mx Robot". Why? I think you need to think of this as a colleague that may or may not deliver what you need. I see in the community we are comparing a Coding Agent to be like a Junior Developer, and this makes sense to be at the moment. I'm learning new ways to think of solving the issue, which you also get with Junior engineers (fresh eyes!).&lt;/p&gt;

&lt;h2&gt;
  
  
  How we did it
&lt;/h2&gt;

&lt;p&gt;First off, I'm in a team of two people at the moment. So the first week, it was very much an after thought. "Oh I could have given this to AI". Only &lt;strong&gt;7% of the pull requests merged were from Mx Robot&lt;/strong&gt;. The second week we were much more intentional. Each morning at 9am, we had an informal review of the backlog and agreed what to delegate to Mx Robot. We currently work in Jira, with no integration with the coding agent. This meant we had to re-write/copy/paste the Jira ticket into a GitHub Issue, or the Copilot agent window on GitHub.&lt;/p&gt;

&lt;p&gt;Once the prompt had initiated work, we copied our prompt back to the Jira ticket so we had a reference of what was asked. The intention here is to learn which phrasing provides the most success.&lt;/p&gt;

&lt;p&gt;The process took an hour each morning. This was mainly due to learning and then demoing our process to another team. In reality this could have been 30 minutes. I would say roughly 60% of the work last week was ear marked as "AI achievable". This means that we believed we could delegate to AI if we wanted to and get some level of success.&lt;/p&gt;

&lt;p&gt;We agreed to only have 2 tickets in progress with Mx Robot at a time. Maybe it's a coincidence, or maybe 1 AI ticket per dev (plus their own work) is a workable heuristic. We haven't gathered enough data to make a determination yet. Our team grows to three devs next week, so we can see if this holds true.&lt;/p&gt;

&lt;p&gt;We also agreed to only have three interactions with Mx Robot on the pull request. If we couldn't get it over the line with three interactions then we either:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scrap it entirely and get humans to do the work, or&lt;/li&gt;
&lt;li&gt;Take over from the pull request if there was a good foundation to build on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Lastly, and maybe we were too pessimistic, we agreed that green field development that needed a wide range of thought we would leave to the humans.&lt;/p&gt;

&lt;p&gt;In week two, &lt;strong&gt;24% of our pull requests were created by Mx Robot&lt;/strong&gt;. We went from a statistic of 1.1 tickets per human per day, to 1.8. This is over a 3 week rolling average.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked
&lt;/h2&gt;

&lt;p&gt;We've given Mx Robot the following types of work&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Refactoring configuration files.&lt;/li&gt;
&lt;li&gt;Removing old feature flags.&lt;/li&gt;
&lt;li&gt;Adding indexes.&lt;/li&gt;
&lt;li&gt;Adding throttling configuration to API endpoints.&lt;/li&gt;
&lt;li&gt;Fixing bugs in a user interface.&lt;/li&gt;
&lt;li&gt;A very small feature that builds on top of an existing data structure we have.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of those changes were then reviewed, tested, approved, and merged within three interactions. I personally feel like I've had more of a "testing" mindset when reviewing the work from Mx Robot. I don't trust that it will have caught everything, so there is more testing overhead here. Keep this in mind when thinking about productivity. You don't get the results entirely for free without human productivity helping.&lt;/p&gt;

&lt;p&gt;How did it all play out then?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;11% of pull requests were abandoned as way off the mark.&lt;/li&gt;
&lt;li&gt;22% of pull requests had 2 comments to get the change ready for human review.&lt;/li&gt;
&lt;li&gt;22% of pull requests had no feedback, were tested locally, and then merged.&lt;/li&gt;
&lt;li&gt;56% of pull requests had one piece of feedback.&lt;/li&gt;
&lt;li&gt;22% of pull requests took a further 2 commits to get them over the line.

&lt;ul&gt;
&lt;li&gt;Looking at the feedback, this was consistently due to bad linting and/or fixing tests.&lt;/li&gt;
&lt;li&gt;This was the case even though we have a &lt;code&gt;copilot-instructions.md&lt;/code&gt; file explaining all linting and tests need to pass for each change.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  What didn’t work
&lt;/h2&gt;

&lt;p&gt;The flow of going from Jira to a GitHub Issue or Copilot window is very clunky. So much so, that we aim to trial not working in Jira for an entire week. We want to bring the product managers and designers closer to Mx Robot, not make engineers a proxy from ticket to pull request. "Pushing left" is still a thing in this new era.&lt;/p&gt;

&lt;p&gt;The other big take away from the two weeks would be specificity. When we were super clear what we wanted, it did well. Where we were more vague we had to be more involved with the pull request. I suspect this is the distinction between AI Assisted and Vibe Coding. We did care about the code, and the solution, in comparison to vibe coding where you're less concerned with the output of code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next experiments
&lt;/h2&gt;

&lt;p&gt;Next week we are going to mix it up a little.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove the 9am call and let each engineer decide what is given to Mx Robot. We believe we learnt a lot last week to the point where pairing on delegation is less fruitful.&lt;/li&gt;
&lt;li&gt;We are going to try giving Mx Robot some more complicated work.&lt;/li&gt;
&lt;li&gt;We may try being more vague again on the assignment. We need to find a balance here.&lt;/li&gt;
&lt;li&gt;We are going to keep a good and a bad change and then review. The aim is to see what changes we can make to hit the target quicker.&lt;/li&gt;
&lt;li&gt;Delve a little deeper into &lt;a href="https://docs.github.com/en/copilot/how-tos/context/copilot-spaces/creating-and-using-copilot-spaces" rel="noopener noreferrer"&gt;Copilot Spaces&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Speaking for myself, I believe it increased the cognitive load and context switching to some extent. However, I think this is about letting the flow bed in. Removing the sync call at 9am will give us some time back, that means we can spread the AI reviews throughout the day a little more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Be direct. We asked "Can you create a pull request", and the answer was "Yes". Did it create the pull request - No. Changing this to "Create a pull request that..." helped.&lt;/li&gt;
&lt;li&gt;Keep tasks small and scoped. I personally like creating lists. It turns out, AI like lists too.&lt;/li&gt;
&lt;li&gt;Review the PRs like you would a junior dev’s. It’s good, but not infallible.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;It’s early days, but I can see this becoming a core part of my workflow. Not because it’s flashy, but because it quietly gets things done. I'm curious to see when our Mx Robot might be up for promotion too.&lt;/p&gt;

&lt;p&gt;... and yes, the banner image was created by Copilot (and Leonardo Da Vinci).&lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>newbie</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Dependency Management</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sat, 18 Jan 2025 21:40:05 +0000</pubDate>
      <link>https://dev.to/benmatselby/dependency-management-197n</link>
      <guid>https://dev.to/benmatselby/dependency-management-197n</guid>
      <description>&lt;p&gt;This post is going to be an advocate for managing your project dependencies and ensuring they are up to date. This seems to be a controversial topic, so I suspect we won't all agree. I think it comes down to your personal experience as to how you might view dependencies.&lt;/p&gt;

&lt;p&gt;Back in my early career days, I had to deal with fixing dependencies when a security exploit was discovered in one of them. It was a real pain, and I never wanted to do it again under those circumstances: super stressful and time-sensitive. So, I made a firm decision: keeping dependencies up to date was the way to go.&lt;/p&gt;

&lt;p&gt;Checkout the &lt;a href="https://dora.dev/capabilities/code-maintainability/" rel="noopener noreferrer"&gt;Code maintainability&lt;/a&gt; capability on the DORA website for a more robust argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a project dependency?
&lt;/h2&gt;

&lt;p&gt;A dependency, or library, is essentially someone else's code. You would install this via your language's package manager, for example &lt;code&gt;npm&lt;/code&gt; (Node), &lt;code&gt;composer&lt;/code&gt; (PHP), or &lt;code&gt;pip&lt;/code&gt; (Python).&lt;/p&gt;

&lt;p&gt;The dependency is likely to give you some functionality that you do not want to write yourself. This could be as grand as a framework, such as React, Django, or Symfony. Or, it could be a dev tool like a code linter, and everything in between.&lt;/p&gt;

&lt;p&gt;You essentially outsource the responsibility of logic to another project or engineer to perform a capability for you. In most cases, you will interact with it through its public API or contract within your project.&lt;/p&gt;

&lt;p&gt;Before you keep adding dependencies to your project, you may want to consider if it’s better to use a third-party project, or to write it yourself. Whilst it is quicker to install other libraries into your project, in the long run it may actually be harder to support. We delve into this next.&lt;/p&gt;

&lt;h2&gt;
  
  
  So why do we need to keep dependencies up to date?
&lt;/h2&gt;

&lt;p&gt;It's a valid question. For me, it breaks down as follows:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt; - If a dependency has a security exploit, you want to be able to update it as soon as possible. This is to ensure your project is not vulnerable to attack. The longer you have left the dependency to decay, the harder it could be to update it. For example if there have been major version changes, you might need to refactor your code to integrate with the new version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bug fixes&lt;/strong&gt; - It's likely that your dependency has been worked on by the project owners. Just like your code, the library may have had bug fixes, and performance improvements applied. Your application could benefit from these changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Improvements&lt;/strong&gt; - Maybe the library has had some new features added to it, that could improve your project. By updating frequently, the changeset you need to understand is minimal. You might be able to do small refactors to your existing code to take advantage of the new features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compatibility&lt;/strong&gt; - If you're using a library that is not being updated, you could find yourself in a situation where you're unable to update other dependencies. This could be because the old library version is no longer compatible with the newer versions of other dependencies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Maintenance&lt;/strong&gt; - Regular updates prevent the accumulation of technical debt, making it easier to maintain your project in the long run.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to keep the dependencies up to date?
&lt;/h2&gt;

&lt;p&gt;We have a few options available to us here. As mentioned above, really think about if a dependency is even required.&lt;/p&gt;

&lt;p&gt;If you really need the dependency, then you can either update your dependencies manually, or you can automate the process.&lt;/p&gt;

&lt;p&gt;I'd recommend automating the process, which takes the burden away from keeping them up to date (almost).&lt;/p&gt;

&lt;p&gt;Some options would include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/dependabot" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt; - Built within the GitHub product set, this will create pull requests for you to update your dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.renovatebot.com" rel="noopener noreferrer"&gt;Renovate&lt;/a&gt; - A vendor agnostic solution, that can be used with GitHub, GitLab, Bitbucket, and Azure DevOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've personally only ever worked with Dependabot, and never really had any issues with it.&lt;/p&gt;

&lt;p&gt;An example of what a simple Dependabot configuration looks like is as follows. This will monitor your &lt;code&gt;npm&lt;/code&gt; dependencies on a weekly schedule and raise pull requests for you, if your dependencies are out of date. Check out &lt;a href="https://docs.github.com/en/code-security/dependabot/ecosystems-supported-by-dependabot/supported-ecosystems-and-repositories" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; to see if your package repository is supported.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/dependabot.yml&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Maintain dependencies for npm&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/'&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;weekly'&lt;/span&gt;
    &lt;span class="na"&gt;commit-message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However you update your dependencies, I would recommend at least reviewing the changelog for the updated version. Automation is fantastic, and you can get all your automated tests running, and merge without a human being involved. However, you lose context. You would not find out about new features and improvements unless you review the changelog. It's also a good habit to know what you're installing into your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, we explored the importance of managing and regularly updating your project dependencies. Keeping dependencies up to date is crucial for maintaining security, fixing bugs, accessing new features, ensuring compatibility, and improving performance. Outdated dependencies can lead to significant issues such as security vulnerabilities, compatibility problems, and technical debt.&lt;/p&gt;

&lt;p&gt;I highly recommend you get them up to date, and then automate the process for keeping them up to to date. Good luck.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@mikehindle?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Mike Hindle&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-black-and-white-photo-of-a-bunch-of-cubes-0HXXmDxVJu8?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/2024/automating-the-startup-of-a-dev-workflow/" rel="noopener noreferrer"&gt;Automating the startup of a dev workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/technical-roadmaps/" rel="noopener noreferrer"&gt;Technical Roadmaps and Dev Sustainability&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Stop tracking changes to certain files in Git</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sat, 04 May 2024 07:34:30 +0000</pubDate>
      <link>https://dev.to/benmatselby/stop-tracking-changes-to-certain-files-in-git-24g6</link>
      <guid>https://dev.to/benmatselby/stop-tracking-changes-to-certain-files-in-git-24g6</guid>
      <description>&lt;p&gt;If you've used &lt;code&gt;git&lt;/code&gt; before, you're probably aware of the &lt;code&gt;.gitignore&lt;/code&gt; file. This is what the &lt;a href="https://git-scm.com/docs/gitignore" rel="noopener noreferrer"&gt;manual&lt;/a&gt; has to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A gitignore file specifies intentionally untracked files that Git should ignore.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This file is usually tracked in your Git repo, so every contributor ignores the same files. Interestingly, you can also have a global ignore file in your home directory too &lt;code&gt;~/.gitignore&lt;/code&gt;. I have a &lt;a href="https://github.com/benmatselby/dotfiles/blob/main/git/.gitignore" rel="noopener noreferrer"&gt;global ignore file&lt;/a&gt; for ignoring basic IDE files.&lt;/p&gt;

&lt;p&gt;Recently, I had a situation whereby the team was split on whether a file should, or should not, be ignored. Tricky, however, there is a way around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assume unchanged
&lt;/h2&gt;

&lt;p&gt;Let's say a file is not going to be ignored in the repo, but you specifically don't want to track changes to this file locally, you can run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git update-index &lt;span class="nt"&gt;--assume-unchanged&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;file]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what the &lt;a href="https://git-scm.com/docs/git-update-index" rel="noopener noreferrer"&gt;manual&lt;/a&gt; has to say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When this flag is specified, the object names recorded for the paths are not updated. Instead, this option sets/unsets the "assume unchanged" bit for the paths. When the "assume unchanged" bit is on, the user promises not to change the file and allows Git to assume that the working tree file matches what is recorded in the index.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;OK, so you're promising that you won't change the file. I think this works for our situation, as the promise is really "I don't mind if Git doesn't track this file locally". This does not impact anyone else on your project either, so it's win win.&lt;/p&gt;

&lt;p&gt;OK, let's say you change your mind and you do want to commit changes to the file. Here's what you do to track the file locally again.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git update-index &lt;span class="nt"&gt;--no-assume-unchanged&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;file]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if you've completely forgotten what files you are, or are not, assuming unchanged?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git ls-files &lt;span class="nt"&gt;-v&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;"^[[:lower:]]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-v&lt;/code&gt; flag will alter the &lt;code&gt;ls-files&lt;/code&gt; output to put a lowercase letter before the file if the &lt;code&gt;assume-unchanged&lt;/code&gt; bit is set. e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;h untracked-file.ts
H tracked-file.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means we can then grep on lowercase letters to see which files are &lt;code&gt;assume-unchanged&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Hopefully, this solution helps you ignore files that you don't want to commit by accident, without them being in the &lt;code&gt;.gitignore&lt;/code&gt; file for your project.&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/benmatselby/git-commands-to-get-you-through-the-day-191i"&gt;Git commands to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.toSquashing%20commits"&gt;Squashing commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/benmatselby/logically-atomic-commits-4lje"&gt;Logically atomic commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chris.beams.io/posts/git-commit/" rel="noopener noreferrer"&gt;How to Write a Git Commit Message&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>howto</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Working with Zed for a week</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Thu, 01 Feb 2024 19:47:32 +0000</pubDate>
      <link>https://dev.to/benmatselby/working-with-zed-for-a-week-kk5</link>
      <guid>https://dev.to/benmatselby/working-with-zed-for-a-week-kk5</guid>
      <description>&lt;p&gt;I took &lt;a href="https://zed.dev/" rel="noopener noreferrer"&gt;Zed&lt;/a&gt; for a spin this week, and this post covers what I noticed whilst using it as my day-to-day editor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I love it, and I'm probably going to stay with it (but I miss a debugger).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is what Zed is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Zed is a high-performance, multiplayer code editor from the creators of Atom and Tree-sitter. It's also open source.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Projects worked on:
&lt;/h2&gt;

&lt;p&gt;These are the projects I managed to work on this week with Zed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python project - 4m+ lines of code&lt;/li&gt;
&lt;li&gt;Go project  - 7k+ lines of code&lt;/li&gt;
&lt;li&gt;Markdown - This blog post&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  No debugger
&lt;/h2&gt;

&lt;p&gt;Honestly, I thought I would miss this a lot more than I did. However, to remove VS Code from my setup, I'd need the debugger. Firing up a second editor, to find the files, to then debug is a little tedious.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's fast
&lt;/h2&gt;

&lt;p&gt;Apart from searching for a symbol, which feels slower than VS Code, Zed seems quicker overall. I prefer the slim-down nature of it in comparison to VS Code. It certainly reminds me of Sublime Text, which I loved (and also now struggle to remember why I stopped using it!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Collaboration UI
&lt;/h2&gt;

&lt;p&gt;I managed to get a colleague to pair with me for 15 minutes using Zed, and it took us a wee while to get used to what the user interface was telling us. It's handy though:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Screensharing - Although we couldn't seem to configure which screen to share, so it shared my work diary, not the screen with the editor on. You live and learn.&lt;/li&gt;
&lt;li&gt;Audio 1:1 calling - This was the first thing we tried, and the quality levels were very good.&lt;/li&gt;
&lt;li&gt;Channel audio - It seems like you have to join the audio even if you just want to use the text chat. Maybe this was an oversight by us though?&lt;/li&gt;
&lt;li&gt;Channel messaging - Slight &lt;a href="https://github.com/zed-industries/zed/issues/6706" rel="noopener noreferrer"&gt;bug&lt;/a&gt; that you couldn't copy the messages from the chat window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have one slight concern about this feature: Normally all this context is in Slack (for me at least), but it would be in Zed. Does this lose a collaboration touch point with the rest of the team who aren't in Zed? One to ponder. You may want to pull in a Product Manager, or a designer into the conversation (They are generally saviours to any given situation). I highly doubt they would install an editor to do that. It does, however, remind me of the early 2000's when engineers had to use IRC to communicate with each other. It's a little bit secret, which makes it fun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Git integration
&lt;/h2&gt;

&lt;p&gt;This was a surprise to me, as I hadn't anticipated this impacting me. I use &lt;code&gt;git&lt;/code&gt; on the CLI. I've never used a UI, and I struggle with them for &lt;code&gt;git&lt;/code&gt;. However, what I did miss was the little "git insights" you can get in VS Code. e.g. "Developer Alice modified this code last week".&lt;/p&gt;

&lt;p&gt;This gives you a sense of "freshness" of the code. Back to &lt;code&gt;git blame&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keymaps
&lt;/h2&gt;

&lt;p&gt;Although it says I was using the VS Code one, there were a &lt;a href="https://github.com/benmatselby/dotfiles/blob/main/zed/keybindings.json" rel="noopener noreferrer"&gt;few keymap changes&lt;/a&gt; I needed to make. No big drama.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outline view
&lt;/h2&gt;

&lt;p&gt;It would be nice to have the Outline View as a scrollable dock item, rather than a modal. It feels prohibitive as a modal, and it doesn't allow you to collapse certain symbols. So in a codebase that may have 15 classes in a file, you couldn't focus on the class you want to look at. It's all expanded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unused variables
&lt;/h2&gt;

&lt;p&gt;It would be good to highlight unused variables, assuming this comes from the language server. It wasn't a biggy, as pre-commit hooks captured it, but it slows you down ever so slightly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copilot
&lt;/h2&gt;

&lt;p&gt;Easily configured, but I did miss having Copilot Chat. You can use the &lt;a href="https://docs.zed.dev/general/assistant-panel" rel="noopener noreferrer"&gt;Open AI integration&lt;/a&gt;, but I already have a license for GitHub Copilot, so not sure I want to pay for both services.&lt;/p&gt;

&lt;h2&gt;
  
  
  It seems to "Just work (tm)"
&lt;/h2&gt;

&lt;p&gt;I've pretty much &lt;a href="https://github.com/benmatselby/dotfiles/tree/main/vscode" rel="noopener noreferrer"&gt;automated the install for VS Code&lt;/a&gt;, but it feels like there is a "lot going on". That doesn't feel the same with Zed. I opened a Python file for the first time, and it downloaded the language server. Same with the Go codebase.&lt;/p&gt;

&lt;p&gt;Apart from the debugger, it had the right level of tools I needed. I also work on TypeScript and PHP projects, so that will be the next test to see how it handles those languages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I'm going to stick with it. I suspect I will fire VS Code up when I need to debug something, but let's see how we go with Zed for a little bit longer.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@diegojimenez?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Diego Jimenez&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/lone-road-going-to-mountains-A-NVHPka9Rk?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/2024/automating-the-startup-of-a-dev-workflow/" rel="noopener noreferrer"&gt;Automating the startup of a dev workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/benmatselby/dotfiles" rel="noopener noreferrer"&gt;My dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/2023/setting-up-k9s-skins-for-environments/" rel="noopener noreferrer"&gt;Setting up k9s skins for different Kubernetes clusters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/communication-tools/" rel="noopener noreferrer"&gt;Collaborative Communication Tools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>review</category>
      <category>productivity</category>
      <category>editor</category>
      <category>zed</category>
    </item>
    <item>
      <title>Show your working out</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Mon, 22 Jan 2024 19:22:35 +0000</pubDate>
      <link>https://dev.to/benmatselby/show-your-working-out-2845</link>
      <guid>https://dev.to/benmatselby/show-your-working-out-2845</guid>
      <description>&lt;p&gt;Does anyone remember what your Maths teacher used to say?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show your working out!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I mean, I bet they said more than that, but this is what I remembered. I think we used to get marked down if you just provided the answer. You got more marks when you showed how you derived your answer.&lt;/p&gt;

&lt;p&gt;This post is a plea for software engineers to do the same when answering technical questions, or debugging an issue in group communication channels.&lt;/p&gt;

&lt;p&gt;Let's take a standard question we are probably asked from time to time: "Can we see if there is a performance issue on our application right now, please?"&lt;/p&gt;

&lt;p&gt;It's a typical question, so let's show differing levels of answering this question.&lt;/p&gt;

&lt;h2&gt;
  
  
  1 - Just the answer 🙂
&lt;/h2&gt;

&lt;p&gt;You're asked, and you answer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No, I cannot see any performance issues at the moment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Helpful to the originator of the question, they have their answer. Perhaps less useful to the next engineer to come along?&lt;/p&gt;

&lt;h2&gt;
  
  
  2 - The answer and visuals 😊😊
&lt;/h2&gt;

&lt;p&gt;You're asked, you answer, and you provide some evidence to back up your opinion.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No, I cannot see any performance issues at the moment. See the attached graphs for the relevant systems.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Graphs attached&lt;/em&gt; 📈📊💹📉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With any luck, the graph will provide some hints to the next engineer where you got the data from. The next engineer may be able to come to the same conclusion. Maybe next time, they can help answer the question (Multiplier effect).&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3 - The answer, the visuals, and links to the original data source 😊👑🧠
&lt;/h2&gt;

&lt;p&gt;You're asked, you answer. This time, you provide clickable links to the original data source that backs up your opinion ❤️.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Looking at this graph for system A, and this graph for system B, I cannot see any performance issues in the last hour. Interestingly, if you scale out here for 1 week, we are running a little quicker than the norm.&lt;/p&gt;

&lt;p&gt;See the attached graphs for the relevant systems.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Graphs attached&lt;/em&gt; 📈📊💹📉&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With this level of context, many engineers can now walk in your shoes as to how you answered the question (Multiplier effect unlocked). Ideally, for those without direct access to monitoring systems, you provide visuals that are useful within in your communication format (be it Slack, email etc).&lt;/p&gt;

&lt;p&gt;For me, this is the best type of answer to the situation. Sure, it takes longer, but perhaps this unlocks others to start answering the same questions in the future. The more you share knowledge around engineers, the quicker we can collectively respond to questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I'd recommend we strive for example 3 above. If you provide enough context, others can learn from your experience. This unlocks their potential, and allows everyone to deliver at pace.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@syinq?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Susan Q Yin&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/books-on-brown-wooden-shelf-2JIvboGLeho?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>newbie</category>
      <category>communication</category>
      <category>beginners</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A case for using a Makefile in your project</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Wed, 17 Jan 2024 20:12:23 +0000</pubDate>
      <link>https://dev.to/benmatselby/a-case-for-using-a-makefile-in-your-project-l7n</link>
      <guid>https://dev.to/benmatselby/a-case-for-using-a-makefile-in-your-project-l7n</guid>
      <description>&lt;p&gt;This post is going to present a case for using a &lt;code&gt;Makefile&lt;/code&gt; in your project. This will be the top-level task runner for your project. You can use &lt;code&gt;make&lt;/code&gt; to run all of your project tasks such as building, linting, testing, and deploying your project. It doesn’t matter what language your project is written in.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Makefile?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files. When you write a program, you should write a makefile for it, so that it is possible to use Make to build and install the program.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://www.gnu.org/software/make/" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Straight out of the gate, this doesn’t necessarily seem like something we could make use of, does it? However, at its core, a &lt;code&gt;Makefile&lt;/code&gt; allows you to define a bunch of instructions together. Each set of instructions can then be given a name, and this becomes the “target”. We use a tool called &lt;code&gt;make&lt;/code&gt; to run one of the targets defined in a &lt;code&gt;Makefile&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you’re working on JavaScript projects, for example, you may be using tools like &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;yarn&lt;/code&gt;, or &lt;code&gt;pnpm&lt;/code&gt; to run your tasks. A &lt;code&gt;Makefile&lt;/code&gt; is a very similar concept, and I’d recommend you have both.&lt;/p&gt;

&lt;p&gt;The reason for this recommendation is abstractions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Abstraction
&lt;/h2&gt;

&lt;p&gt;We can use &lt;code&gt;make&lt;/code&gt; to define an abstraction layer between your internal project decisions, and the outside world (a contract). The outside world could include what gets run in your CI/CD pipeline, or what engineers run in their terminals to build and test the project. By defining and making use of a &lt;code&gt;Makefile&lt;/code&gt;, you can change your internal project workings, but leave the contract intact.&lt;/p&gt;

&lt;p&gt;A concrete example for a JavaScript project could be switching your project from using &lt;code&gt;npm&lt;/code&gt; to &lt;code&gt;pnpm&lt;/code&gt;. If you’re using tasks within your &lt;code&gt;package.json&lt;/code&gt; you have probably exposed &lt;code&gt;npm run ...&lt;/code&gt; tasks in your CI/CD pipeline, your README, and your engineers will be running those commands. If you change your tool to &lt;code&gt;pnpm&lt;/code&gt; you suddenly need to change a lot more code to bed this in. Your engineers also need to change their muscle memory to use the new version of the command. However, if you had a &lt;code&gt;Makefile&lt;/code&gt; as a facade for your project, your &lt;code&gt;make build&lt;/code&gt; task would stay the same to the outside world, but the internals of what &lt;code&gt;make build&lt;/code&gt; does would change to use &lt;code&gt;pnpm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another example could be for a project written in Go, where there really isn’t a task runner, and you may need to remember a rather complicated command to build your Go binaries. By having a &lt;code&gt;Makefile&lt;/code&gt; you can document all the key commands in one place, and reference them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at a single &lt;code&gt;make&lt;/code&gt; target from &lt;a href="https://github.com/benmatselby/walter/blob/main/Makefile" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;, which is a Go project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight make"&gt;&lt;code&gt;&lt;span class="nl"&gt;.PHONY&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;test&lt;/span&gt;
&lt;span class="nl"&gt;test&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;##&lt;/span&gt;&lt;span class="nf"&gt; Run the unit tests&lt;/span&gt;
  &lt;span class="err"&gt;go&lt;/span&gt; &lt;span class="err"&gt;test&lt;/span&gt; &lt;span class="err"&gt;./...&lt;/span&gt; &lt;span class="nv"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;coverage.out
  &lt;span class="err"&gt;go&lt;/span&gt; &lt;span class="err"&gt;tool&lt;/span&gt; &lt;span class="err"&gt;cover&lt;/span&gt; &lt;span class="nv"&gt;-func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;coverage.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above shows a single &lt;code&gt;make&lt;/code&gt; target called &lt;code&gt;test&lt;/code&gt;. We can execute this target by running &lt;code&gt;make test&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;❯ make &lt;span class="nb"&gt;test
&lt;/span&gt;go &lt;span class="nb"&gt;test&lt;/span&gt; ./... &lt;span class="nt"&gt;-coverprofile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;coverage.out
ok      github.com/benmatselby/walter/cmd       0.504s  coverage: 18.2% of statements
ok      github.com/benmatselby/walter/cmd/board 0.243s  coverage: 75.7% of statements
ok      github.com/benmatselby/walter/cmd/search        0.844s  coverage: 90.6% of statements
ok      github.com/benmatselby/walter/cmd/sprint        1.052s  coverage: 85.5% of statements
go tool cover &lt;span class="nt"&gt;-func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;coverage.out
github.com/benmatselby/walter/cmd/board/board.go:9:             NewBoardCommand100.0%
github.com/benmatselby/walter/cmd/board/issues.go:15:           NewIssueCommand33.3%
github.com/benmatselby/walter/cmd/board/issues.go:33:           ListIssues     93.8%
github.com/benmatselby/walter/cmd/board/list.go:13:             NewListCommand 33.3%
github.com/benmatselby/walter/cmd/board/list.go:30:             DisplayBoards  100.0%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we have output from the two commands defined in the &lt;code&gt;test&lt;/code&gt; target. This is the same command engineers use when testing the software on their machines, to what is run in the &lt;a href="https://github.com/benmatselby/walter/blob/main/.github/workflows/go.yml#L36" rel="noopener noreferrer"&gt;CI/CD platform&lt;/a&gt; for quality checks.&lt;/p&gt;

&lt;p&gt;If we wanted to change the options to &lt;code&gt;go test&lt;/code&gt;, we could do this in one place, and it not impact everywhere else. It would be a trivial encapsulated change. We could also switch out &lt;code&gt;go test&lt;/code&gt; for another test runner, and it wouldn’t impact anything else either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation
&lt;/h2&gt;

&lt;p&gt;Taking this further, if you can define a standard &lt;code&gt;Makefile&lt;/code&gt; for all of your projects with the same target names, you can probably automate more things at a higher level. For example, you could do the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone your all git repos for your solution.&lt;/li&gt;
&lt;li&gt;Iterate over each one and install their dependencies (&lt;code&gt;make install&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Run the unit tests to make sure they work (&lt;code&gt;make test&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Run each application (&lt;code&gt;make run&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Perhaps this could be part of an automated system to spin up your entire project stack on your local machine. It wouldn’t matter if some of those projects were Go, React, Python, PHP for example, as the public contract (The &lt;code&gt;Makefile&lt;/code&gt;) is the same.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As with most things, you have to decide if adding an extra abstraction layer is worth it. I’ve been using a &lt;code&gt;Makefile&lt;/code&gt; in my projects since about 2013 when we transitioned a PHP project away from &lt;code&gt;ant&lt;/code&gt;/&lt;code&gt;phing&lt;/code&gt;. These projects have ranged in the language used, but what is consistent is the name of the Make targets. I can pretty much clone any personal repo, and remember all the &lt;code&gt;make&lt;/code&gt; commands irrelevant if the project is PHP, Python, JavaScript, Go etc.&lt;/p&gt;

&lt;p&gt;As outlined in &lt;a href="https://benmatselby.dev/post/development-environments/" rel="noopener noreferrer"&gt;this post (2018)&lt;/a&gt; using &lt;code&gt;make&lt;/code&gt; to define how to run and test your project has gone into a full ecosystem to build development environments for engineers.&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/development-environments/" rel="noopener noreferrer"&gt;Development environments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/2024/automating-the-startup-of-a-dev-workflow/" rel="noopener noreferrer"&gt;Automating the startup of a dev workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/vscode-dev-containers/" rel="noopener noreferrer"&gt;Setting up a VS Code Dev Container&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Automating the startup of a dev workflow</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Tue, 02 Jan 2024 19:09:39 +0000</pubDate>
      <link>https://dev.to/benmatselby/automating-the-startup-of-a-dev-workflow-22dl</link>
      <guid>https://dev.to/benmatselby/automating-the-startup-of-a-dev-workflow-22dl</guid>
      <description>&lt;p&gt;Hopefully, this is the first of many small posts showing how I automate my workflow.&lt;/p&gt;

&lt;p&gt;Back around 2008, I had a mentor/buddy for my new job. Rys. He was a wonderful, knowledgeable, and supportive buddy who always seemed to be one step ahead.&lt;/p&gt;

&lt;p&gt;One day he noticed that I came into the office each day, opened the terminal, and created x amount of tabs, which I then named (So I knew what each terminal was there for, e.g. logs, database, git, and codebases etc).&lt;/p&gt;

&lt;p&gt;He asked me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How much time would you save if you could automate that?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sitting there, stunned, I wasn't sure how to do what he said, but that question has stuck with me throughout my career. Then over the years, I've started to automate more and more, because I would remember Rys asking me how much time I would save.&lt;/p&gt;

&lt;p&gt;So, I now have an alias defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;start-company&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  open &lt;span class="nt"&gt;-a&lt;/span&gt; Music
  open &lt;span class="nt"&gt;-a&lt;/span&gt; Slack
  open &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"Google Chrome"&lt;/span&gt;
  open &lt;span class="nt"&gt;-a&lt;/span&gt; Obsidian
  open &lt;span class="nt"&gt;-a&lt;/span&gt; Notion
  open &lt;span class="nt"&gt;-a&lt;/span&gt; Miro
  open &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"Visual Studio Code"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where &lt;code&gt;company&lt;/code&gt; is the name of the company I work for. This may seem small, and maybe even obvious, but running &lt;code&gt;start-company&lt;/code&gt; each time I boot my machine is substantially quicker than opening each application in turn.&lt;/p&gt;

&lt;p&gt;Running this command is the first of many stacked habits I have in the morning. For more information on stacking habits, check out &lt;a href="https://jamesclear.com/atomic-habits" rel="noopener noreferrer"&gt;Atomic Habits&lt;/a&gt;. I'm hopefully going to write up other habits I have for my workflow.&lt;/p&gt;

&lt;p&gt;So I have my terminal and other applications open, but how about naming those darn terminal windows Rys asked me about all those years ago?&lt;/p&gt;

&lt;p&gt;Well, I now use &lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;tmux&lt;/a&gt; and &lt;a href="https://github.com/tmuxinator/tmuxinator" rel="noopener noreferrer"&gt;tmuxinator&lt;/a&gt;. I have had many failed &lt;code&gt;tmux&lt;/code&gt; attempts over the years, but I'm firmly bedded in now.&lt;/p&gt;

&lt;p&gt;What is &lt;code&gt;tmux&lt;/code&gt;?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That nicely brings us to &lt;code&gt;tmuxinator&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Create and manage tmux sessions easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Therefore I can start a &lt;code&gt;tmux&lt;/code&gt; session, via &lt;code&gt;tmuxinator&lt;/code&gt;, which has a defined configuration. So one example would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: dotfiles
root: ~/

windows:
  - bms: cd ~/git/github/benmatselby
  - work: cd ~/git/github/[company-name]
  - dotfiles: cd ~/git/github/benmatselby/dotfiles
  - life: cd ~/git/github/benmatselby/life
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I now run &lt;code&gt;tmuxinator start dotfiles&lt;/code&gt; (I have this aliased to &lt;code&gt;txs&lt;/code&gt;), I get 4 named windows/tabs in a &lt;code&gt;tmux&lt;/code&gt; session, all in the correct working directory. This is a massive time saving for me. I have many &lt;code&gt;tmuxinator&lt;/code&gt; configuration files now. Each project generally gets its own configuration.&lt;/p&gt;

&lt;p&gt;Hopefully, this setup is useful, or maybe interesting to you. Happy automating folks 😊&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@sortino?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Joshua Sortino&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/worms-eye-view-photography-of-ceiling-LqKhnDzSF-8?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/benmatselby/dotfiles" rel="noopener noreferrer"&gt;My dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/2023/setting-up-k9s-skins-for-environments/" rel="noopener noreferrer"&gt;Setting up k9s skins for different Kubernetes clusters&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>automation</category>
      <category>tooling</category>
      <category>workflow</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Setting up k9s skins for different Kubernetes clusters</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sat, 01 Apr 2023 07:18:07 +0000</pubDate>
      <link>https://dev.to/benmatselby/setting-up-k9s-skins-for-different-kubernetes-clusters-527j</link>
      <guid>https://dev.to/benmatselby/setting-up-k9s-skins-for-different-kubernetes-clusters-527j</guid>
      <description>&lt;p&gt;This post is going to show you how to define different skins for &lt;a href="https://k9scli.io" rel="noopener noreferrer"&gt;k9s&lt;/a&gt;, so you can quickly see which environment you're working on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;k9s&lt;/code&gt; is a terminal application that allows you to manage your &lt;a href="https://kubernetes.io" rel="noopener noreferrer"&gt;Kubernetes&lt;/a&gt; clusters. So if you're managing your production cluster, for example, you probably want to take extra care of what you're doing.&lt;/p&gt;

&lt;p&gt;Every time I jump onto a production database for nearly two decades, I have set the background to red. Over the years better tooling has come out, so I now have iTerm profiles that allow me to quickly change the colour of the background when in different environments. Recently I was doing a bit of work on a Kubernetes platform using &lt;code&gt;k9s&lt;/code&gt; and was doing the same thing, setting my iTerm profile. Then I checked on the &lt;code&gt;k9s&lt;/code&gt; docs and realised you can do this within &lt;code&gt;k9s&lt;/code&gt;. More importantly, it would be automatic &lt;strong&gt;based on your cluster name&lt;/strong&gt;, which sounds even better.&lt;/p&gt;

&lt;p&gt;So, I've set up the following skins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standard skin&lt;/li&gt;
&lt;li&gt;A testing skin&lt;/li&gt;
&lt;li&gt;A production skin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check out the &lt;a href="https://github.com/derailed/k9s/tree/master/skins" rel="noopener noreferrer"&gt;official skins on GitHub&lt;/a&gt;. I've based my skins on &lt;code&gt;monokai.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once you have picked your base skin, save it to this path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/k9s/skin.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you now fire up &lt;code&gt;k9s&lt;/code&gt;, you should have the skin you have picked. This is what mine looks like as standard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r10cwcam64l4fwkqx88.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1r10cwcam64l4fwkqx88.png" alt="k9s standard monokai skin" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we want to move on to the good stuff and have different skins for different clusters. Well luckily, &lt;a href="https://k9scli.io/topics/skins/" rel="noopener noreferrer"&gt;k9s supports this&lt;/a&gt;. It's about naming the skin after the cluster name. So, I have a cluster called &lt;code&gt;prod&lt;/code&gt;, therefore I've created a file called:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/k9s/prod_skin.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The theme is still the base &lt;code&gt;monokai.yml&lt;/code&gt; skin, but I changed the &lt;code&gt;background&lt;/code&gt; value to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;background&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;background&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#41000c'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now, when I connect to the &lt;code&gt;prod&lt;/code&gt; cluster using &lt;code&gt;k9s&lt;/code&gt;, my experience looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhzqtnj0mlilygzrg7kx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhzqtnj0mlilygzrg7kx.png" alt="k9s production monokai skin with red background" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've also gotten into the habit of having a specific colour for testing environments. So basically only my local development environment looks "normal". Everything else has a colour that can imply how worried I should be about making changes. My testing skin has a dark purple background.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd40kam6tr43sf4he47p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd40kam6tr43sf4he47p.png" alt="k9s testing monokai skin with purple background" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of these skins are defined in my &lt;a href="https://github.com/benmatselby/dotfiles/tree/main/k9s" rel="noopener noreferrer"&gt;dotfiles repo&lt;/a&gt; and you can see I &lt;a href="https://github.com/benmatselby/dotfiles/blob/main/k9s/install.sh" rel="noopener noreferrer"&gt;symlink&lt;/a&gt; the skins, so I can easily track changes in git.&lt;/p&gt;

&lt;p&gt;Hopefully, you found this useful.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@ventiviews?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Venti Views&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/1cqIcrWFQBI?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How useful are code coverage reports?</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sun, 06 Nov 2022 14:37:49 +0000</pubDate>
      <link>https://dev.to/benmatselby/how-useful-are-code-coverage-reports-4a3m</link>
      <guid>https://dev.to/benmatselby/how-useful-are-code-coverage-reports-4a3m</guid>
      <description>&lt;p&gt;This post is going to talk about code coverage reports from unit tests. However, to provide some context first, I'm going to reminisce about 2010.&lt;/p&gt;

&lt;h2&gt;
  
  
  A story
&lt;/h2&gt;

&lt;p&gt;Back in 2010, I was working for &lt;a href="https://www.plus.net" rel="noopener noreferrer"&gt;Plusnet, an ISP in the UK&lt;/a&gt; (&lt;a href="https://www.plus.net/refer.php?strReferralsUid=f612ba7d23963c179e27ccabe44ecc45c38e8a51542adc4e0602250fdc677760" rel="noopener noreferrer"&gt;Referral link&lt;/a&gt;). The engineering team were still getting to grips with unit testing our code. What we saw time and time again was many tests being written, high coverage reports, and management was happy. However, if you checked out a test, we saw that tests were running, and executing code, but they were not asserting anything. This meant the tests were more of a linter. So &lt;a href="https://github.com/sebastianbergmann/phpunit/commit/19feb8e3cd6c88dab46aebbd053fa26ecb8e3ea7" rel="noopener noreferrer"&gt;I wrote&lt;/a&gt; the &lt;code&gt;--assert-strict&lt;/code&gt; feature in &lt;a href="https://phpunit.de" rel="noopener noreferrer"&gt;PHPUnit&lt;/a&gt; (which has subsequently become &lt;code&gt;fail-on-incomplete&lt;/code&gt;). This helped us raise the quality of our tests at Plusnet.&lt;/p&gt;

&lt;p&gt;Why mention this? Opinions mostly come from experience, and I wanted to share mine before talking about this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;I value coverage reports. It's &lt;strong&gt;&lt;em&gt;a tool&lt;/em&gt;&lt;/strong&gt; in the toolbox, it is not &lt;strong&gt;&lt;em&gt;the&lt;/em&gt;&lt;/strong&gt; tool in the toolbox! It is also not perfect (nothing is).&lt;/p&gt;

&lt;p&gt;When I started a new job this year I found the project had thousands of tests, which is lovely. As a new engineer, I wanted to see what that looked like in terms of coverage. Did we have thousands of tests and high coverage or thousands of tests and low coverage? Why does it matter? For me, it gives me the confidence to make changes in the code. Once I have the confidence, it unlocks the ability to move at pace.&lt;/p&gt;

&lt;p&gt;Getting the coverage report is not easy, as we lack test suites to help figure this out. I briefly mentioned we could work on this, and a colleague mentioned that coverage reports aren't helpful, and folks end up chasing the metric.&lt;/p&gt;

&lt;p&gt;At this point, I want to agree with the latter statement. I value coverage reports, but I do not think you should chase unrealistic metrics.&lt;/p&gt;

&lt;p&gt;Many testing tools allow you to ignore code in coverage reports. I'm genuinely against this concept because I want to gain confidence. I'm personally not after 100%. I'm after the highest coverage you can get, for the maximum benefit, and no more. If there is a gap in coverage, I'm fine with that, as long as it's clear and upfront.&lt;/p&gt;

&lt;p&gt;It's also worth noting that bikeshedding over the last 5% of code coverage, is &lt;em&gt;more than likely&lt;/em&gt; not going to add overall value. You will get diminishing returns, in my opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics
&lt;/h2&gt;

&lt;p&gt;So, back to coverage reports. Line coverage is handy, but try and get a branch coverage report. This shows which paths through the code are tested. That's two metrics that can and should be used with many other metrics you can get from your code, e.g. &lt;a href="https://en.wikipedia.org/wiki/Cyclomatic_complexity" rel="noopener noreferrer"&gt;Cyclomatic Complexity&lt;/a&gt;, and Static Analysis. No single metric can tell the entire story. Let's take a well-known example from the past that no one uses anymore. If you judged a software engineer on one single metric: lines of code written, you are not getting a realistic picture of that engineer!&lt;/p&gt;

&lt;p&gt;Software is no different, you need to weigh all these metrics together. Each metric provides a different lens to look through in terms of quality.&lt;/p&gt;

&lt;p&gt;So, meh, does it really matter?&lt;/p&gt;

&lt;h2&gt;
  
  
  Importance
&lt;/h2&gt;

&lt;p&gt;Well, I would argue that if you don't have visibility of what code your tests are covering, you're now going to rely on monitoring and analytics platforms to identify quality issues with your code. When we say monitoring and analytics platforms, we actually mean our users. Our users are doing things on our platform, and the monitoring systems alert the engineers when things fail.&lt;/p&gt;

&lt;p&gt;This week, as a relevant anecdote, we saw some notifications from &lt;a href="https://rollbar.com" rel="noopener noreferrer"&gt;Rollbar&lt;/a&gt; that showed us something was wrong with a new feature. We managed to get a coverage report for a single module of our code (took a little while), and we saw that the bugs identified in Rollbar were actually not covered by tests.&lt;/p&gt;

&lt;p&gt;I personally want to know about this in development, not from our users, via Rollbar. It's more costly to fix it for one thing, and it's also impacting our customers, which isn't great. It's also stressful working in an environment where you know you have production issues impacting real people.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In conclusion, this is how I would summarise my views on this.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I value a holistic set of data points that help us understand quality in software development.&lt;/li&gt;
&lt;li&gt;Code coverage is a single metric that can be part of that set of metrics you monitor.&lt;/li&gt;
&lt;li&gt;No single metric can stand by itself, and be meaningful.&lt;/li&gt;
&lt;li&gt;Nothing is perfect, which is why we should value a toolbox.&lt;/li&gt;
&lt;li&gt;I don't believe in gaming the system and "hiding" uncovered code to get to 100%.

&lt;ul&gt;
&lt;li&gt;You need engineering teams who are prepared and confident enough to publicly share their coverage reports. This sets the tone of the culture.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Context is needed, always.

&lt;ul&gt;
&lt;li&gt;There will be reasons why the coverage is as it is.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Use tools that help engineering teams with confidence/delivering at pace and ultimately delivering customer satisfaction.&lt;/li&gt;

&lt;li&gt;You cannot compare reports from different teams or projects.

&lt;ul&gt;
&lt;li&gt;More than likely the same with most metrics.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Striving to improve is a mindset we should engage with, so use tools that help that improvement.&lt;/li&gt;

&lt;/ul&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://testing.googleblog.com/2020/08/code-coverage-best-practices.html" rel="noopener noreferrer"&gt;Code Coverage Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>testing</category>
      <category>metrics</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Debugging Python with a virtual environment in VSCode</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sun, 30 Oct 2022 15:09:19 +0000</pubDate>
      <link>https://dev.to/benmatselby/debugging-python-with-a-virtual-environment-in-vscode-1dah</link>
      <guid>https://dev.to/benmatselby/debugging-python-with-a-virtual-environment-in-vscode-1dah</guid>
      <description>&lt;p&gt;My current job is mainly Python, so there was a steep learning curve. I have done some Python previously, but mainly for writing &lt;a href="https://github.com/benmatselby/sublime-phpcs" rel="noopener noreferrer"&gt;Sublime&lt;/a&gt; &lt;a href="https://github.com/benmatselby/sublime-jenkins-dashboard" rel="noopener noreferrer"&gt;Text&lt;/a&gt; &lt;a href="https://github.com/benmatselby/sublime-phpdocumentor" rel="noopener noreferrer"&gt;plugins&lt;/a&gt; &lt;a href="https://github.com/benmatselby/sublime-pman" rel="noopener noreferrer"&gt;back in the day&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the last few months, I’ve set up my VSCode environment on my work machine. Last night I was wanting to do something on a different machine. I could not remember how to debug Python code inside a virtual environment within VSCode!&lt;/p&gt;

&lt;p&gt;I kept getting this error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;has&lt;/span&gt; &lt;span class="n"&gt;occurred&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;ModuleNotFoundError&lt;/span&gt;
&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;named&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;django&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error could have been a different module, but for me, it was &lt;code&gt;django&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I sync all my VSCode settings via my &lt;a href="https://github.com/benmatselby/dotfiles" rel="noopener noreferrer"&gt;dotfiles&lt;/a&gt;, so I could not understand why it worked on my work machine and not my personal one. I did know it was a virtual environment issue though.&lt;/p&gt;

&lt;p&gt;After some digging, I found out you have to pick your default interpreter. In VS Code open the Command Palette (⇧ ⌘ P). Then select “&lt;strong&gt;Python: Select Interpreter&lt;/strong&gt;".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fud5ksk1xysgstmhu44ic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fud5ksk1xysgstmhu44ic.png" alt="Python: Select Interpreter" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will produce a list of Python installations that you can pick from.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hux9qf5133ombcd0nyi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hux9qf5133ombcd0nyi.jpg" alt="Python: Interpreter List" width="800" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pick your local virtual environment Python interpreter. For me, this is the one that has a star next to it.&lt;/p&gt;

&lt;p&gt;This then allows you to use your debug configuration. For completeness, mine was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IntelliSense&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;learn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;about&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;possible&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;attributes.&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Hover&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;view&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;descriptions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;existing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;attributes.&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;information&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;visit:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://go.microsoft.com/fwlink/?linkid=&lt;/span&gt;&lt;span class="mi"&gt;830387&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"configurations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Python: Shell plus"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"launch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"program"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"${workspaceFolder}/manage.py"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"shell_plus"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"DOMAIN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost:8888"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"CLIENT_DOMAIN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"localhost:8080"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"DYLD_FALLBACK_LIBRARY_PATH"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/opt/homebrew/lib/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"django"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"justMyCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Hopefully, I will remember this next time, or at least know I've written it up here.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@supergios?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Jonny Gios&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/lake-district?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>python</category>
      <category>debug</category>
    </item>
    <item>
      <title>Mongo shell commands to get you through the day</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Sun, 01 May 2022 16:39:12 +0000</pubDate>
      <link>https://dev.to/benmatselby/mongo-shell-commands-to-get-you-through-the-day-56n0</link>
      <guid>https://dev.to/benmatselby/mongo-shell-commands-to-get-you-through-the-day-56n0</guid>
      <description>&lt;p&gt;I recently started a new job. The data store is &lt;a href="https://www.mongodb.com" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt;, which I have barely used before. This post aims to document what I've learnt to get me through the day. Please feel free to &lt;a href="http://twitter.com/benmatselby" rel="noopener noreferrer"&gt;tweet me&lt;/a&gt; if there are discrepancies.&lt;/p&gt;

&lt;p&gt;The first thing that I became aware of, is that there are/were two cli tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The legacy &lt;code&gt;mongo&lt;/code&gt; shell, which &lt;a href="https://www.mongodb.com/docs/manual/reference/program/mongo/" rel="noopener noreferrer"&gt;was deprecated in MongoDB v5.0&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The new, and active, &lt;code&gt;mongosh&lt;/code&gt; shell, which replaced &lt;code&gt;mongo&lt;/code&gt;. The documentation for this shell is &lt;a href="https://www.mongodb.com/docs/mongodb-shell/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post will discuss &lt;code&gt;mongosh&lt;/code&gt; and assume you have MongoDB running on your machine (or access to an instance).&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting
&lt;/h2&gt;

&lt;p&gt;If you're wanting to connect to a local database instance, then by running &lt;code&gt;mongosh&lt;/code&gt; it will connect to &lt;code&gt;localhost&lt;/code&gt; as default.&lt;/p&gt;

&lt;p&gt;A more complete connection string would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="s2"&gt;"mongodb://localhost:27017"&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;user]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will prompt for the password, so it's not stored in your &lt;code&gt;~/.[zsh|bash]_history&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Once you have connected, you can run &lt;code&gt;help&lt;/code&gt; to get some basic commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;help

  &lt;/span&gt;Shell Help:

    use                Set current database
    show               &lt;span class="s1"&gt;'show databases'&lt;/span&gt;/&lt;span class="s1"&gt;'show dbs'&lt;/span&gt;: Print a list of all available databases.
                       &lt;span class="s1"&gt;'show collections'&lt;/span&gt;/&lt;span class="s1"&gt;'show tables'&lt;/span&gt;: Print a list of all collections &lt;span class="k"&gt;for &lt;/span&gt;current database.
                       &lt;span class="s1"&gt;'show profile'&lt;/span&gt;: Prints system.profile information.
                       &lt;span class="s1"&gt;'show users'&lt;/span&gt;: Print a list of all &lt;span class="nb"&gt;users &lt;/span&gt;&lt;span class="k"&gt;for &lt;/span&gt;current database.
                       &lt;span class="s1"&gt;'show roles'&lt;/span&gt;: Print a list of all roles &lt;span class="k"&gt;for &lt;/span&gt;current database.
                       &lt;span class="s1"&gt;'show log &amp;lt;type&amp;gt;'&lt;/span&gt;: log &lt;span class="k"&gt;for &lt;/span&gt;current connection, &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;type &lt;/span&gt;is not &lt;span class="nb"&gt;set &lt;/span&gt;uses &lt;span class="s1"&gt;'global'&lt;/span&gt;
                       &lt;span class="s1"&gt;'show logs'&lt;/span&gt;: Print all logs.

    &lt;span class="nb"&gt;exit               &lt;/span&gt;Quit the MongoDB shell with &lt;span class="nb"&gt;exit&lt;/span&gt;/exit&lt;span class="o"&gt;()&lt;/span&gt;/.exit
    quit               Quit the MongoDB shell with quit/quit&lt;span class="o"&gt;()&lt;/span&gt;
    Mongo              Create a new connection and &lt;span class="k"&gt;return &lt;/span&gt;the Mongo object. Usage: new Mongo&lt;span class="o"&gt;(&lt;/span&gt;URI, options &lt;span class="o"&gt;[&lt;/span&gt;optional]&lt;span class="o"&gt;)&lt;/span&gt;
    connect            Create a new connection and &lt;span class="k"&gt;return &lt;/span&gt;the Database object. Usage: connect&lt;span class="o"&gt;(&lt;/span&gt;URI, username &lt;span class="o"&gt;[&lt;/span&gt;optional], password &lt;span class="o"&gt;[&lt;/span&gt;optional]&lt;span class="o"&gt;)&lt;/span&gt;
    it                 result of the last line evaluated&lt;span class="p"&gt;;&lt;/span&gt; use to further iterate
    version            Shell version
    load               Loads and runs a JavaScript file into the current shell environment
    enableTelemetry    Enables collection of anonymous usage data to improve the mongosh CLI
    disableTelemetry   Disables collection of anonymous usage data to improve the mongosh CLI
    passwordPrompt     Prompts the user &lt;span class="k"&gt;for &lt;/span&gt;a password
    &lt;span class="nb"&gt;sleep              &lt;/span&gt;Sleep &lt;span class="k"&gt;for &lt;/span&gt;the specified number of milliseconds
    print              Prints the contents of an object to the output
    printjson          Alias &lt;span class="k"&gt;for &lt;/span&gt;print&lt;span class="o"&gt;()&lt;/span&gt;
    cls                Clears the screen like console.clear&lt;span class="o"&gt;()&lt;/span&gt;
    isInteractive      Returns whether the shell will enter or has entered interactive mode

  For more information on usage: https://docs.mongodb.com/manual/reference/method
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Listing the databases
&lt;/h2&gt;

&lt;p&gt;Using the output from &lt;code&gt;help&lt;/code&gt;, let's list all the databases stored in the instance we are running on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; show dbs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to be able to switch between the databases, so lets switch to the &lt;code&gt;admin&lt;/code&gt; database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; use admin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a database
&lt;/h2&gt;

&lt;p&gt;So we have seen how to list databases, but we want to create a new one to store our data. To do this, we can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; use entertainment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may notice that we are using the same &lt;code&gt;use&lt;/code&gt; command. By switching to a non-existent database, the database will be created, when we create a collection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deleting a database
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; I &lt;strong&gt;do not&lt;/strong&gt; recommend testing this on production!&lt;/p&gt;

&lt;p&gt;Make sure you are on the database you want to drop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; use entertainment
switched to db entertainment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then let's drop the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.dropDatabase&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; ok: 1, dropped: &lt;span class="s1"&gt;'entertainment'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Creating a collection
&lt;/h2&gt;

&lt;p&gt;Using the commands from above, create a database called &lt;code&gt;entertainment&lt;/code&gt; again. Then switch to that database. We now want to create a collection. Let's just make sure we are on the same page again. Let's check the name of the database we are both on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.getName&lt;span class="o"&gt;()&lt;/span&gt;
entertainment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your output should match mine, &lt;code&gt;entertainment&lt;/code&gt;. Now, let's create a collection called &lt;code&gt;films&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.createCollection&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"films"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For further options/configuration on creating collections, please review &lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.createCollection/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showing collections
&lt;/h2&gt;

&lt;p&gt;Let's see what collections we have in the &lt;code&gt;entertainment&lt;/code&gt; database.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If you're coming from a SQL based background, &lt;code&gt;collections&lt;/code&gt; are the MongoDB equivalent of &lt;code&gt;tables&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; show collections
films
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inserting documents
&lt;/h2&gt;

&lt;p&gt;Now we have a database (&lt;code&gt;entertainment&lt;/code&gt;), and a collection (&lt;code&gt;films&lt;/code&gt;), let's create some documents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.insertOne&lt;span class="o"&gt;({&lt;/span&gt; title: &lt;span class="s2"&gt;"The Big Lebowski"&lt;/span&gt;, url: &lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/The_Big_Lebowski"&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedId: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaad80dd6e8884b86fda3"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This has created a document in the &lt;code&gt;films&lt;/code&gt; collection with two attributes: &lt;code&gt;title&lt;/code&gt;, and &lt;code&gt;url&lt;/code&gt;. Behind the scenes, MongoDB will add an additional attribute: &lt;code&gt;_id&lt;/code&gt; which cannot be changed.&lt;/p&gt;

&lt;p&gt;You can also create many documents at the same time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.insertMany&lt;span class="o"&gt;([{&lt;/span&gt; title: &lt;span class="s2"&gt;"How to loose a guy in 10 days"&lt;/span&gt;, url: &lt;span class="s2"&gt;"https://en.wikipedia.org/wiki/How_to_Lose_a_Guy_in_10_Days"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;,
&lt;span class="o"&gt;{&lt;/span&gt; title: &lt;span class="s2"&gt;"Father of the Bride"&lt;/span&gt;, url: &lt;span class="s2"&gt;"https://www.imdb.com/title/tt0101862/"&lt;/span&gt; &lt;span class="o"&gt;}])&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedIds: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s1"&gt;'0'&lt;/span&gt;: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda4"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    &lt;span class="s1"&gt;'1'&lt;/span&gt;: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For further options/configuration on inserting documents, please review &lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.collection.insertOne/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting documents
&lt;/h2&gt;

&lt;p&gt;We should now have three documents in our &lt;code&gt;films&lt;/code&gt; collection, within the &lt;code&gt;entertainment&lt;/code&gt; database. Let's check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.find&lt;span class="o"&gt;({})&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaad80dd6e8884b86fda3"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'The Big Lebowski'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://en.wikipedia.org/wiki/The_Big_Lebowski'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda4"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'How to loose a guy in 10 days'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://en.wikipedia.org/wiki/How_to_Lose_a_Guy_in_10_Days'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'Father of the Bride'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://www.imdb.com/title/tt0101862/'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Filtering documents
&lt;/h2&gt;

&lt;p&gt;It's unlikely that we always want to get all of the documents, so let's filter films with the word &lt;code&gt;the&lt;/code&gt; in them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.find&lt;span class="o"&gt;({&lt;/span&gt; title: &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$regex&lt;/span&gt;: /the/i &lt;span class="o"&gt;}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see we have introduced a &lt;code&gt;$regex&lt;/code&gt; keyword to provide a &lt;code&gt;SQL LIKE&lt;/code&gt; command, if you're use to SQL.&lt;/p&gt;

&lt;p&gt;If you know the id of the document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.find&lt;span class="o"&gt;({&lt;/span&gt; _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'Father of the Bride'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://www.imdb.com/title/tt0101862/'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that we are returning an array of documents. But what if we just want the one document?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.findOne&lt;span class="o"&gt;({&lt;/span&gt; _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;})&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
  title: &lt;span class="s1"&gt;'Father of the Bride'&lt;/span&gt;,
  url: &lt;span class="s1"&gt;'https://www.imdb.com/title/tt0101862/'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For further options/configuration on finding documents, please review &lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.collection.findOne/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Updating documents
&lt;/h2&gt;

&lt;p&gt;Let's say we want to give a film a rating. We can do this via an update.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;db.films.updateOne&lt;span class="o"&gt;({&lt;/span&gt; title: &lt;span class="s2"&gt;"The Big Lebowski"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;, &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$set&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt; rating: 5 &lt;span class="o"&gt;}})&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;,
  insertedId: null,
  matchedCount: 1,
  modifiedCount: 1,
  upsertedCount: 0
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The benefit of a NoSQL data store is the fact that documents can have varying fields. Let's checkout what the documents look like now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.find&lt;span class="o"&gt;({})&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaad80dd6e8884b86fda3"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'The Big Lebowski'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://en.wikipedia.org/wiki/The_Big_Lebowski'&lt;/span&gt;,
    rating: 5
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda4"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'How to loose a guy in 10 days'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://en.wikipedia.org/wiki/How_to_Lose_a_Guy_in_10_Days'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="o"&gt;{&lt;/span&gt;
    _id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;,
    title: &lt;span class="s1"&gt;'Father of the Bride'&lt;/span&gt;,
    url: &lt;span class="s1"&gt;'https://www.imdb.com/title/tt0101862/'&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that only one film document has a &lt;code&gt;rating&lt;/code&gt; field.&lt;/p&gt;

&lt;p&gt;For further options/configuration on updating documents, please review &lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.collection.updateOne/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deleting documents
&lt;/h2&gt;

&lt;p&gt;Deleting documents is very much akin to finding documents. So let's say we want to delete one document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; db.films.deleteOne&lt;span class="o"&gt;({&lt;/span&gt;_id: ObjectId&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"626eaae00dd6e8884b86fda5"&lt;/span&gt;&lt;span class="o"&gt;)})&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; acknowledged: &lt;span class="nb"&gt;true&lt;/span&gt;, deletedCount: 1 &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For further options/configuration on deleting documents, please review &lt;a href="https://www.mongodb.com/docs/manual/reference/method/db.collection.deleteOne/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration file
&lt;/h2&gt;

&lt;p&gt;We can create a configuration file called &lt;code&gt;~/.mongoshrc.js&lt;/code&gt; to customise the prompt. An example could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getName&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt; with &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; documents&amp;gt; `&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you save this file, and then reconnect you should see your prompt as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;entertainment with 2 documents&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For further information on the configuration file, please review &lt;a href="https://www.mongodb.com/docs/mongodb-shell/mongoshrc/" rel="noopener noreferrer"&gt;the docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tidbits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mongosh&lt;/code&gt; has tab completion, which really helps discoverability of commands. If you run &lt;code&gt;db.[tab][tab]&lt;/code&gt; you will see a list of commands on the &lt;code&gt;db&lt;/code&gt; object. Likewise, if you do &lt;code&gt;db.films.[tab][tab]&lt;/code&gt; you will see a list of commands on the &lt;code&gt;collections&lt;/code&gt; object.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I hope this provides some useful knowledge to get you through your day using MongoDB. It should provide a grounding of basic commands, and provide links to give you further reading for more advanced commands/options.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@alfonsmc10?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Alfons Morales&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/git-101/" rel="noopener noreferrer"&gt;Git commands to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/docker-101/" rel="noopener noreferrer"&gt;Docker knowledge to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/shell-101/" rel="noopener noreferrer"&gt;Shell commands to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://benmatselby.dev/post/terraform-101/" rel="noopener noreferrer"&gt;Terraform knowledge to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>mongodb</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Use Docker Context to switch between different solutions</title>
      <dc:creator>Ben Selby</dc:creator>
      <pubDate>Wed, 17 Nov 2021 18:58:17 +0000</pubDate>
      <link>https://dev.to/benmatselby/use-docker-context-to-switch-between-different-solutions-3e0b</link>
      <guid>https://dev.to/benmatselby/use-docker-context-to-switch-between-different-solutions-3e0b</guid>
      <description>&lt;p&gt;You may be on the lookout for a replacement to Docker Desktop &lt;a href="https://www.docker.com/blog/roi-of-docker-desktop-vs-diy-considerations-risks-and-benefits-for-business/" rel="noopener noreferrer"&gt;at the moment&lt;/a&gt;. If you are, you may be wanting to trial the different solutions. You're going to need to know what is involved, and what the different cost models include. This post is going to show you how you can use &lt;code&gt;docker context&lt;/code&gt; to run the different systems in parallel. The two solutions this post will cover are &lt;a href="https://minikube.sigs.k8s.io/docs/start/" rel="noopener noreferrer"&gt;minikube&lt;/a&gt; and &lt;a href="https://multipass.run" rel="noopener noreferrer"&gt;multipass&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting minikube up and running
&lt;/h2&gt;

&lt;p&gt;This post assumes the host machine is a Mac. Therefore, we can use &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;brew.sh&lt;/a&gt; to install the necessary packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;hyperkit
brew &lt;span class="nb"&gt;install &lt;/span&gt;minikube
brew &lt;span class="nb"&gt;install &lt;/span&gt;docker
brew &lt;span class="nb"&gt;install &lt;/span&gt;docker-compose
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once this is complete, you can start the &lt;code&gt;minikube&lt;/code&gt; application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube start &lt;span class="nt"&gt;--driver&lt;/span&gt; hyperkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will now be running a Virtual Machine we can use for Docker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting multipass up and running
&lt;/h2&gt;

&lt;p&gt;Let's use &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;brew.sh&lt;/a&gt; again to install the necessary packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;multipass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multipass allows us to use &lt;a href="https://cloudinit.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;cloud-init&lt;/a&gt; to define a the environment we can use. This will configure the virtual machine for you. The definition I use is defined below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu&lt;/span&gt;
    &lt;span class="na"&gt;sudo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ALL=(ALL) NOPASSWD:ALL&lt;/span&gt;
    &lt;span class="na"&gt;ssh-authorized-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ssh-rsa .....&lt;/span&gt;
&lt;span class="na"&gt;package_update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;packages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;apt-transport-https&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;avahi-daemon&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;ca-certificates&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;curl&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;gnupg&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;lsb-release&lt;/span&gt;
&lt;span class="na"&gt;runcmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo curl -fsSL https://get.docker.com | sudo bash&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo systemctl enable docker&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo systemctl enable -s HUP ssh&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo groupadd docker&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sudo usermod -aG docker ubuntu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is saved to &lt;code&gt;$HOME/git/github/benmatselby/dotfiles/common/multipass-docker.yml&lt;/code&gt;. You can save this file where you want. Add the contents of your &lt;code&gt;~/.ssh/id_rsa.pub&lt;/code&gt; file to the &lt;code&gt;ssh-authorized-keys&lt;/code&gt; array above. This allows your host machine to &lt;code&gt;ssh&lt;/code&gt; into the virtual machine multipass will create.&lt;/p&gt;

&lt;p&gt;Now we want to spin up the multipass environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$HOME&lt;/span&gt;/git/github/benmatselby/dotfiles/common/
multipass launch &lt;span class="nt"&gt;-c&lt;/span&gt; 2 &lt;span class="nt"&gt;-m&lt;/span&gt; 2G &lt;span class="nt"&gt;-d&lt;/span&gt; 10G &lt;span class="nt"&gt;-n&lt;/span&gt; docker-multipass 20.04 &lt;span class="nt"&gt;--cloud-init&lt;/span&gt; multipass-docker.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you &lt;code&gt;cd&lt;/code&gt; into the directory where you saved the &lt;code&gt;cloud-init&lt;/code&gt; script. This command will launch a virtual machine using Ubuntu 20.04, with 10GB of disk space (&lt;code&gt;-d&lt;/code&gt;), 2GB of RAM (&lt;code&gt;-m&lt;/code&gt;), 2 CPUs (&lt;code&gt;-c&lt;/code&gt;), and named &lt;code&gt;docker-multipass&lt;/code&gt;. You can change the values as you see fit. You will need the name of the instance for later.&lt;/p&gt;

&lt;p&gt;You may also want to mount some local folders to make life a little easier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;multipass mount /Users docker-multipass
multipass mount /Volumes docker-multipass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see the information about the VM you created by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;multipass info docker-multipass
Name:           docker-multipass
State:          Running
IPv4:           192.168.64.5
                172.17.0.1
Release:        Ubuntu 20.04.3 LTS
Image &lt;span class="nb"&gt;hash&lt;/span&gt;:     a83b747df657 &lt;span class="o"&gt;(&lt;/span&gt;Ubuntu 20.04 LTS&lt;span class="o"&gt;)&lt;/span&gt;
Load:           0.19 0.14 0.05
Disk usage:     1.8G out of 9.5G
Memory usage:   232.8M out of 1.9G
Mounts:         /Volumes &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /Volumes
                    UID map: 501:default
                    GID map: 20:default
                /Users   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; /Users
                    UID map: 501:default
                    GID map: 20:default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using docker context
&lt;/h2&gt;

&lt;p&gt;We now have two environments that can be used instead of Docker Desktop: &lt;code&gt;minikube&lt;/code&gt; and &lt;code&gt;multipass&lt;/code&gt;. The best way to switch between the two systems is to use &lt;code&gt;docker context&lt;/code&gt;. Let's now create a context for multipass, and set it as the default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context create multipass &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Multipass Docker Desktop"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"host=ssh://ubuntu@docker-multipass.local"&lt;/span&gt;
docker context use multipass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The name provided in the &lt;code&gt;multipass launch&lt;/code&gt; command, is what becomes the &lt;code&gt;ubuntu@[multipass name].local&lt;/code&gt; value. So if you named your multipass instance "lebowski" you would use &lt;code&gt;host=ssh://ubuntu@lebowski.local&lt;/code&gt; as your &lt;code&gt;--docker&lt;/code&gt; context. I used &lt;code&gt;docker-multipass&lt;/code&gt; in the examples above.&lt;/p&gt;

&lt;p&gt;The last thing we need to do is &lt;code&gt;ssh&lt;/code&gt; into into the VM so we can accept the authenticity of the host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh ubuntu@docker-multipass.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now leave the VM, &lt;code&gt;exit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now run &lt;code&gt;docker run hello-world&lt;/code&gt;. This will run the &lt;code&gt;hello-world&lt;/code&gt; container via &lt;code&gt;multipass&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can see what contexts you have by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker context &lt;span class="nb"&gt;ls
&lt;/span&gt;NAME            DESCRIPTION                               DOCKER ENDPOINT
default         Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
desktop-linux                                             unix:///Users/Ben/.docker/run/docker.sock
multipass &lt;span class="k"&gt;*&lt;/span&gt;     Multipass Docker Desktop                  ssh://ubuntu@docker-multipass.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's now add the &lt;code&gt;minikube&lt;/code&gt; context. First, we need some data from minikube to build the context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube &lt;span class="nt"&gt;-p&lt;/span&gt; minikube docker-env
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_TLS_VERIFY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_HOST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"tcp://192.168.64.10:2376"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DOCKER_CERT_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/Users/Ben/.minikube/certs"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MINIKUBE_ACTIVE_DOCKERD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"minikube"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need this information for the context connection string. Let's run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context create minikube &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"Minikube Docker Desktop"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--docker&lt;/span&gt; &lt;span class="s2"&gt;"host=tcp://192.168.64.10:2376,cert=/Users/Ben/.minikube/certs/cert.pem,ca=/Users/Ben/.minikube/certs/ca.pem,key=/Users/Ben/.minikube/certs/key.pem"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see how we have built up the &lt;code&gt;--docker&lt;/code&gt; string by using the environment variables provided by the &lt;code&gt;minikube&lt;/code&gt; command. Let's now check the contexts we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context &lt;span class="nb"&gt;ls
&lt;/span&gt;NAME            DESCRIPTION                               DOCKER ENDPOINT
default         Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
desktop-linux                                             unix:///Users/Ben/.docker/run/docker.soc
minikube        Minikube Docker Desktop                   tcp://192.168.64.10:2376
multipass &lt;span class="k"&gt;*&lt;/span&gt;     Multipass Docker Desktop                  ssh://ubuntu@docker.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then use &lt;code&gt;docker context use [name]&lt;/code&gt; to switch between the contexts. Let's switch to &lt;code&gt;minikube&lt;/code&gt; and run &lt;code&gt;hello-world&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker context use minikube
docker run hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have now run the &lt;code&gt;hello-world&lt;/code&gt; container using both docker contexts.&lt;/p&gt;

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

&lt;p&gt;Docker Desktop is an easy to use system for the Mac. For personal projects, it is great. With the new licensing agreement, businesses may need to review how their engineers run containers during development. This post showed how you can use &lt;code&gt;docker context&lt;/code&gt; to switch between different back ends to help trial alternatives to Docker Desktop.&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@alschim?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Alexander Schimmeck&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/choice?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  See also
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/benmatselby/docker-knowledge-to-get-you-through-the-day-47bl"&gt;Docker knowledge to get you through the day&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/benmatselby/setting-up-a-vs-code-dev-container-minikube-549a"&gt;Setting up a VS Code Dev Container - Minikube&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
    </item>
  </channel>
</rss>
