<?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: Joe Schmitt</title>
    <description>The latest articles on DEV Community by Joe Schmitt (@josephschmitt).</description>
    <link>https://dev.to/josephschmitt</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%2F298592%2Fbf63374b-2b38-421c-8806-2a986800ab0f.png</url>
      <title>DEV Community: Joe Schmitt</title>
      <link>https://dev.to/josephschmitt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/josephschmitt"/>
    <language>en</language>
    <item>
      <title>The Tools That Make My Terminal WorK</title>
      <dc:creator>Joe Schmitt</dc:creator>
      <pubDate>Sun, 05 Oct 2025 19:24:37 +0000</pubDate>
      <link>https://dev.to/josephschmitt/the-tools-that-make-my-terminal-work-3ka6</link>
      <guid>https://dev.to/josephschmitt/the-tools-that-make-my-terminal-work-3ka6</guid>
      <description>&lt;p&gt;At some point, most developers start to care about their terminal setup. It stops being just a place to run commands and becomes part of how you think about your work.&lt;/p&gt;

&lt;p&gt;Over the years, I've built mine into something fast, predictable, and easy to reproduce across machines. None of it is particularly complicated, but the tools fit together in a way that makes the whole setup feel cohesive.&lt;/p&gt;

&lt;p&gt;Here's what I use, and why it's worth knowing about.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dotfiles + GNU Stow
&lt;/h2&gt;

&lt;p&gt;Everything starts with &lt;a href="https://github.com/josephschmitt/dotfiles" rel="noopener noreferrer"&gt;my dotfiles repo&lt;/a&gt;. It's where all my terminal configurations live: shell, editor, Tmux, Git, everything.&lt;/p&gt;

&lt;p&gt;The reason for having a dedicated repo is simple: these configurations evolve constantly, and being able to version them in Git means I can track changes, experiment safely, and sync them across machines. The tricky part is &lt;em&gt;where&lt;/em&gt; those files actually live. Most configuration files belong in your home directory (&lt;code&gt;~/.zshrc&lt;/code&gt;, &lt;code&gt;~/.config/nvim/init.lua&lt;/code&gt;, etc.), but you really don't want to make your entire home directory a Git repo.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;GNU Stow&lt;/strong&gt; comes in.&lt;/p&gt;

&lt;p&gt;Stow lets you keep your dotfiles in a separate, organized folder structure, and then it symlinks them into place in your home directory. For example, a &lt;code&gt;zsh/.zshrc&lt;/code&gt; file inside the repo becomes &lt;code&gt;~/.zshrc&lt;/code&gt; when stowed.&lt;/p&gt;

&lt;p&gt;This approach has a few big advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You get full version control and portability without polluting your home directory.&lt;/li&gt;
&lt;li&gt;You can easily remove or update a tool's configuration by "unstowing" it.&lt;/li&gt;
&lt;li&gt;You always know exactly what will be linked where -- no magic, no scripts, no templating language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I chose Stow specifically because of that simplicity. The files in my repo are exactly the files that end up on my system -- no templates, no build step, no indirection. You can open any file in the repo and know immediately what your local configuration would look like.&lt;/p&gt;

&lt;p&gt;The repo is also structured around &lt;strong&gt;profiles&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;shared/&lt;/strong&gt; for configuration common to all machines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;personal/&lt;/strong&gt; for personal devices&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;work/&lt;/strong&gt; for work-related setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That lets me apply a different combination of stow packages depending on which machine I'm setting up. It keeps the configurations isolated but still easy to maintain in one place.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;stow shared work&lt;/code&gt; on a new laptop, and everything falls into place.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;Tmux&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Tmux&lt;/strong&gt; is a terminal multiplexer: it lets you run and manage multiple terminal sessions inside a single window. You can split the screen into panes, create tab-like "windows," detach from a session entirely, and come back later with everything exactly where you left it.&lt;/p&gt;

&lt;p&gt;For me, it's the backbone of how I work day to day. It ties together everything else -- Neovim, shells, Git, even AI assistants -- into a single, coherent workspace.&lt;/p&gt;

&lt;p&gt;Each Tmux session usually starts from a project directory. I'll open one up (often through &lt;strong&gt;Sesh&lt;/strong&gt;, more on that later) and it immediately drops me into a layout I've come to rely on: a main pane on the left and a couple of ancillary panes on the right.&lt;/p&gt;

