<?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: Rudolf Olah</title>
    <description>The latest articles on DEV Community by Rudolf Olah (@rudolfolah).</description>
    <link>https://dev.to/rudolfolah</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%2F178172%2F90fec551-5bd0-458d-9169-95867e4f9cc8.jpeg</url>
      <title>DEV Community: Rudolf Olah</title>
      <link>https://dev.to/rudolfolah</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rudolfolah"/>
    <language>en</language>
    <item>
      <title>Engineering Management Tools: My Top Picks</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Sun, 01 Mar 2026 14:35:00 +0000</pubDate>
      <link>https://dev.to/rudolfolah/engineering-management-tools-my-top-picks-1hbh</link>
      <guid>https://dev.to/rudolfolah/engineering-management-tools-my-top-picks-1hbh</guid>
      <description>&lt;p&gt;Engineering managers have a different workflow than ICs (individual contributors), and though we often use the same tools, their layout and integration into our workflow are different.&lt;/p&gt;

&lt;h1&gt;
  
  
  Calendar: Google
&lt;/h1&gt;

&lt;p&gt;The most essential tool is the calendar, and &lt;a href="https://calendar.google.com/" rel="noopener noreferrer"&gt;Google Calendar&lt;/a&gt; is great. As a manager, creating recurring events such as daily standups or bi-weekly sprint planning meetings is standard.&lt;/p&gt;

&lt;p&gt;Creating and subscribing to multiple calendars is a good feature. Depending on the number of projects and teams, creating a separate calendar for recurring events can make sense. Many organizations have a separate calendar for engineering department meetings and presentations. &lt;em&gt;Any meetings affecting multiple departments or teams within a department could be on a shared calendar. Office hours are another candidate for a shared calendar across the organization.&lt;/em&gt; Multiple shared calendars are useful in keeping the main calendar manageable.&lt;/p&gt;

&lt;p&gt;For ICs, setting up “focus time” in the calendar is a good way to let engineering managers know when they can schedule meetings to avoid interrupting focused work time. Subscribing to multiple calendars is also great for keeping track of holidays and out-of-office time, which can affect capacity planning and on-call schedules.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tasks, to-dos: Todoist, Google Tasks
&lt;/h1&gt;

&lt;p&gt;There are many task management and to-do list tools out there. Previously, I used &lt;a href="https://todoist.com/" rel="noopener noreferrer"&gt;Todoist&lt;/a&gt; for task management and tried out a few different tools.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The best to-do list is close to the other tools you use for managing a team.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you live in Google Calendar, then &lt;a href="https://tasks.google.com/" rel="noopener noreferrer"&gt;Google Tasks&lt;/a&gt; is a good choice since it integrates directly into the calendar, and like calendars, you can create multiple to-do lists. You can set tasks to repeat, a good reminder that appears in the calendar without taking up a block of time. &lt;em&gt;Tasks are a good reminder for various preparation work for project planning and roadmapping.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Notes: Notion, Obsidian, Google Docs, Slack
&lt;/h1&gt;

&lt;p&gt;For short-form notes, what I’ve found works best is using whichever tool is available. If I’m in a meeting on Google Meet or looking at the calendar, I can use Google Keep for notes. If I’m in a Slack huddle or see something in a channel or thread that I want to write a note about, I use the “Direct Message to self” feature of Slack as a note-to-self. I use &lt;a href="https://www.notion.so/" rel="noopener noreferrer"&gt;Notion&lt;/a&gt; or &lt;a href="https://obsidian.md/" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt; for long-form notes or for turning short notes into long-form ones. &lt;em&gt;Writing notes and creating links between them is very useful. The links between notes make it easy to refer to past notes about meetings or additional notes about documents.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of my workflows involves using Slack and Notion. I use Slack for a summary that can be copied/pasted to various channels and threads and Notion for a longer-form note with more details that I rewrite later for different formats (e.g., a technical spec, engineering brief, a company-wide presentation, or during a 1:1). The same applies to Teams, Google Docs, or other tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Obsidian Plugins
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://obsidian.md/plugins" rel="noopener noreferrer"&gt;There are many plugins for Obsidian&lt;/a&gt; to help you with note-taking and creating a knowledge base:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/delashum/obsidian-checklist-plugin" rel="noopener noreferrer"&gt;Checklist&lt;/a&gt;: This plugin gathers all checklists, to-do lists, and tasks across all pages and puts them in the sidebar. It makes it easy to create checklists in daily notes and keep track of which ones are completed later.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/lynchjames/note-refactor-obsidian" rel="noopener noreferrer"&gt;Note Refactor&lt;/a&gt;: This plugin enables you to select text and extract it into a new page. Do you have a long page with many notes about different topics written while you were in the flow? That’s no problem; you can branch out into new pages with the Note Refactor plugin.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/liamcain/obsidian-periodic-notes" rel="noopener noreferrer"&gt;Periodic Notes&lt;/a&gt;: This plugin will create weekly, monthly, quarterly and yearly notes for you at the click of a button. This makes it easy to summarize your week or month. As an engineering manager, I found that a monthly list of what the team got done last month and what was upcoming was great for communicating the value the team was delivering. The quarterly notes can tie into organizational goals.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://florianwoelki.github.io/obsidian-iconize/" rel="noopener noreferrer"&gt;Iconize&lt;/a&gt;: add icons to files and folders; this plugin is good for highlighting very important pages with a visual cue.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  1:1s and Career Goals: Lattice
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://lattice.com/" rel="noopener noreferrer"&gt;Lattice&lt;/a&gt; is incredible for this. The software formalizes what’s usually in spreadsheets or in document templates. For 1:1s, I encourage ICs to add topics; it’s a checklist to ensure we cover each topic. There’s also a checklist of “action items” for the IC and myself to ensure we follow up with concrete actions based on our conversations. Another great feature is the career track and career goals. The org can set up the templates for the career track, and I can work with an IC to turn those into specific goals. &lt;em&gt;Lattice makes it far easier to collaborate with an IC on their goals and to ensure there’s accountability from myself and the IC on accomplishing things that not only move the company or projects forward, they move the IC forward in their career.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Diagrams: Lucidchart, Drawio
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.lucidchart.com/pages/" rel="noopener noreferrer"&gt;Lucidchart&lt;/a&gt; and &lt;a href="https://www.drawio.com/" rel="noopener noreferrer"&gt;Drawio&lt;/a&gt; are great diagramming tools. Lucidchart has many great templates to use as starting points, such as user journeys, use case diagrams, sprint retrospectives, roadmaps, and cloud architecture diagrams. Drawio also contains many great templates and can be downloaded locally. I primarily use Drawio for engineering architecture diagrams.&lt;/p&gt;