&lt;p&gt;The left pane is almost always my editor Neovim running in LazyVim. On the right, I usually have two smaller panes stacked vertically: the top one runs an AI coding assistant like &lt;a href="https://opencode.ai" rel="noopener noreferrer"&gt;OpenCode&lt;/a&gt;, and the bottom one is just a regular shell for running commands, tests, or quick Git actions.&lt;/p&gt;

&lt;p&gt;It's a simple layout, but it covers nearly everything I need. If I ever need a third or fourth pane, I can split, rearrange, or resize them at will using simple keyboard shortcuts.&lt;/p&gt;

&lt;p&gt;Navigation is fast and intuitive. I move between panes using &lt;strong&gt;Alt + movement keys&lt;/strong&gt;, and when I need to focus on one task, I hit &lt;strong&gt;Alt + z&lt;/strong&gt; to "zoom" a pane full-screen, then drop back into my grid when I'm done. I can create new windows with &lt;strong&gt;Alt + 1--9&lt;/strong&gt; and switch between them using &lt;strong&gt;Alt + [&lt;/strong&gt; and &lt;strong&gt;Alt + ]&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Those shortcuts make it feel less like juggling terminals and more like working in a dynamic, responsive interface that's entirely keyboard-driven.&lt;/p&gt;

&lt;p&gt;I've also added a few "popup" panes, centered overlays that float above the grid. They're perfect for quick context switches: I have one for &lt;strong&gt;LazyGit&lt;/strong&gt;, one for &lt;strong&gt;Yazi&lt;/strong&gt;, one for a bare “quick shell”, and one that runs &lt;strong&gt;Sesh&lt;/strong&gt; so I can instantly jump between sessions.&lt;/p&gt;

&lt;p&gt;All of this combines into a setup that's fast to move around in, easy to multitask within, and flexible enough to adapt as I work. Whether I'm deep in code or juggling multiple projects, everything stays within reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neovim (with LazyVim)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Neovim&lt;/strong&gt;, configured with &lt;strong&gt;LazyVim&lt;/strong&gt;, was my gateway drug into the world of advanced terminal tools.&lt;/p&gt;

&lt;p&gt;For years I resisted diving into Vim beyond the absolute basics. I'd been using VS Code for nearly a decade, and that workflow was burned into muscle memory. Every time I tried Vim, it felt like touching a hot stove: awkward and counterintuitive, clearly designed by someone who didn't like other people very much.&lt;/p&gt;

&lt;p&gt;What finally got me over the hump was two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LazyVim&lt;/strong&gt; gives Vim/Neovim the vast majority of the features of a modern IDE, in a setup that's cohesive, visually polished, and doesn't require building everything from scratch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I was spending more time editing files on remote machines, and being stuck in stock Vim or Nano was painful. I realized if I just learned Vim properly and made it my own, it would pay off in flexibility everywhere I worked.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And I was right.&lt;/p&gt;

&lt;p&gt;I'm now completely addicted to Vim's modal editing workflow. Motions, operators, and text objects make editing &lt;em&gt;fast&lt;/em&gt; -- so fast that I feel clumsy when I have to use a traditional editor without them.&lt;/p&gt;

&lt;p&gt;My setup is based on &lt;strong&gt;LazyVim's defaults&lt;/strong&gt;, which I've customized only where it adds clear value. If you peek into my config, it might look like I've gone overboard -- but almost everything I've added falls into the "nice-to-have" category rather than "must-have." I'm careful to only integrate plugins that enhance something I already know how to do manually. The few keymap tweaks I've made are the exception; those are there to match how my hands naturally want to work.&lt;/p&gt;

&lt;p&gt;With that setup, Neovim has become my full-time IDE, for both personal and work projects. I've got LSPs configured for the languages I use, auto-formatting, test runners, and build tools all running smoothly. And because everything is keyboard-driven and composable, I can move through code, refactor, and search without ever breaking flow.&lt;/p&gt;

&lt;p&gt;Once the motions and shortcuts settle into muscle memory, it's genuinely hard to overstate how fast and intuitive it feels.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/jesseduffield/lazygit" rel="noopener noreferrer"&gt;LazyGit&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;LazyGit&lt;/strong&gt; is my Git UI of choice. It hits the perfect balance between having access to the full power of Git without needing to memorize its arcane command syntax, and being able to see everything that's going on visually.&lt;/p&gt;