&lt;p&gt;Both Lucidchart and Drawio can be used for quickly sketching out diagrams. The user interfaces are well-designed. &lt;em&gt;Lucidchart has a good collaboration mode, where you can share a diagram and build it out with your team.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  SQL Database and Codebase Tools: JetBrains
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.jetbrains.com/" rel="noopener noreferrer"&gt;JetBrains&lt;/a&gt; suite for professionals — from &lt;a href="https://www.jetbrains.com/idea/" rel="noopener noreferrer"&gt;IntelliJ IDEA&lt;/a&gt; to &lt;a href="https://www.jetbrains.com/pycharm/" rel="noopener noreferrer"&gt;PyCharm&lt;/a&gt; to &lt;a href="https://www.jetbrains.com/datagrip/" rel="noopener noreferrer"&gt;https://www.jetbrains.com/datagrip/&lt;/a&gt;, each tool makes it easy for engineering managers to explore and understand a code base, data models, and database schema.&lt;/p&gt;

&lt;p&gt;I use IntelliJ IDEA to get up to speed on a codebase by searching the code or clicking through to see the usage and definitions of methods and classes. The integrated debugger works great for Python and Ruby codebases, and the autocomplete and code navigation for TypeScript codebases are fantastic.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The database tools in JetBrains IDEs allow you to connect to various data sources, from DynamoDB to PostgreSQL to ClickHouse to Redis and SQLite. The tool lets you run queries and edit records and rows within the editor, which is good for checking data and modifying it during testing. It’s also possible to sort, filter, and search the data locally and to compare data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While there are other database tools, having an integrated database viewer in your IDE that sits beside the code that creates and updates that data is very useful.&lt;/p&gt;

&lt;h1&gt;
  
  
  Password Management: 1Password, Bitwarden
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://1password.com/" rel="noopener noreferrer"&gt;1Password&lt;/a&gt; and &lt;a href="https://bitwarden.com/" rel="noopener noreferrer"&gt;Bitwarden&lt;/a&gt; are solid choices for password management. Both feature vaults that can be shared with team members and across departments. &lt;em&gt;They both feature Single Sign On, which enables your IT department to control access to the vaults.&lt;/em&gt; Bitwarden is also open source, with the core code licensed under the GPL.&lt;/p&gt;

&lt;p&gt;For software engineers, IT, and DevOps, the CLI, and APIs offered by 1Password and Bitwarden allow for the automation of secrets management and vault management.&lt;/p&gt;

</description>
      <category>management</category>
      <category>leadership</category>
    </item>
    <item>
      <title>Learning Coding from High Skilled Professional Programmers</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Sat, 06 Sep 2025 14:29:54 +0000</pubDate>
      <link>https://dev.to/rudolfolah/learning-coding-from-high-skilled-professional-programmers-28cj</link>
      <guid>https://dev.to/rudolfolah/learning-coding-from-high-skilled-professional-programmers-28cj</guid>
      <description>&lt;p&gt;So, to be a prolific programmer, what does it take? In the past, we would have to sit beside the programmer or have them describe their workflow to us. With streaming platforms, we can observe how software engineers approach problem-solving and learn from their approaches, which can help improve our own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live Stream Programming
&lt;/h2&gt;

&lt;p&gt;I was watching a few videos from &lt;a href="https://www.youtube.com/@geohotarchive/videos?view=0&amp;amp;sort=dd&amp;amp;shelf_id=2" rel="noopener noreferrer"&gt;the George Hotz streaming archives on YouTube&lt;/a&gt;. George Hotz, more popularly known as geohot, is a prolific programmer who has jailbroken the iPhone and PlayStation 3, built open source semi-autonomous car software, and, more recently, founded a machine learning startup. What's interesting is his approach to tackling challenges, such as building a neural net chess engine.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/RFaFmkCEGEs"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding Questions
&lt;/h2&gt;

&lt;p&gt;Another interesting selection to watch is from &lt;a href="https://www.youtube.com/c/neetcode" rel="noopener noreferrer"&gt;Neetcode, videos that walk through solutions to LeetCode problems&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, in one video, it begins with a review of the question, followed by a diagram to map out the inputs and steps to achieve the expected output, and then the coding is presented.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/fei4bJQdBUQ"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;No matter the question, this is the overall process for coding interviews. Where it gets interesting is the code implementation. As it's walked through, take note of where there's a pause and where the solution is checked and stepped through. The debugger can help step through code.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Pair Programming
&lt;/h2&gt;

&lt;p&gt;Gene Kim paired with Steve Yegge, an incredible engineer and writer, on chat-oriented programming, basically AI pair programming. &lt;a href="https://steve-yegge.medium.com/" rel="noopener noreferrer"&gt;You can find Yegge's writings from 2005 to the present, and they're all good stuff&lt;/a&gt;. Within many essays, there are a few lines that can have a significant impact on how you write code and approach problem-solving. &lt;a href="https://sites.google.com/site/steveyegge2/innovation-101" rel="noopener noreferrer"&gt;In Yegge's essay "Innovation 101," for example, there's a section on why he writes essays&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The video walkthrough effectively demonstrates the process Yegge uses to work with an AI copilot and how knowledge transfer and training occur.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/jpzv-_YQf6k"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source History Class
&lt;/h2&gt;

&lt;p&gt;There is a wealth of open source code out there to learn from. There are even two great books that discuss the architecture, system design, and code for various open-source projects. However, this focuses on the code at a certain point in time.&lt;/p&gt;

&lt;p&gt;An interesting way to learn is to attend history class. By going through the past commits in a project, you can see how the code got into its current shape.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/simonw/llm" rel="noopener noreferrer"&gt;&lt;code&gt;llm&lt;/code&gt; command line tool&lt;/a&gt; provides an instructive example. The code for &lt;code&gt;llm&lt;/code&gt; is written in Python and &lt;a href="https://github.com/simonw/llm/commits/main/?since=2023-04-01&amp;amp;until=2023-04-01" rel="noopener noreferrer"&gt;began with prototyping, with the first commits made on April 1st, 2023&lt;/a&gt;. &lt;a href="https://github.com/simonw/llm/commit/3f89cb9609ee504654692faab4b404427454d1ff" rel="noopener noreferrer"&gt;The first commit sets up a GitHub Action workflow to test and publish the Python package; it also has one command.&lt;/a&gt; From the start, it's possible to use the tool, test it and publish a package to distribute it more widely.&lt;/p&gt;

&lt;p&gt;The initial design of &lt;code&gt;llm&lt;/code&gt; is documented through the open GitHub issues. One of the issues opened was "command for browsing captured logs", and it contains a few ideas on implementation. The expectation is revised and then closed out with a pull request. What's interesting is that this is still the initial part of the journey to building a new command-line tool. The issues are used as documentation and then quickly closed out with an implementation.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/QUXQNi6jQ30"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Let's think about the alternatives to this. If we start a project and create a comprehensive list of tasks using issues, we may reconsider our approach and close many of the issues. What about beginning with no issues listed and only documenting through pull requests? This approach can work; however, the design will already be in place, and we may not see the complete set of techniques that have been tried. By opening issues that are going to be worked on soon (within a day or within a week) and commenting on them, a trail of code and design breadcrumbs is created, along with a place to document the various approaches tried. Commenting on the design and leaving notes for yourself (and your team) about considerations that changed the design helps you in the future when looking back at how and why the implementation is the way it is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Books and Courses
&lt;/h2&gt;

&lt;p&gt;Books and video courses from highly skilled engineers are worthwhile to read and watch, because they can contain insights on how to improve the effectiveness of your problem solving skills.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.informit.com/imprint/series_detail.aspx?ser=3511331" rel="noopener noreferrer"&gt;Zed Shaw has written a few books on learning to program in Ruby, Python, and C&lt;/a&gt;, plus video courses on those.  In &lt;a href="http://learnrubythehardway.org/book/ex7.html" rel="noopener noreferrer"&gt;"Learn Ruby the Hard Way", exercise 7&lt;/a&gt; has a set of study drills: write a comment for each line of code, read it out loud to find errors, keep track of any mistakes you've made in the code, try to avoid repeating the mistakes in the next exercise. This is valuable advice and can help clarify your understanding of the code base and when reading through merge requests and other people's code. Many books and video courses contain these valuable productivity tips and insights about the author's workflow but you may need to dig through to find them.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Your Software Engineer Coworkers
&lt;/h2&gt;

&lt;p&gt;In the above, I've covered the ways you can learn from great developers who develop in open source or stream their coding sessions. You can apply some of that to learning from your coworkers. Read through their code and code commits, read through what they comment on code reviews, and ask them about their workflow. They may utilize many keyboard shortcuts or use specific extensions and plugins for their IDE. When they plan their work out, they may use a TODO comment in the code or a simple list in a notepad or another method. Whatever their strategies, processes and systems thinking they use, you can ask and learn from them.&lt;/p&gt;

</description>
      <category>learning</category>
      <category>productivity</category>
      <category>programming</category>
      <category>resources</category>
    </item>
    <item>
      <title>Debian GNU/Linux in VirtualBox on MacOS M1 to Practice Kubernetes</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Sun, 11 May 2025 16:45:13 +0000</pubDate>
      <link>https://dev.to/rudolfolah/debian-gnulinux-in-virtualbox-on-macos-m1-to-practice-kubernetes-4dad</link>
      <guid>https://dev.to/rudolfolah/debian-gnulinux-in-virtualbox-on-macos-m1-to-practice-kubernetes-4dad</guid>
      <description>&lt;p&gt;When studying for the CKAD (Certified Kubernetes Application Developer) exam, I practiced using the &lt;a href="https://killercoda.com/killer-shell-ckad" rel="noopener noreferrer"&gt;Killer Coda CKAD scenarios&lt;/a&gt; and the &lt;a href="https://killer.sh/ckad" rel="noopener noreferrer"&gt;Killer Shell Exam Simulator&lt;/a&gt;. The exam simulator sets up a remote Linux XFCE desktop environment with a browser and terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/rudolfolah/kubernetes-and-docker-desktop-for-fast-local-development-19c3"&gt;When practicing various Kubernetes commands, I used minikube and colima to set up Kubernetes with Docker&lt;/a&gt;. However, this isn’t the same experience as navigating a desktop with a specific resolution, set of tools, and slightly different keyboard shortcuts. To get the same experience, without being limited to a few exam simulator sessions, I looked into VirtualBox and Vagrant. VirtualBox is a virtualization system, and Apple Silicon chips became supported by VirtualBox in September 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  VirtualBox 7.1
&lt;/h2&gt;

&lt;p&gt;Here are the steps I took to run a Debian desktop environment in VirtualBox:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.virtualbox.org/wiki/Downloads" rel="noopener noreferrer"&gt;Download version 7.1+ of VirtualBox for &lt;code&gt;macOS / Apple Silicon hosts&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cdimage.debian.org/debian-cd/current/arm64/iso-cd/" rel="noopener noreferrer"&gt;Download an ARM64 ISO for the Debian GNU/Linux distribution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Install VirtualBox&lt;/li&gt;
&lt;li&gt;Start VirtualBox&lt;/li&gt;
&lt;li&gt;Drop the Debian &lt;code&gt;.iso&lt;/code&gt; file onto VirtualBox

&lt;ol&gt;
&lt;li&gt;You can “skip the unattended installation”&lt;/li&gt;
&lt;li&gt;Set the hard disk size, base memory, and number of processors&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;Adjust the amount of storage in the settings for the virtual machine&lt;/li&gt;

&lt;li&gt;Go to Settings &amp;gt; Display for the virtual machine and change the “Scale Factor” from 100% to 200% (or larger)&lt;/li&gt;

&lt;li&gt;Go to Settings &amp;gt; Network and change “Attached to” from NAT to Bridged Adapter, the Adapter Type to “Intel PRO/1000 MT Desktop (82540EM),” and the Promiscuous Mode to “Allow All.” &lt;em&gt;The network settings must be fixed if the network mirrors do not work correctly during the installation process.&lt;/em&gt;
&lt;/li&gt;

&lt;li&gt;Start the virtual machine and &lt;a href="https://www.debian.org/releases/stable/arm64/" rel="noopener noreferrer"&gt;follow the usual steps for a Debian installation&lt;/a&gt;
&lt;/li&gt;

&lt;/ol&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%2F4wpvwihacqmknuaqiiqp.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%2F4wpvwihacqmknuaqiiqp.png" alt=" " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Kubernetes, you can install kubectl and minikube via apt-get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management" rel="noopener noreferrer"&gt;https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/#install-using-native-package-management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://minikube.sigs.k8s.io/docs/start/?arch=%2Flinux%2Farm64%2Fstable%2Fdebian+package" rel="noopener noreferrer"&gt;https://minikube.sigs.k8s.io/docs/start/?arch=%2Flinux%2Farm64%2Fstable%2Fdebian+package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# kubectl&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; &lt;span class="s2"&gt;"https://dl.k8s.io/release/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; https://dl.k8s.io/release/stable.txt&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/bin/linux/arm64/kubectl"&lt;/span&gt;
&lt;span class="nb"&gt;chmod &lt;/span&gt;u+x ./kubectl

&lt;span class="c"&gt;# minikube&lt;/span&gt;
curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://github.com/kubernetes/minikube/releases/latest/download/minikube_latest_arm64.deb
&lt;span class="nb"&gt;sudo &lt;/span&gt;dpkg &lt;span class="nt"&gt;-i&lt;/span&gt; minikube_latest_arm64.deb