&lt;p&gt;It handles the basics -- staging and unstaging changes, committing, pulling, and pushing -- but also makes the advanced stuff easy. Interactive rebases, staging individual hunks, managing stashes, switching branches -- all of it's just a few keystrokes away, and all without ever touching the mouse.&lt;/p&gt;

&lt;p&gt;It gives me the same control as the command line, but with a clear, structured view of what's changed and how it fits together.&lt;/p&gt;

&lt;p&gt;I usually open LazyGit in one of two ways, both of which ultimately boil down to a popup. Inside &lt;strong&gt;LazyVim&lt;/strong&gt;, &lt;code&gt;&amp;lt;leader&amp;gt;gg&lt;/code&gt;opens LazyGit directly within Neovim. It's great for quick diffs or commits, though when Neovim is running in a split Tmux pane, the view can get a bit narrow. For that, I have a Tmux keybind -- &lt;code&gt;&amp;lt;leader&amp;gt;G&lt;/code&gt; -- that opens LazyGit in a full-width popup across all panes, no matter how my layout is arranged.&lt;/p&gt;

&lt;p&gt;That flexibility means I can manage Git state from anywhere, without context-switching or losing focus.&lt;/p&gt;

&lt;p&gt;At this point, I rarely need to drop down to raw Git commands. Occasionally, in very large monorepos, LazyGit slows down a bit and I'll use Git directly, but those cases are rare.&lt;/p&gt;

&lt;p&gt;The only customization I've made is visual -- I've themed it to match the rest of my terminal and set it to use &lt;strong&gt;&lt;a href="https://github.com/dandavison/delta" rel="noopener noreferrer"&gt;Delta&lt;/a&gt;&lt;/strong&gt; as the diff tool. It fits right in with the rest of my setup: clean, fast, and fully keyboard-driven.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/ajeetdsouza/zoxide" rel="noopener noreferrer"&gt;Zoxide&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Zoxide&lt;/strong&gt; is a relatively recent addition to my setup, but it's quickly become one of those tools I can't imagine going back to working without.&lt;/p&gt;

&lt;p&gt;It works as a smarter replacement for the standard &lt;code&gt;cd&lt;/code&gt; command. Once you've used it to navigate somewhere, Zoxide remembers that directory. From then on, you can jump back to it just by typing part of its name. For example, after visiting &lt;code&gt;~/development/my-project&lt;/code&gt; once, I can just run &lt;code&gt;z devproj&lt;/code&gt; and it'll take me straight there.&lt;/p&gt;

&lt;p&gt;For a long time, I didn't really see the point -- typing full paths didn't &lt;em&gt;feel&lt;/em&gt; that painful. But eventually I realized how often I was bouncing between the same directories day after day. The real breakthrough came when I discovered the &lt;code&gt;zi&lt;/code&gt; command, which opens an FZF-powered fuzzy finder listing all known directories. It removes the "magic" guesswork entirely. I can just search and jump instantly.&lt;/p&gt;

&lt;p&gt;I also use &lt;code&gt;zoxide query&lt;/code&gt; (aliased to &lt;code&gt;zq&lt;/code&gt;) constantly. It's like &lt;code&gt;z&lt;/code&gt;, but instead of changing directories, it returns the full path it matched to. That's perfect for scripts or one-off commands where I want to &lt;em&gt;use&lt;/em&gt; a path as a search query without moving into it.&lt;/p&gt;