&lt;span class="c"&gt;# test the installation&lt;/span&gt;
minikube start
kubectl get po &lt;span class="nt"&gt;-A&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may need to unset the following VirtualBox global setting because it could cause issues with spinning up a virtual machine on Apple Silicon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;VBoxManage setextradata global &lt;span class="s2"&gt;"VBoxInternal/Devices/pcbios/0/Config/DebugLevel"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Vagrant
&lt;/h2&gt;

&lt;p&gt;Many of the above steps are manual and can be done through the VirtualBox interface. You can use &lt;a href="https://developer.hashicorp.com/vagrant" rel="noopener noreferrer"&gt;Vagrant&lt;/a&gt; to automate the steps. Vagrant makes it simpler to reproduce a working virtual machine environment.&lt;/p&gt;

&lt;p&gt;Install Vagrant using &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;For the manual steps above to change the storage and network settings, this is how you would automate the configuration with Vagrant:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provider&lt;/span&gt; &lt;span class="s2"&gt;"virtualbox"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customize&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"storagectl"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"VirtIO Controller"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--hostiocache"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"on"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;vb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customize&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"modifyvm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--nictype1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"82540EM"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DNS resolution can be provisioned with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provision&lt;/span&gt; &lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;inline: &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class="no"&gt;SHELL&lt;/span&gt;&lt;span class="sh"&gt;
  echo 'DNS=8.8.8.8' &amp;gt;&amp;gt; /etc/systemd/resolved.conf
  systemctl restart systemd-resolved
&lt;/span&gt;&lt;span class="no"&gt;SHELL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>virtualmachine</category>
      <category>virtualbox</category>
      <category>kubernetes</category>
      <category>docker</category>
    </item>
    <item>
      <title>Task Runners for Projects</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Thu, 26 Dec 2024 18:43:04 +0000</pubDate>
      <link>https://dev.to/rudolfolah/task-runners-for-projects-57gi</link>
      <guid>https://dev.to/rudolfolah/task-runners-for-projects-57gi</guid>
      <description>&lt;p&gt;Many projects need to run arbitrary commands and tasks.&lt;/p&gt;

&lt;p&gt;In some projects, this is done by creating commands within an IDE such as &lt;a href="https://www.jetbrains.com/help/idea/running-applications.html" rel="noopener noreferrer"&gt;JetBrains Intellij&lt;/a&gt; or &lt;a href="https://code.visualstudio.com/docs/editor/tasks" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt; for common tasks such as running tests or building a project.&lt;/p&gt;

&lt;p&gt;JavaScript and TypeScript projects can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gruntjs.com/" rel="noopener noreferrer"&gt;Grunt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gulpjs.com/" rel="noopener noreferrer"&gt;Gulp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.npmjs.com/cli/v8/using-npm/scripts" rel="noopener noreferrer"&gt;package.json &lt;code&gt;scripts&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Depending on familiarity with the tools, the simplest task runners are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shell scripts&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/make/manual/make.html" rel="noopener noreferrer"&gt;Makefiles&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other task runners:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/casey/just" rel="noopener noreferrer"&gt;just&lt;/a&gt;, stores tasks in a file similar to Makefile format, has CLI completion support and loads &lt;code&gt;.env&lt;/code&gt; files&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mise.jdx.dev/getting-started.html" rel="noopener noreferrer"&gt;mise&lt;/a&gt;, task runner that uses TOML files or standalone files&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>makefile</category>
      <category>just</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Keeping Skills Up-to-Date as a Software Developer</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Thu, 19 Sep 2024 02:34:44 +0000</pubDate>
      <link>https://dev.to/rudolfolah/keeping-skills-up-to-date-as-a-software-developer-l69</link>
      <guid>https://dev.to/rudolfolah/keeping-skills-up-to-date-as-a-software-developer-l69</guid>
      <description>&lt;p&gt;Software developers need to stay up-to-date within their specialization and in the general field. If you’re a frontend web dev, you will want to keep up with how frameworks are evolving. If you’re into devops, you’ll need to be up-to-date on the latest build and deploy tools and IaC.&lt;/p&gt;

&lt;p&gt;These are my recommended sites for keeping your skills up to date:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.oreilly.com/online-learning/" rel="noopener noreferrer"&gt;O’Reilly Online Learning&lt;/a&gt;: features many books, audio books, and video courses along with sandboxes for running code.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.linkedin.com/learning" rel="noopener noreferrer"&gt;LinkedIn Learning&lt;/a&gt;: offers a wide range of video courses and is good for a refresher or for getting started quickly with a new tech. It also has business-oriented content if you need to get up to speed on non-coding subjects.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codingchallenges.fyi/" rel="noopener noreferrer"&gt;Coding Challenges&lt;/a&gt; features a list of self-directed challenges that you can code in any programming language. Some of the challenges include building your own Memcached server and building a Docker container. There’s a nice variety of challenges and by working through them you can learn about data structures, algorithms, and the specifics of a programming language, library or framework.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://roadmap.sh/" rel="noopener noreferrer"&gt;roadmap.sh - Developer Roadmaps&lt;/a&gt; gives you direction to learn parts of the tech stacks for different positions in the field. They also feature lists of projects you can work on to upgrade your skills.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learning.acm.org/skills-bundle" rel="noopener noreferrer"&gt;Association for Computing Machinery: ACM members get access to O’Reilly Online Learning, Skillsoft Percipio, and Pluralsight.&lt;/a&gt; You also get access to the ACM Digital Library which contains a wealth of information of computer science and software engineering research.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>learning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The Power of Tries, Data Structure Optimization in Emacs</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Thu, 19 Sep 2024 02:10:33 +0000</pubDate>
      <link>https://dev.to/rudolfolah/the-power-of-tries-data-structure-optimization-in-emacs-2abb</link>
      <guid>https://dev.to/rudolfolah/the-power-of-tries-data-structure-optimization-in-emacs-2abb</guid>
      <description>&lt;p&gt;&lt;em&gt;The following article, originally published in 2009, was a combination of both prose and code, written in Emacs with a tool called &lt;a href="https://github.com/nrnrnr/noweb" rel="noopener noreferrer"&gt;"noweb"&lt;/a&gt;. I have updated it to not use the special syntax of TeX and noweb. Noweb is a &lt;a href="https://en.wikipedia.org/wiki/Literate_programming" rel="noopener noreferrer"&gt;"literate programming" tool, where the usual interplay between comments and code is changed into a complex layering of code and explanations and deep-dives&lt;/a&gt;. With the noweb tool, you can export the code into an assembled ordering. This prose/code text can be run through the noweb tool and produce an emacs lisp file. The code that's exported was in blocks that begin with &lt;code&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;=&lt;/code&gt; and end with &lt;code&gt;@&lt;/code&gt;. This updated version includes the assembled code at the end. &lt;a href="https://www.smashingmagazine.com/2009/11/zen-coding-a-new-way-to-write-html-code/" rel="noopener noreferrer"&gt;Zencoding was a way to rapidly generate HTML using CSS selectors.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  zencoding-trie
&lt;/h2&gt;

&lt;p&gt;To improve the performance of &lt;code&gt;zencoding-mode&lt;/code&gt;, caching/memoization of previously entered input needed to be done. At first, a naive hash-table implementation was chosen and this greatly cut down the speed with which zencoding generated HTML. Then it was realized that a trie data structure would be more efficient as the hash-table was storing partially entered input as well. A trie could store the partially entered data when needed and use less space than a hash-table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Trie" rel="noopener noreferrer"&gt;A trie is a tree where each node represents a character in a string&lt;/a&gt;. When you reach a leaf node, a word or sentence is spelled out. Each node can contain a value.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Important: the key is not stored in the node, but in the parent of that node.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The only operations we require for our trie are retrieve value and insert value.&lt;/p&gt;

&lt;p&gt;A node is a sequence of two elements. The first element is some value, in our case the cached version of zencoding's AST (Abstract Syntax Tree) output. If this is NIL then there is no value stored in this node. The second element is a sequence of branches (more nodes).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;make-zencoding-trie-node&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Creates a vector of two elements. The first element is some value, the second element is a character table for storing more branches of the trie. The value is initially NIL."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;vector&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-char-table&lt;/span&gt; &lt;span class="ss"&gt;'trie-table&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need some functions for setting and getting the values of our node type. All of the functions accept a node as an argument which must be a sequence type with at least two elements. The &lt;code&gt;value&lt;/code&gt; argument can be anything, typically something non-NIL. The &lt;code&gt;branch-key&lt;/code&gt; argument must be a character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-set-value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;aset&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a function to access a particular branch in a node. If the branch does not exist, it will be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-create-branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;aset&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;branch-key&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-zencoding-trie-node&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-brancher&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt;
    &lt;span class="nv"&gt;branch&lt;/span&gt;
      &lt;span class="c1"&gt;;; branch doesn't exist, so create it and then return it.&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-create-branch&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retrieval function is given a string &lt;code&gt;s&lt;/code&gt; to search for and the &lt;code&gt;trie&lt;/code&gt; to search within. Where &lt;code&gt;n&lt;/code&gt; is the length of the string &lt;code&gt;s&lt;/code&gt;, the argument &lt;code&gt;i&lt;/code&gt; is bounded like so: &lt;code&gt;0 &amp;lt; i &amp;lt;= n&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We are moving forward through a string till we reach its end. The current character is &lt;code&gt;s[i - 1]&lt;/code&gt;. If the current node we are visiting in the trie contains the current character as one of its branches, then we have to visit it.&lt;/p&gt;