&lt;p&gt;One of the most powerful use cases is parameter expansion. If I want to open Neovim in a specific project, instead of manually &lt;code&gt;cd&lt;/code&gt;ing into it, I can run something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    nvim &lt;span class="si"&gt;$(&lt;/span&gt;zq myproj&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one-liner uses Zoxide's search to expand to the full path automatically.&lt;/p&gt;

&lt;p&gt;And that's just the start. Like several other tools in this setup, Zoxide ends up getting used &lt;em&gt;by&lt;/em&gt; other utilities -- for example, through FZF integration -- making it a quiet but indispensable layer in the overall system.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;FZF&lt;/a&gt; + &lt;a href="https://github.com/BurntSushi/ripgrep" rel="noopener noreferrer"&gt;Ripgrep&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;FZF&lt;/strong&gt; and &lt;strong&gt;Ripgrep&lt;/strong&gt; are everywhere in my setup. They're not flashy tools on their own, but they're the foundation that makes almost everything else fast and fluid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ripgrep&lt;/strong&gt; (&lt;code&gt;rg&lt;/code&gt;) is a modern replacement for &lt;code&gt;grep&lt;/code&gt;: it searches through files blazingly fast, respecting &lt;code&gt;.gitignore&lt;/code&gt; files and optimized for developer workflows. I use it both directly and indirectly, often without even realizing it, since it powers search in tools like Neovim and other terminal UIs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FZF&lt;/strong&gt;, on the other hand, is the universal fuzzy finder. It's the UI layer that lets me pick anything -- files, commands, directories, Git branches, sessions -- just by typing a few letters.&lt;/p&gt;

&lt;p&gt;It shows up everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inside &lt;strong&gt;Neovim/LazyVim&lt;/strong&gt;, where it powers file and text search.&lt;/li&gt;
&lt;li&gt;In my &lt;strong&gt;shell&lt;/strong&gt;, for navigating command history or recently used directories.&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;LazyGit&lt;/strong&gt;, to fuzzy find repositories.&lt;/li&gt;
&lt;li&gt;And in &lt;strong&gt;Sesh&lt;/strong&gt;, to quickly jump between open sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FZF has become such a deep part of my workflow that it's almost invisible -- it's just how I find things now. Paired with Ripgrep, it turns the terminal into something that's not only powerful, but &lt;em&gt;immediately accessible&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;They're small tools, but they punch far above their weight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh My Posh
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Oh My Posh&lt;/strong&gt; handles my shell prompt, and while it might look like a purely aesthetic choice, it's actually a big quality-of-life improvement.&lt;/p&gt;

&lt;p&gt;The real value isn't in how it looks, it's in how consistent and maintainable it is. I've done manual prompt customization in Bash before, and it becomes unreadable almost immediately. Even for Bash, which is already known for being a bit inscrutable, that's saying something.&lt;/p&gt;

&lt;p&gt;With Oh My Posh, my prompt configuration is standardized and declarative. It's the same across every shell I use, and it behaves exactly the same on every machine. The configuration is simple and predictable, and I can tweak it without feeling like I'm defusing a bomb.&lt;/p&gt;

&lt;p&gt;At a glance, my prompt gives me the key bits of context I care about -- current directory, Git branch and status, and even which shell I'm running -- all color-coded and cleanly presented. It's fast, rock solid, and stays out of the way.&lt;/p&gt;

&lt;p&gt;It's one of those small things that you stop noticing entirely until you have to use a system without it.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/dandavison/delta" rel="noopener noreferrer"&gt;Delta&lt;/a&gt;, &lt;a href="https://github.com/eza-community/eza" rel="noopener noreferrer"&gt;Eza&lt;/a&gt;, &lt;a href="https://github.com/sharkdp/bat" rel="noopener noreferrer"&gt;Bat&lt;/a&gt;, and &lt;a href="https://github.com/sxyazi/yazi" rel="noopener noreferrer"&gt;Yazi&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;These four tools fall into what I think of as the &lt;em&gt;quality-of-life&lt;/em&gt; category. They don't redefine how I work, but they make the experience smoother, faster, and a little more enjoyable.&lt;/p&gt;

&lt;p&gt;I spend a lot of time looking at diffs these days, especially as more and more of my code is written by AI that I then review. &lt;strong&gt;Delta&lt;/strong&gt; makes that experience far better. It's my default Git difftool, and it's also what &lt;strong&gt;LazyGit&lt;/strong&gt; uses behind the scenes. I configure it once, and I get consistent, syntax-highlighted diffs everywhere: clear, colorful, and easy to parse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eza&lt;/strong&gt; is a modern replacement for &lt;code&gt;ls&lt;/code&gt;. It adds visual niceties like icons, tree views, and control over recursion depth. I've aliased &lt;code&gt;ls&lt;/code&gt; to &lt;code&gt;eza&lt;/code&gt;, and most of the time I forget I'm even using it. It makes directory listings just a bit more readable without changing how I work.&lt;/p&gt;

&lt;p&gt;Same story with &lt;strong&gt;Bat&lt;/strong&gt;, which replaces &lt;code&gt;cat&lt;/code&gt;. It adds syntax highlighting and line numbers when displaying files, but otherwise behaves exactly like &lt;code&gt;cat&lt;/code&gt;. It's another one of those small upgrades that quietly improves the default experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Yazi&lt;/strong&gt; is a bit different -- it's a full terminal-based file browser. I don't use it constantly, but when I do, it's invaluable. It's fast, powerful, and great for when I'm spelunking through unfamiliar directory trees. It lets me copy, move, rename, and preview files inline, all without leaving the terminal.&lt;/p&gt;

&lt;p&gt;The common thread between all these tools is speed and simplicity. They each follow the Unix philosophy of doing one thing and doing it well, often improving on utilities that have existed for decades. I can absolutely get things done without them — it's just slower and clunkier.&lt;/p&gt;

&lt;p&gt;Combined, they make the terminal a place that feels as powerful and polished as any modern IDE. And because I've standardized my color themes across everything, it all looks cohesive too.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/joshmedeski/sesh" rel="noopener noreferrer"&gt;Sesh&lt;/a&gt; + &lt;a href="https://github.com/vinnymeller/twm" rel="noopener noreferrer"&gt;TWM&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sesh&lt;/strong&gt; is what ties my whole terminal environment together. It manages my &lt;strong&gt;Tmux&lt;/strong&gt; sessions -- the backbone of how I work -- and gives me a clean, consistent way to move between projects.&lt;/p&gt;

&lt;p&gt;Most of my sessions are defined by working directories. I've configured Sesh so that its picker doesn't just list open Tmux sessions, but also directories tracked by &lt;strong&gt;Zoxide&lt;/strong&gt;. That means if I pick a Zoxide directory, Sesh automatically creates a new Tmux session there, naming it after the directory. It's seamless: one action to jump into any project, whether it already exists or not.&lt;/p&gt;

&lt;p&gt;I use Sesh almost exclusively through its &lt;strong&gt;popup window in Tmux&lt;/strong&gt;, which makes it fast to open, fuzzy find a project, and jump right in without breaking focus.&lt;/p&gt;

&lt;p&gt;Alongside Sesh, I also use &lt;strong&gt;TWM (Tmux Workspace Manager)&lt;/strong&gt;, which adds another layer of automation on top. TWM scans directories I've configured and automatically detects projects based on certain markers: a &lt;code&gt;.git&lt;/code&gt; directory, a &lt;code&gt;package.json&lt;/code&gt; file, etc. When I launch it, it presents a fuzzy finder list (powered by &lt;strong&gt;FZF&lt;/strong&gt;) of projects I can narrow down interactively.&lt;/p&gt;

&lt;p&gt;Once I select a project, TWM automatically spins up a Tmux session and applies a specific layout depending on the type of project, all without me lifting a finger.&lt;/p&gt;

&lt;p&gt;Together, Sesh and TWM handle nearly all of my session and project management. I don't have to remember where things live or how they're configured, I just pick what I want to work on, and everything else falls into place.&lt;/p&gt;

&lt;p&gt;It's the final layer that makes my terminal setup feel like a real, integrated environment rather than a collection of separate tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  Putting It All Together
&lt;/h2&gt;

&lt;p&gt;The terminal can be as minimal or as complex as you make it. For a long time, I treated it as a tool of last resort, a place to run a few commands and then get back to a "real" environment like VS Code. But somewhere along the way, it stopped being just a shell and became &lt;em&gt;the&lt;/em&gt; environment.&lt;/p&gt;

&lt;p&gt;The tools I've described here -- from &lt;strong&gt;Stow&lt;/strong&gt; to &lt;strong&gt;Tmux&lt;/strong&gt;, &lt;strong&gt;Neovim&lt;/strong&gt;, &lt;strong&gt;LazyGit&lt;/strong&gt;, &lt;strong&gt;Zoxide&lt;/strong&gt;, &lt;strong&gt;FZF&lt;/strong&gt;, and everything in between -- weren't things I adopted all at once. Each solved one small problem. But together, they've grown into a cohesive system that's fast, consistent, and surprisingly pleasant to use.&lt;/p&gt;

&lt;p&gt;That doesn't mean everyone needs this exact setup. The best setups are personal -- they grow over time, one improvement at a time, as you find the friction points that matter to you. If a tool adds clarity or speed, keep it. If it adds complexity or gets in the way, drop it.&lt;/p&gt;

&lt;p&gt;This isn't about collecting tools for their own sake; it's about building an environment that helps you think less about how you work, and more about what you're working on.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>productivity</category>
      <category>tooling</category>
    </item>
    <item>
      <title>How I run through a tutorial and actually remember things</title>
      <dc:creator>Joe Schmitt</dc:creator>
      <pubDate>Thu, 02 Jul 2020 01:24:28 +0000</pubDate>
      <link>https://dev.to/josephschmitt/how-i-run-through-a-tutorial-and-actually-remember-things-lde</link>
      <guid>https://dev.to/josephschmitt/how-i-run-through-a-tutorial-and-actually-remember-things-lde</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of a (hopefully) long-running series of Dev Diary entires on my process of teaching myself Swift and Swift UI in order to build an app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I mentioned before, Apple has some &lt;a href="https://developer.apple.com/tutorials"&gt;amazing tutorials&lt;/a&gt; dedicated to Swift UI. The presentation of these is the best I've ever seen, broken down step-by-step with clear diffs and explanations on what you're doing, and even a quick quiz at the end to make sure you actually understood what you've done.&lt;/p&gt;

&lt;p&gt;When doing these types of tutorials, you might often find that you've gotten to the end to that quiz having retained almost nothing. It's ok, it happens. Here's what I do that oftentimes helps to make sure I'm paying attention and actually learning, not just regurgitating.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Re-read every instruction/step more than once. It's too easy to just skim and not really take in what they're saying. Forcing yourself to do it at least twice, or maybe even once out-loud, forces you to slow down and pay attention&lt;/li&gt;
&lt;li&gt;Never copy-paste the sample code. I learned this one the hard way from having done these types of tutorials from a text book back in the day. Copying and pasting has the same issue as skimming: you're not actually retaining anything. Forcing yourself to write the lines at least gives you a shot at remembering, just like note-taking helps retain a lecture&lt;/li&gt;
&lt;li&gt;Try to do the tutorial step yourself before you copy the step. I can't stress this one enough. When I read an instruction that wants me to do something, I immediately ignore the code they're asking me to write and try and write the code myself. Nine times out of 10 I fail miserably, but that's ok! Eventually I start getting the hang of it and I start being able to complete the example just from its description, without referring to the sample code at all. That's when I know I've nailed it.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devdiary</category>
      <category>swiftui</category>
      <category>programming</category>
    </item>
    <item>
      <title>Looking in to SwiftUI</title>
      <dc:creator>Joe Schmitt</dc:creator>
      <pubDate>Wed, 01 Jul 2020 16:23:31 +0000</pubDate>
      <link>https://dev.to/josephschmitt/looking-in-to-swiftui-220</link>
      <guid>https://dev.to/josephschmitt/looking-in-to-swiftui-220</guid>
      <description>&lt;p&gt;One of the most exciting things to come out of the last couple WWDC's is Swift UI. If you're unfamiliar, it's a UI framework that makes writing UI code much lighter and easier by using a lot of concepts that have been popularized by things such as React.&lt;/p&gt;

&lt;p&gt;Swift UI is clearly the future of Apple's platforms, and since I'm learning this stuff from scratch anyway, I may as well embrace the future. So my new app will be written in as close to 100% Swift UI as I can manage, and require iOS 14.&lt;/p&gt;

&lt;p&gt;But, now I've just added something else I have to learn. Luckily, it seems like a lot of Swift UI's syntax is built upon the basics of Swift, so learning both together shouldn't be too bad.&lt;/p&gt;

&lt;p&gt;The first thing I did was to try and figure out what all Swift UI is capable of. Luckily Apple has some great tutorials over on &lt;a href="https://developer.apple.com/tutorials/swiftui"&gt;their developer site&lt;/a&gt; to help get started. These have been an invaluable resource and I'll be sure to reference them as I get going.&lt;/p&gt;

&lt;p&gt;The other place I've been spending my time to try to get my head around what SwiftUI can do is on &lt;a href="https://www.youtube.com/channel/UCmJi5RdDLgzvkl3Ly0DRMlQ"&gt;Paul Hudson's YouTube channel&lt;/a&gt;. These have been &lt;em&gt;especially&lt;/em&gt; great. I'm not sure what it is about his explanation style, but his videos have led to more "aha!" moments when it comes to understanding the major concepts than most.&lt;/p&gt;

&lt;p&gt;I started out with this &lt;a href="https://youtu.be/nA6Jo6YnL9g"&gt;video on &lt;code&gt;NavigationView&lt;/code&gt;&lt;/a&gt;, which is one of the simplest and most basic concepts in a UI stack. A few of the major things I learned here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;navigationBarTitle()&lt;/code&gt; is called on a view &lt;em&gt;inside&lt;/em&gt; the &lt;code&gt;NavigationView&lt;/code&gt;, not on the view itself. Why? Because a &lt;code&gt;NavigationView&lt;/code&gt; can contain many sub-views, and each sub-view could/should/will have it's own title. This means that the following simple &lt;code&gt;NavigationView&lt;/code&gt; stack looks a bit weird:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;Navigation&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&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;Looking at this code you would think you'd apply &lt;code&gt;.navigationBarTitle&lt;/code&gt; on the &lt;code&gt;NavigationView&lt;/code&gt; itself. But this is simply because SwiftUI is handling something really clever: everything is a View. Views are the most basic foundation of SwiftUI, and so when you create a &lt;code&gt;Text()&lt;/code&gt; it's actually not just creating the text itself, but also the entire wrapping view the text lives in. So as your &lt;code&gt;NavigationView&lt;/code&gt; hierarchy gets more complex, this makes more sense:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;ContentView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;some&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;NavigationView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;First&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="kt"&gt;VStack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;Hello&lt;/span&gt; &lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;again&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigationBarTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="kt"&gt;Second&lt;/span&gt; &lt;span class="kt"&gt;View&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&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;Now it's easier to see what's going on, and why we'd want to apply the title to a sub-view and not the &lt;code&gt;NavigationView&lt;/code&gt; itself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NavigationLink&lt;/code&gt; seems to be the way SwiftUI wants you to dig into and out of &lt;code&gt;NavigationView&lt;/code&gt; stacks. But, you can get around this and use custom &lt;code&gt;Buttons&lt;/code&gt;'s if you bind them to certain variables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I left the video with a bunch of questions, though. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why does the wrapping view struct implement the &lt;code&gt;View&lt;/code&gt; protocol as &lt;code&gt;struct ContentView: View&lt;/code&gt;, while the &lt;code&gt;body&lt;/code&gt; property does &lt;code&gt;body: some View&lt;/code&gt;? What does &lt;code&gt;some View&lt;/code&gt; mean?&lt;/li&gt;
&lt;li&gt;In the video he applied some decorators to his variables like &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@ObservableObject&lt;/code&gt; which I have no idea what they do. He also sometimes passed a variable as it was named, and sometimes with a &lt;code&gt;$&lt;/code&gt; in front of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's fine, I've only just started looking at SwiftUI code, let alone understanding it.&lt;/p&gt;

&lt;p&gt;And it just so happens that there's a video on the same channel that explains this: &lt;a href="https://youtu.be/stSB04C4iS4"&gt;What's the difference between @State, @ObjectBinding, and @EnvironmentObject?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This video was &lt;em&gt;awesome&lt;/em&gt;, and it explained so many wonderful things to me&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SwiftUI's views are all structs, not classes.&lt;/p&gt;

&lt;p&gt;Why is that important? Because a &lt;code&gt;struct&lt;/code&gt; is &lt;em&gt;passed by value&lt;/em&gt; whereas a &lt;code&gt;class&lt;/code&gt; is &lt;em&gt;passed by reference&lt;/em&gt;. Additionally, once you've created a struct, it's immutable and can't change. This makes sense if you think about it in terms of another type of struct, a &lt;code&gt;number&lt;/code&gt;. Once you create the number &lt;code&gt;5&lt;/code&gt;, you can't change what the number &lt;code&gt;5&lt;/code&gt; means. This is different to a &lt;code&gt;class&lt;/code&gt; which is instantiated and its location in memory is referenced. Once you initialize a &lt;code&gt;class&lt;/code&gt;, not only can you update its properties, but all other references to that same &lt;code&gt;class&lt;/code&gt; &lt;em&gt;instance&lt;/em&gt; will also instantly get those changes.&lt;/p&gt;

&lt;p&gt;How does this relate to structs? Well, if our view structs were permanently immutable, then we'd never be able to update them with new data. To solve this issue, SwiftUI provides the &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@ObjectBinding&lt;/code&gt; decorators. What these do is they tell SwiftUI that &lt;em&gt;these specific variables&lt;/em&gt; might change, and if they do, then the View should re-render.&lt;/p&gt;

&lt;p&gt;What's the difference between &lt;code&gt;@State&lt;/code&gt; and &lt;code&gt;@ObjectBinding&lt;/code&gt;? Simple: a &lt;code&gt;@State&lt;/code&gt; has one-way binding, meaning data only flows one direction, while &lt;code&gt;@ObjectBinding&lt;/code&gt; has two-way binding, meaning it can change in both directions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This also answers the question I had earlier about why some variables had a &lt;code&gt;$&lt;/code&gt; in front of them. When they do, it means that they're bound, and therefore should be monitored for changes. Without it, the compiler will just fix them to their value during compile time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;These videos have been hugely helpful so far, and Paul is a joy to watch. I'll be checking out more of &lt;a href="https://www.youtube.com/playlist?list=PLuoeXyslFTuaZtX7xSYbWz3TR0Vpz39gK"&gt;his SwiftUI videos&lt;/a&gt; as I learn. But I think at this point I understand enough of the code being written in these videos that I can start prototyping some parts of my app. The best way to learn is by doing.&lt;/p&gt;

</description>
      <category>swiftui</category>
      <category>programming</category>
      <category>devdiary</category>
    </item>
    <item>
      <title>A (new) place to start</title>
      <dc:creator>Joe Schmitt</dc:creator>
      <pubDate>Mon, 29 Jun 2020 14:02:35 +0000</pubDate>
      <link>https://dev.to/josephschmitt/a-new-place-to-start-5c4g</link>
      <guid>https://dev.to/josephschmitt/a-new-place-to-start-5c4g</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of a (hopefully) long-running series of Dev Diary entires on my process of teaching myself Swift and Swift UI in order to build an app.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The past 13+ years of my career have been defined by constantly starting new things. In school, I thought I was going to be an interactive UI designer, designing the most beautiful and fluid interactive Flash (lol) web experiences you'd ever seen. But I discovered an itch for building instead of designing, and so taught myself to program instead (ActionScript at the time).&lt;/p&gt;

&lt;p&gt;My first job right out of school then was as an Interactive Developer, despite getting a BFA in design. Not coming from a programming background and holding a programming job was terrifying, but the thrill to learn kept me at it, and I ended up building some &lt;a href="https://thefwa.com/cases/mario-kart-wii-experience"&gt;amazing&lt;/a&gt; &lt;a href="https://thefwa.com/cases/wario-land-shake-it"&gt;projects&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But mastery over Flash and ActionScript was not job security, and sure enough a few years later Flash fell out of favor (rightly so, it had &lt;em&gt;so&lt;/em&gt; many problems) and web standards was the new hotness. So I buckled down and learned HTML, CSS, and JavaScript. Soon I was building &lt;a href="https://vimeo.com/blog/post/introducing-vimeo-music-store/"&gt;cool new products&lt;/a&gt; using &lt;a href="https://www.wired.com/2010/08/vimeo-spreads-the-html5-love-with-web-native-video-player/"&gt;web standards&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And on and on it went: learning C and Objective-C, Angular (when that was a thing), ES6, NodeJS, TypeScript, etc.&lt;/p&gt;

&lt;p&gt;My favorite thing to tell new engineers that get frustrated by how often and quickly this field changes is this: because everything is constantly new, it means you're only ever 2 years behind the experts. Everyone is new at it, and every new start gives you an opportunity to be successful again.&lt;/p&gt;

&lt;p&gt;And so here I am again looking towards another new start. But this time it's not driven by career advancement, but more just general curiosity. I've been wanting to scratch a specific itch of an App idea I've had for a few years, and all the new stuff Apple announced at &lt;a href="https://developer.apple.com/wwdc20/"&gt;WWDC 2020&lt;/a&gt; got me excited enough to try it out.&lt;/p&gt;

&lt;p&gt;So I'm going to try something new again, but this time, two-fold: I'm going to teach myself Swift and &lt;a href="https://developer.apple.com/tutorials/swiftui"&gt;SwiftUI&lt;/a&gt; while trying to build an app, and I'm going to document my learning and building process in public. My hope is that anyone reading this (and my future struggles and learnings) will be able to glean some kind of insight into how to learn something new.&lt;/p&gt;

&lt;p&gt;And so here's to a(nother) new beginning.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>swiftui</category>
      <category>career</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