&lt;p&gt;When the end of &lt;code&gt;s&lt;/code&gt; has been reached, &lt;code&gt;i = n&lt;/code&gt;, then we have reached the correct node and can return it (it will be created if it doesn't already exist). Before this, we will have to keep on searching for the right node.&lt;/p&gt;

&lt;p&gt;If we reach the end of the trie before the correct node has been found, we return NIL.&lt;/p&gt;

&lt;p&gt;The traverse function is a generalized version which includes a function argument, &lt;code&gt;f&lt;/code&gt;, telling us how to select the next branch to visit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;funcall&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="nv"&gt;branch&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1+&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-retrieve&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ss"&gt;'zencoding-trie-node-branch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we have a function for inserting a string and its value into a trie. The pre-conditions are that &lt;code&gt;s&lt;/code&gt; is a type of string, &lt;code&gt;value&lt;/code&gt; and &lt;code&gt;trie&lt;/code&gt; are non-NIL.&lt;/p&gt;

&lt;p&gt;We use the previously defined retrieve operation to find the final node and then insert the &lt;code&gt;value&lt;/code&gt; there. Fortunately for us, the retrieve operation takes care of creating new branches if necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-insert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"`s' is the string used to navigate the trie (each character is a node in the trie). `value' is the value we want to insert. `trie' is the node where we start the insertion."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-set-value&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ss"&gt;'zencoding-trie-node-brancher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="c1"&gt;;;; zencoding-trie.el --- A trie data structure built for zencoding-mode&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; Copyright (C) 2009, Rudolf Olah&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; Author: Rudolf Olah&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; This file is free software; you can redistribute it and/or modify&lt;/span&gt;
&lt;span class="c1"&gt;;; it under the terms of the GNU General Public License as published by&lt;/span&gt;
&lt;span class="c1"&gt;;; the Free Software Foundation; either version 3, or (at your option)&lt;/span&gt;
&lt;span class="c1"&gt;;; any later version.&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; This file is distributed in the hope that it will be useful,&lt;/span&gt;
&lt;span class="c1"&gt;;; but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;/span&gt;
&lt;span class="c1"&gt;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;/span&gt;
&lt;span class="c1"&gt;;; GNU General Public License for more details.&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;
&lt;span class="c1"&gt;;; You should have received a copy of the GNU General Public License&lt;/span&gt;
&lt;span class="c1"&gt;;; along with GNU Emacs; see the file COPYING.  If not, write to&lt;/span&gt;
&lt;span class="c1"&gt;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,&lt;/span&gt;
&lt;span class="c1"&gt;;; Boston, MA 02110-1301, USA.&lt;/span&gt;
&lt;span class="c1"&gt;;;&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;make-zencoding-trie-node&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"Creates a vector of two elements. The first element is some value, the second element is a character table for storing more branches of the trie. The value is initially NIL."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;vector&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-char-table&lt;/span&gt; &lt;span class="ss"&gt;'trie-table&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-set-value&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;aset&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-create-branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;aset&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;branch-key&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-zencoding-trie-node&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-node-brancher&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-branches&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt;
    &lt;span class="nv"&gt;branch&lt;/span&gt;
      &lt;span class="c1"&gt;;; branch doesn't exist, so create it and then return it.&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-create-branch&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="nv"&gt;branch-key&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;funcall&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;aref&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1-&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;null&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;length&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
      &lt;span class="nv"&gt;branch&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;1+&lt;/span&gt; &lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-retrieve&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ss"&gt;'zencoding-trie-node-branch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;zencoding-trie-insert&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;value&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="s"&gt;"`s' is the string used to navigate the trie (each character is a node in the trie). `value' is the value we want to insert. `trie' is the node where we start the insertion."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-node-set-value&lt;/span&gt;
   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-traverse&lt;/span&gt; &lt;span class="nv"&gt;s&lt;/span&gt; &lt;span class="nv"&gt;trie&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="ss"&gt;'zencoding-trie-node-brancher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;provide&lt;/span&gt; &lt;span class="ss"&gt;'zencoding-trie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;;; test code&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;make-zencoding-trie-node&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-insert&lt;/span&gt; &lt;span class="s"&gt;"ha"&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-insert&lt;/span&gt; &lt;span class="s"&gt;"hi"&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zencoding-trie-retrieve&lt;/span&gt; &lt;span class="s"&gt;"ha"&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>trie</category>
      <category>datastructures</category>
      <category>emacs</category>
    </item>
    <item>
      <title>Docker Compose Develop Watch and Syncing Files from the Host Container to a Service</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Fri, 12 Jul 2024 14:02:19 +0000</pubDate>
      <link>https://dev.to/rudolfolah/docker-compose-develop-watch-and-syncing-files-from-the-host-container-to-a-service-18hh</link>
      <guid>https://dev.to/rudolfolah/docker-compose-develop-watch-and-syncing-files-from-the-host-container-to-a-service-18hh</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/docker/compose/issues/11102" rel="noopener noreferrer"&gt;This thread has helped me better understand the "develop" behavior with Docker Compose&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/compose/file-watch/#example-1" rel="noopener noreferrer"&gt;The Docker Compose documentation of "Example 1" in "Use Compose Watch"&lt;/a&gt; does a pretty good job explaining things. Perhaps part of it should be added to &lt;a href="https://docs.docker.com/compose/compose-file/develop/" rel="noopener noreferrer"&gt;the Compose File - Develop page&lt;/a&gt; instead of hidden by links?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After the service is up, the watch mode starts monitoring the target directories and files. Then, whenever a source file in the web/ directory is changed, Compose syncs the file to the corresponding location under /src/web inside the container. For example, ./web/App.jsx is copied to /src/web/App.jsx.&lt;/p&gt;

&lt;p&gt;Once copied, the bundler updates the running application without a restart.&lt;/p&gt;

&lt;p&gt;Unlike source code files, adding a new dependency can’t be done on-the-fly, so whenever package.json is changed, Compose rebuilds the image and recreates the web service container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The "Rebuild Everything" Method
&lt;/h2&gt;

&lt;p&gt;This appears to be the ideal process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build the image with the current state of files copied into it
run compose with watch&lt;/li&gt;
&lt;li&gt;whenever a file changes, rebuild the image so it has the updated state of files within it&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The "Sync Files Manually" Approach
&lt;/h2&gt;

&lt;p&gt;Alternatively, outside of Docker Compose for syncing files (and based on the suggestions in the thread):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build the image with the current state of files copied into it (use a "watch" or "reload" command built into whatever app you're running)&lt;/li&gt;
&lt;li&gt;run compose (do not use develop or watch)&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;docker compose cp ./src app:/src&lt;/code&gt;
this should trigger the watch/reload command within the container&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The "Volume Mounting" Method
&lt;/h2&gt;

&lt;p&gt;Another option is to build a base image that &lt;em&gt;does not&lt;/em&gt; include source code and &lt;em&gt;only&lt;/em&gt; builds an environment in which the source code can be built or run. Then, a volume can be mounted into the container with the latest source code from the host environment, and the code can be run.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;build the image with the environment&lt;/li&gt;
&lt;li&gt;run compose with a volume mounted&lt;/li&gt;
&lt;li&gt;run the steps in the container to build/run the source&lt;/li&gt;
&lt;/ol&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%2Feh2844caramnapbiqg5j.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%2Feh2844caramnapbiqg5j.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It all depends on your developer workflow and what is understandable and can be used daily with minimal disruption to &lt;a href="https://medium.com/hootsuite-engineering/optimizing-the-feedback-loop-a-key-to-great-developer-productivity-f567c4e80c80" rel="noopener noreferrer"&gt;the developer feedback loop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Things to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how often are dependencies changing? should they be re-installed within the container or should the image be rebuilt (since one of the steps is installing dependencies)?&lt;/li&gt;
&lt;li&gt;is there a "watch" or "reload" command that reloads your app based on files changes?&lt;/li&gt;
&lt;li&gt;how much time does it take to rebuild the image? is it acceptable to yourself and to your team to wait for a rebuild on every set of source code changes? does it slow the developer feedback loop too much?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>development</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Incredible Updates in VS Code 1.91 (June 2024)</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Fri, 05 Jul 2024 17:49:07 +0000</pubDate>
      <link>https://dev.to/rudolfolah/incredible-updates-in-vs-code-191-june-2024-3p10</link>
      <guid>https://dev.to/rudolfolah/incredible-updates-in-vs-code-191-june-2024-3p10</guid>
      <description>&lt;p&gt;&lt;a href="https://code.visualstudio.com/updates/v1_91" rel="noopener noreferrer"&gt;Version 1.91 of VS Code is out now and has some incredible updates:&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/updates/v1_91#_extension-install-options" rel="noopener noreferrer"&gt;You can now install a specific version of extensions without downloading the latest version.&lt;/a&gt; This is useful if there are issues with newer versions or if everyone on the team is running a particular version of an extension.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/updates/v1_91#_unset-a-theme-color" rel="noopener noreferrer"&gt;Override a theme's color or border if you don't like it.&lt;/a&gt; You can set it back to "default".&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com/updates/v1_91#_typescript-55" rel="noopener noreferrer"&gt;TypeScript 5.5 is included.&lt;/a&gt; It enables regular expression syntax checking in JavaScript and TypeScript.&lt;/li&gt;
&lt;li&gt;Python: VS Code now uses &lt;a href="https://github.com/microsoft/python-environment-tools" rel="noopener noreferrer"&gt;python-environment-tools&lt;/a&gt; to discover all Python installs and virtual environments.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/updates/v1_91#_code-actions-on-save" rel="noopener noreferrer"&gt;Run "code actions" when saving a file, such as for automatically fixing lint issues.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vscode</category>
      <category>python</category>
    </item>
    <item>
      <title>In-Project Python Virtualenvs in Poetry</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Sat, 01 Jun 2024 17:54:43 +0000</pubDate>
      <link>https://dev.to/rudolfolah/in-project-virtualenvs-in-poetry-30km</link>
      <guid>https://dev.to/rudolfolah/in-project-virtualenvs-in-poetry-30km</guid>
      <description>&lt;p&gt;Poetry is a dependency and package manager for Python.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can list the Poetry configuration with &lt;code&gt;poetry config --list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You can set a Poetry configuration option with &lt;code&gt;poetry config $setting $value&lt;/code&gt;, for example &lt;code&gt;poetry config virtualenvs.path /path/to/cache/directory/virtualenvs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a Poetry project is created, the default configuration will create a virtualenv in another directory.&lt;/p&gt;

&lt;p&gt;Change where the virtualenv is created by adding this &lt;code&gt;poetry.toml&lt;/code&gt; file to your project before you run &lt;code&gt;poetry install&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# poetry.toml
[virtualenvs]
create = true
in-project = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documentation for Poetry advises &lt;em&gt;not&lt;/em&gt; to check in the &lt;code&gt;poetry.toml&lt;/code&gt; into version control since it can contain user-specific settings. You can add &lt;code&gt;poetry.toml&lt;/code&gt; to the &lt;code&gt;.gitignore&lt;/code&gt; for a repo.&lt;/p&gt;

</description>
      <category>python</category>
      <category>virtualenv</category>
      <category>poetry</category>
      <category>configuration</category>
    </item>
    <item>
      <title>New shell scripting language, a new tablet, and in-product messaging</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Fri, 24 May 2024 16:15:26 +0000</pubDate>
      <link>https://dev.to/rudolfolah/new-shell-scripting-language-a-new-tablet-and-in-product-messaging-5g5h</link>
      <guid>https://dev.to/rudolfolah/new-shell-scripting-language-a-new-tablet-and-in-product-messaging-5g5h</guid>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amber-lang.com/" rel="noopener noreferrer"&gt;Amber, a programming language that compiles to BASH&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matthewstrom.com/writing/wayfinding/" rel="noopener noreferrer"&gt;The slippery slope of in-product messaging
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://daylightcomputer.com/product" rel="noopener noreferrer"&gt;Daylight Computer, an alternative to Kindle and iPad?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Shell scripting times a million
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://amber-lang.com/" rel="noopener noreferrer"&gt;Amber is a new programming language that allows you to write code converted into BASH shell scripts.&lt;/a&gt; The language's syntax is a mix of JavaScript, Python, and something else (Kotlin? Rust?). The idea is to write in a language with a modern syntax, type-safety, and safety features.&lt;/p&gt;

&lt;p&gt;One of those safety features forces you to write code to handle failures whenever you run a shell command.&lt;/p&gt;

&lt;p&gt;The syntax also makes it more apparent that command failures are being handled:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let files = ["config.json", "file.txt", "audio.mp3"]

loop index, file in files {
    $mv {file} {index}{file}$ failed {
        echo "Failed to rename {file}"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're only occasionally writing shell scripts, Amber may not be a priority for you. In such cases, linting tools like &lt;a href="https://www.shellcheck.net/" rel="noopener noreferrer"&gt;ShellCheck&lt;/a&gt; could be more beneficial. However, if you find yourself frequently writing shell scripts, to the point where you're considering Python or Ruby for better re-usability, then Amber is definitely worth your attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  In-app tour guides are marketing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://matthewstrom.com/writing/wayfinding/" rel="noopener noreferrer"&gt;In &lt;em&gt;"The Slippery Slope of In-Product Messaging,"&lt;/em&gt; designer Matthew Ström explains that in-product messaging, those product tours you see in web apps, could be a symptom of a "bad" design.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's an interesting take, though I can't entirely agree. In-product messaging helps guide users/customers through new product features, regardless of whether the new feature's user experience is well-designed.&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%2Fdtyt9nzd2g91833pv453.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%2Fdtyt9nzd2g91833pv453.png" alt="screenshot of app cues" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In-product messaging is another marketing touchpoint that informs the customer about a feature that may not be part of their typical workflow. Not to mention, once a customer/user has seen them, they won't reappear. Think about it this way: from a B2B SaaS perspective, the customer gets an email about a new feature release, logs into the app, and sees a small notification icon or a banner on the page about the new feature release. They go to some other page and get invited to go through a tour of the feature. This kind of repetition is needed even for well-designed user experiences.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tablet you might use every single day
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://daylightcomputer.com/product" rel="noopener noreferrer"&gt;The Daylight Computer is a mix between the Kindle and the iPad.&lt;/a&gt; The screen resembles the Kindle screen, and it has the form factor of an iPad, including a stylus. It is extremely interesting that the screen's refresh rate is much higher than the typical ebook reader. It's high enough to be a tablet.&lt;/p&gt;

&lt;p&gt;The Daylight Computer, DC-1, runs Android, so you can run any Android tablet app on it with a kinder and gentler screen for the eyes.&lt;/p&gt;

&lt;p&gt;Screen glare is not a problem with the DC-1.&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%2Fid2m84khzgvgxj0blx6i.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%2Fid2m84khzgvgxj0blx6i.png" alt="screenshot of daylight computer and ipad comparison" width="800" height="612"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've bought a few tablets before and used them for reading, watching movies (and sometimes video games and coding). I use them once in a while. I also have a Kindle and use it every day.&lt;/p&gt;

&lt;p&gt;It will be interesting to see whether the DC-1 lives up to the hype.&lt;/p&gt;

</description>
      <category>bash</category>
      <category>ipad</category>
      <category>product</category>
      <category>marketing</category>
    </item>
    <item>
      <title>React Router has merged with Remix, should you use a different router?</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Fri, 17 May 2024 03:18:02 +0000</pubDate>
      <link>https://dev.to/rudolfolah/react-router-has-merged-with-remix-should-you-use-a-different-router-5e2a</link>
      <guid>https://dev.to/rudolfolah/react-router-has-merged-with-remix-should-you-use-a-different-router-5e2a</guid>
      <description>&lt;p&gt;&lt;a href="https://remix.run/blog/merging-remix-and-react-router?ck_subscriber_id=2125265822" rel="noopener noreferrer"&gt;At ReactConf 2024, the Remix framework team announced merging the Remix full-stack framework into React Router.&lt;/a&gt; They reasoned that Remix was becoming a very thin layer over React Router.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/T8TZQ6k4SLE?start=5537"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of React Router and Remix
&lt;/h2&gt;

&lt;h3&gt;
  
  
  React Router Basics
&lt;/h3&gt;

&lt;p&gt;If you're unfamiliar with it, routers provide a way to render a React component based on the URL and URL parameters. That's the most essential feature. The more advanced features of a frontend router include data loading, loading indicators, and server rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction to Remix
&lt;/h3&gt;

&lt;p&gt;Remix is a full-stack framework for React. It consists of a compiler, a server-side HTTP handler, a server framework, and a browser framework. This framework provides server-side rendering, data fetching from the server, progressive enhancement, and state management. Since Remix provides full-stack data flow, it can handle state management, removing the need for libraries like Redux, React Query, and Apollo. Progressive enhancement means that users who have JavaScript disabled for whatever reason can still click links, submit forms, and use the web app.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Merger Announcement
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Critical Reasons for the Merger
&lt;/h3&gt;

&lt;p&gt;The Remix team decided to merge with React Router because they created a framework based on React Router, they believe that all React developers (who use a framework) should enjoy from automatic code splitting, simplified data loading, and server rendering.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impact on Existing Projects
&lt;/h3&gt;

&lt;p&gt;The Remix team provided an upgrade path that made it easy for React projects using React Router to use Remix. The next version of Remix is now React Router v7. They will likely provide documentation on upgrading from React Router v6 and from Remix to React Router v7, as &lt;a href="https://reactrouter.com/en/main/upgrading/v5" rel="noopener noreferrer"&gt;they have in the past for upgrading from React Router v5&lt;/a&gt;, Reach Router, and RouterProvider. Watch for upgrade documentation and news of an upgrade path in the next six months.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluating Your Options
&lt;/h2&gt;

&lt;p&gt;If you are happy with React Router v6 and have been using some of the features that Remix has through other libraries, you should evaluate the current Remix framework and see what it provides compared to what you already have. It may make sense to look forward to an upgrade to React Router v7 (aka Remix v3).&lt;/p&gt;

&lt;p&gt;You should take into account the level of effort it would take to upgrade and whether the code base is existing or a new project. If it's a new project, you can evaluate React Router v7 as a framework choice amongst Next.js and other React framework choices.&lt;/p&gt;

&lt;p&gt;Suppose all you need is a router for your React pages and components, and you want to avoid any advanced features that React Router v7 will provide. In that case, you should evaluate sticking with React Router v6 or considering the following alternatives to React Router.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives to React Router
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Wouter
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/molefrog/wouter" rel="noopener noreferrer"&gt;Wouter is a well-maintained routing library for React.&lt;/a&gt; It has minimal dependencies, is small (2.1 KB gzipped), and has the same basic components as React Router (Link, Switch, Redirect). It provides hooks for the location, the route, and the router, and the API is simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  TanStack/router
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/TanStack/router" rel="noopener noreferrer"&gt;The TanStack/router is a React router written in TypeScript so it's typesafe and it includes built-in caching.&lt;/a&gt; It is lightweight (12 KB) and has a lot of functionality. It goes beyond what wouter provides and has overlaps with features that React Router provides such as &lt;a href="https://tanstack.com/router/latest/docs/framework/react/overview" rel="noopener noreferrer"&gt;nested routes, file-based route generation, and automatic route prefetching&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://tanstack.com/router/latest/docs/framework/react/migrate-from-react-router" rel="noopener noreferrer"&gt;They provide a migration guide from React Router to TanStack/router that you can follow&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update: &lt;a href="https://tanstack.com/start/latest" rel="noopener noreferrer"&gt;TanStack is creating their own React framework powered by TanStack Router, it's called TanStack Start&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;The JavaScript and React ecosystems move very fast. The merging of React Router with Remix is one such change. Another change is the encouragement of using frameworks when creating new React projects, deprecating the previous way of using create-react-app. The frameworks modernize the React developer experience and introduce new possibilities for frontend engineers to build great web apps. However, each change also needs to be evaluated before it's implemented, perhaps your project doesn't need all the features provided by a framework, maybe another router instead of React Router works better for your use cases, or possibly it's time to commit to a framework instead of cobbling together random React libraries.&lt;/p&gt;

&lt;p&gt;Staying up to date in the tech industry is vital. &lt;a href="https://react.dev/blog" rel="noopener noreferrer"&gt;If you are using React, check out the React blog&lt;/a&gt;, the blogs of your &lt;a href="https://remix.run/blog" rel="noopener noreferrer"&gt;favorite React framework&lt;/a&gt;, and the GitHub code repos for the React libraries that you use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://conf.react.dev/" rel="noopener noreferrer"&gt;Check out ReactConf; it can provide insight into where the industry is going.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.jplhomer.org/posts/on-laravel-full-stack-javascript-and-productive-frameworks/?ck_subscriber_id=2125265822" rel="noopener noreferrer"&gt;There's a blog post about fullstack frameworks and Laravel (a PHP framework)&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...JavaScript frameworks do the front-end really well. But you need a back-end, too, for routing and server rendering, which is why things like SSR in Next.js and Remix, and more recently—React Server Components—are born.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Update: &lt;a href="https://react.dev/learn/creating-a-react-app#start-from-scratch" rel="noopener noreferrer"&gt;The official React docs recommend Vite, Parcel, or RSbuild if you're starting from scratch and do not want to use a full-stack framework like React Router v7 or Next.js&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>remix</category>
      <category>webdev</category>
      <category>router</category>
    </item>
    <item>
      <title>Kubernetes and Docker Desktop for Fast Local Development</title>
      <dc:creator>Rudolf Olah</dc:creator>
      <pubDate>Wed, 08 May 2024 15:11:33 +0000</pubDate>
      <link>https://dev.to/rudolfolah/kubernetes-and-docker-desktop-for-fast-local-development-19c3</link>
      <guid>https://dev.to/rudolfolah/kubernetes-and-docker-desktop-for-fast-local-development-19c3</guid>
      <description>&lt;p&gt;&lt;a href="https://www.docker.com/blog/how-kubernetes-works-under-the-hood-with-docker-desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt; can run a Kubernetes node that is accessible locally. It enables you to build and re-build local Docker images and have them available to Kubernetes pods for deployments.&lt;/p&gt;

&lt;p&gt;For typical deployments in Kubernetes, you will want to specify a version tag for a Docker image.&lt;/p&gt;

&lt;p&gt;For local development with Docker Desktop and Kubernetes, you can set the tag of the image &lt;code&gt;latest&lt;/code&gt; or &lt;code&gt;development&lt;/code&gt;, any tag without a version number.&lt;/p&gt;

&lt;p&gt;You must also set the deployment's &lt;code&gt;restartPolicy&lt;/code&gt; to &lt;code&gt;Always&lt;/code&gt; and the container's &lt;code&gt;imagePullPolicy&lt;/code&gt; to &lt;code&gt;IfNotPresent&lt;/code&gt;. This ensures that Kubernetes can pull the image from Docker Desktop, and that it will always restart with the latest updated image.&lt;/p&gt;

&lt;p&gt;Then you can run &lt;code&gt;kubectl rollout restart deployment $DEPLOYMENT_NAME&lt;/code&gt; to restart the pod and pull the latest development image.&lt;/p&gt;

&lt;p&gt;The iteration cycle looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write code&lt;/li&gt;
&lt;li&gt;Build the image with the &lt;code&gt;development&lt;/code&gt; tag&lt;/li&gt;
&lt;li&gt;Restart the deployment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can use &lt;a href="https://github.com/emcrisostomo/fswatch" rel="noopener noreferrer"&gt;fswatch&lt;/a&gt; or some other watch tool to monitor changes in source code and kick off the Docker image rebuild and then the Kubernetes deployment restart.&lt;/p&gt;

&lt;p&gt;For monitoring the local Kubernetes cluster, I have been using &lt;a href="https://headlamp.dev/" rel="noopener noreferrer"&gt;Headlamp&lt;/a&gt; which is available as a &lt;a href="https://hub.docker.com/extensions/headlamp/headlamp-docker-extension" rel="noopener noreferrer"&gt;Docker Desktop extension&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Check &lt;a href="https://docs.docker.com/desktop/install/mac-permission-requirements/" rel="noopener noreferrer"&gt;"Understand permission requirements for Docker Desktop on Mac"&lt;/a&gt; if there are permission or port issues.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/nqKYgeUtk8s"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

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