<?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: Garrin Costa, Jr.</title>
    <description>The latest articles on DEV Community by Garrin Costa, Jr. (@gmcjr).</description>
    <link>https://dev.to/gmcjr</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3892762%2Fee42a687-4cd8-4265-ac77-af583fb876b8.jpeg</url>
      <title>DEV Community: Garrin Costa, Jr.</title>
      <link>https://dev.to/gmcjr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gmcjr"/>
    <language>en</language>
    <item>
      <title>Audio Development and C++</title>
      <dc:creator>Garrin Costa, Jr.</dc:creator>
      <pubDate>Thu, 16 Jul 2026 18:04:00 +0000</pubDate>
      <link>https://dev.to/gmcjr/audio-development-and-c-5d2j</link>
      <guid>https://dev.to/gmcjr/audio-development-and-c-5d2j</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;I came into programming from a background in music production and audio engineering. I'd been interested in programming for a long time, but only in the last couple of years have I dug in seriously, working primarily in JavaScript and its libraries and frameworks. I wanted to go deeper and there are so many compelling paths. Of all of them, C++ emerged as a logical next step.&lt;/p&gt;

&lt;p&gt;Coming from JavaScript, C++ felt more familiar than I expected. Both derive their basic syntax from C, so control structures like &lt;code&gt;if-else&lt;/code&gt; and &lt;code&gt;for&lt;/code&gt; loops look familiar. Both support object-oriented programming through classes and methods, and both support functional concepts like first-class functions and closures. But what really caught my attention was noticing the role C++ was playing in audio development. Once I started looking, it kept turning up, in the plugins I use and in the DAWs that host them.&lt;/p&gt;

&lt;p&gt;So what makes C++ so widely used in this area? What problems arise in audio development that C++ solves, and what makes it well-suited to solve them?&lt;/p&gt;

&lt;h3&gt;
  
  
  C++, briefly
&lt;/h3&gt;

&lt;p&gt;C++ was designed by Bjarne Stroustrup at AT&amp;amp;T Bell Labs and had its first commercial release in 1985, as an extension of C with object-oriented features added on top. It has since expanded to include functional features and facilities for low-level memory manipulation. It compiles ahead of time to machine code rather than being interpreted at runtime, and it is standardized internationally as ISO/IEC 14882, maintained by the ISO/IEC working group JTC1/SC22/WG21.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audio processing and deadlines
&lt;/h3&gt;

&lt;p&gt;Audio processing runs on a fixed deadline. In the browser, for example, the Web Audio API processes sound in blocks of 128 sample-frames, which works out to roughly 3ms of audio at a sample rate of 44.1kHz (128 samples ÷ 44,100 samples per second ≈ 2.9ms). If a block isn't finished before the next one is needed, the hardware is forced to play back stale data, silence, or interpolated samples, resulting in audible clicks, pops, or dropouts. Everything below follows from this constraint.&lt;/p&gt;

&lt;h3&gt;
  
  
  Garbage collection
&lt;/h3&gt;

&lt;p&gt;Languages with a garbage collector, including JavaScript, clean up unused memory automatically. A background process decides when to run, and while it runs it can pause the whole program. The pause is brief, but its timing and length are unpredictable, and under a deadline of a few milliseconds, the risk of running into even a brief pause is unacceptable.&lt;/p&gt;

&lt;p&gt;This is a major problem that C++ solves, as it has no garbage collector. A program allocates and frees memory as needed, happening exactly where the programmer writes them, rather than being left to the timing of a background process. The catch is that allocating can itself take an unpredictable amount of time, so real-time audio code goes a step further and moves every allocation out from under the deadline, doing it all before playback begins. &lt;/p&gt;

&lt;p&gt;JUCE, a C++ framework for building audio plugins, builds its plugin structure around this. Its AudioProcessor class gives a plugin two functions with two different jobs. prepareToPlay() runs once, before playback starts, and the host tells it roughly how large the audio blocks are going to be. That's the moment the plugin sets aside all the memory it will need, mainly its buffers, the arrays that hold each block of samples while the plugin works on them. processBlock() then runs over and over during playback, once per block, under the deadline, doing the actual audio processing with memory that already exists. Since nothing in C++ allocates except what the code explicitly allocates, keeping every allocation in prepareToPlay() leaves processBlock() with no hidden step that could stall it, ensuring no calls to new, malloc, or vector reallocations occur during playback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoiding locks on the audio thread
&lt;/h3&gt;

&lt;p&gt;The garbage collection problem above is about one kind of unpredictable pause. Another kind comes from threads.&lt;/p&gt;

&lt;p&gt;A thread is a single sequence of instructions that a CPU executes, one after another. A program can run more than one thread at once, each with its own place in the code, while sharing access to the same memory. This is how an audio plugin is built. One thread might run the user interface (drawing knobs, handling clicks), and a separate audio thread is called by the host repeatedly to fill each block of samples. Both run at the same time, possibly on different CPU cores, and both can see the same variables. &lt;/p&gt;

&lt;p&gt;This situation is less common in standard JavaScript, where the main execution thread processes one statement at a time via an event loop.  While Web Workers and AudioWorklets now allow multi-threading in the browser, the standard model for UI and logic remains single-threaded, whereas C++ audio plugins require parallel threads for UI and DSP from the start. An audio plugin's UI and audio threads run in parallel, and any data they share has to be coordinated.&lt;/p&gt;

&lt;p&gt;Two threads reading and writing the same variable at the same time can corrupt it. One way to prevent this is through a mutex, short for mutual exclusion, which is a lock that guarantees only one thread can access a piece of shared data at a time. A thread has to acquire the lock before it can touch the shared data. If another thread already holds the lock, the second thread waits until the first releases it with an unlock operation.&lt;/p&gt;

&lt;p&gt;Mutexes are a standard synchronization tool in most multithreaded software, and for good reason. However, for audio code, the wait behavior of a mutex creates a major problem because it has no time limit. When the audio thread needs a lock that the UI thread happens to be holding, and the UI thread gets paused by the OS scheduler or just takes longer than expected, the audio thread sits blocked for as long as that takes, and the deadline passes. This failure mode, where a high-priority thread ends up waiting on a low-priority one, is called priority inversion, and it's the main reason real-time audio code avoids mutexes.&lt;/p&gt;

&lt;p&gt;For passing a single value between the two threads, like a plugin parameter, the common alternative to a mutex is an atomic variable. At the lowest level, &lt;code&gt;std::atomic&lt;/code&gt; wraps a variable to ensure that read and write operations are &lt;strong&gt;indivisible&lt;/strong&gt;.  When you call &lt;code&gt;load()&lt;/code&gt; or &lt;code&gt;store()&lt;/code&gt; on an atomic variable (like &lt;code&gt;std::atomic&amp;lt;float&amp;gt;&lt;/code&gt; as opposed to plain &lt;code&gt;float&lt;/code&gt;), the compiler translates this into a single CPU instruction that cannot be interrupted. A plugin's gain parameter, for example, would be declared as a &lt;code&gt;std::atomic&amp;lt;float&amp;gt;&lt;/code&gt;. When the user moves the gain knob, the UI thread writes a new value into it. Each time the audio thread runs &lt;code&gt;processBlock()&lt;/code&gt; to fill a block of samples, it reads the current value and applies it to the audio.&lt;br&gt;
To ensure this remains lock-free on all hardware and prevents instruction reordering, production code typically uses std::memory_order_release on the write and std::memory_order_acquire on the read.&lt;/p&gt;

&lt;p&gt;No mutex is needed because of what "atomic" guarantees. An &lt;strong&gt;ordinary&lt;/strong&gt; write to memory can take more than one CPU operation to complete, and a thread reading at the wrong moment can catch the write partway through, picking up a value that is part old number and part new, a number that was never written. That torn value is the corruption a &lt;strong&gt;mutex&lt;/strong&gt; exists to prevent. An &lt;strong&gt;atomic&lt;/strong&gt; read or write completes as a single, &lt;strong&gt;indivisible&lt;/strong&gt; operation, so the audio thread always gets either the complete old value or the complete new one. The protection the lock provided is built into the operation itself, so there's nothing left to guard and no waiting to do. The UI thread writes whenever the user turns the knob, the audio thread reads whenever it needs to, and neither one ever blocks the other. This approach, coordinating threads without any locks, is called &lt;strong&gt;lock-free&lt;/strong&gt; programming, and it's the standard way code running on the audio thread shares data with the rest of the program. To ensure the CPU doesn't reorder these operations and break the logic, production code typically pairs the write with std::memory_order_release and the read with std::memory_order_acquire. &lt;/p&gt;

&lt;p&gt;However, while atomics guarantee thread safety, they do not prevent audio artifacts. If the parameter value changes instantly between samples, it creates a discontinuity known as a 'click.' Therefore, the atomic variable should strictly serve as the target value. Inside the audio loop, the processor must read this target and then smoothly interpolate (or 'slew') the actual processing parameter toward it over a few milliseconds, ensuring the audio signal remains continuous even when the control data changes abruptly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct access to plugin SDKs and OS audio layers
&lt;/h3&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxm2m7945txp5hctumhc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbxm2m7945txp5hctumhc.jpg" alt="Pro Tools DAW with open plugins" width="800" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Plugin formats are defined as C++ (or C-ABI-over-C++) interfaces. Steinberg distributes the VST3 SDK directly, built on COM-style interfaces implemented in C++.  Avid’s AAX format, used by Pro Tools, expects its plugin developers to work in object-oriented C++. Native Instruments maintains ni-media, an open-source C++ library for reading and writing audio streams, and its NKS standard operates as a metadata specification that enriches standard VST3 and Audio Unit plugins with hardware integration, keeping them on the same C++ foundation.&lt;/p&gt;

&lt;p&gt;Below the plugin formats sit the operating systems' own audio layers, which follow a similar hybrid model. On macOS, Core Audio handles the system's audio through pure C programming interfaces, though Apple provides an optional C++ SDK to wrap these APIs for easier development. On Windows, low-latency audio goes through ASIO, a driver protocol developed by Steinberg, with an SDK likewise written in C/C++. A C++ audio engine talks to the plugin host above it and the operating system below it primarily in its own language. However, to ensure stability across different compilers, these interactions cross ABI boundaries (such as COM on Windows or C-interfaces on macOS), acting as a standardized translation layer that allows C++ code to interoperate safely without binary incompatibility.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layered architecture
&lt;/h3&gt;

&lt;p&gt;Not everything in audio software is written this way, and the exceptions are informative. Cycling '74's Max/MSP is a visual, patch-based environment. Its SDK supplies the headers, source, and libraries for building external objects (plug-ins) in C or C++, so the underlying engine and its high-performance extensions are C/C++, while the patching layer end users work in is not. &lt;/p&gt;

&lt;p&gt;Ableton's Max for Live integration adds another layer of abstraction. While the DSP inside a Max device may still rely on C++ (via the Max engine or gen~), controlling the host application itself happens through the Live Object Model. This is accessed via specific Max objects or a JavaScript interface, meaning the plugin author can script complex interactions with Ableton Live without writing a single line of C++. &lt;/p&gt;

&lt;p&gt;This demonstrates a consistent industry pattern: C++ dominates the DSP and engine layers where nanosecond timing is critical, while higher-level scripting layers (JavaScript, Python, Lua) are deliberately used for control logic, UI, and arrangement, as these tasks are not bound by the real-time audio deadline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shortcomings
&lt;/h3&gt;

&lt;p&gt;Manual memory management brings inherent risks such as forgetting to free memory, freeing it twice, or accessing it after release. These bugs can be subtle and difficult to track down, often requiring rigorous discipline or modern C++ idioms like RAII to mitigate. &lt;/p&gt;

&lt;p&gt;C++ also lacks a standardized ABI (Application Binary Interface), meaning the memory layout of a compiled class or function call is not guaranteed to match across different compilers or versions. Plugin formats must design around this limitation.  VST3, for instance, separates the audio processing component (IAudioProcessor) from the UI controller (IEditController) behind defined COM-style interfaces. This creates a stable binary contract—a "translation layer"—that allows a host and plugin to communicate safely without relying on raw C++ class layouts at the boundary.&lt;/p&gt;

&lt;p&gt;Finally, the language is significantly more verbose than many modern alternatives. It demands a deep understanding of systems programming concepts, resulting in a steeper learning curve and longer development times compared to higher-level languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Problems
&lt;/h3&gt;

&lt;p&gt;Audio development also faces challenges that the language itself cannot fix. &lt;/p&gt;

&lt;p&gt;Format Fragmentation remains a major hurdle.  VST3, AU, and AAX are separate, largely incompatible standards, forcing developers to build and test each plugin multiple times. CLAP, an open, MIT-licensed format launched in 2022 by Bitwig and u-he, was created to solve this.  Adoption has grown rapidly: Bitwig, REAPER, and FL Studio now fully support it, with Studio One and Cubase following suit.  However, industry giants like Ableton Live, Pro Tools, and Logic Pro still do not support it, ensuring a multi-format world for the foreseeable future. &lt;/p&gt;

&lt;p&gt;Denormal numbers represent a lower-level hardware quirk.  Extremely small floating-point values near zero can force CPUs into a slow "microcode" path, causing massive performance spikes. Preventing this still falls to the programmer—typically by enabling "flush-to-zero" CPU flags or adding a tiny, inaudible noise floor to the signal—rather than being handled automatically by the language or compiler. &lt;/p&gt;

&lt;p&gt;Rust is the most frequently named alternative to C++ for this work. Its ownership system guarantees memory safety without a garbage collector, meeting the same real-time requirements as C++. While early frameworks like nih-plug focused on VST3 and CLAP, newer frameworks (e.g., truce) now offer native support for AU and AAX as well.  Despite this technical maturity, Rust’s audio ecosystem remains a fraction of C++’s decades-old library collection. Whether it achieves mainstream adoption depends less on the language itself—which already handles the central requirements—and more on how quickly its ecosystem and tooling fill the remaining gaps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Summary
&lt;/h3&gt;

&lt;p&gt;Audio code has a few milliseconds to produce each block of samples, and that one constraint accounts for most of what this piece covered. A language running on the audio thread can't have a garbage collector pausing it at unpredictable times, can't afford to wait on locks, and benefits from sharing a language with the plugin formats and OS audio layers it connects to. C++ meets all of those conditions, and the industry's foundations, from VST3 and AAX to Core Audio and ASIO to JUCE, are already written in it. Where the deadline doesn't reach, as in Max/MSP's patching layer and Max for Live's JavaScript API, the same industry uses friendlier languages, which says a lot about why C++ holds the real-time layer in particular. The language costs something in return, in memory bugs, binary incompatibility, and time spent learning it. While new formats like CLAP are gaining traction in FL Studio and Studio One, and languages like Rust now offer native AU and AAX support via frameworks like truce, the work on the audio thread still gets written in C++.&lt;/p&gt;

&lt;p&gt;Sources: Web Audio API specification, W3C CR-webaudio-20180918 (w3.org/TR); C++ history and ISO/IEC 14882, en.wikipedia.org and stroustrup.com; JUCE AudioProcessor class reference (docs.juce.com); MDN Web Docs, "JavaScript execution model" and "Concurrency model and Event Loop" (developer.mozilla.org); Ross Bencina, "Real-time audio programming 101: time waits for nothing" (rossbencina.com); Fabian Renn-Giles, "Using locks in real-time audio processing, safely" (timur.audio); Steinberg VST3 SDK (github.com/steinbergmedia/vst3sdk) and VST3 architecture documentation (deepwiki.com/steinbergmedia/vst3_public_sdk); Avid AAX developer/alliance documentation (developer.avid.com); Native Instruments GitHub (ni-media) and NKS developer page (native-instruments.com); Apple Core Audio Overview and Core Audio Essentials (developer.apple.com/library/archive); Steinberg ASIO driver documentation (helpcenter.steinberg.de); Cycling '74 max-sdk GitHub repository; Ableton Help Center, "Controlling Live using Max for Live" (help.ableton.com); CLAP announcement (bitwig.com) and CLAP adoption status (producergrid.com); Rust ownership documentation (doc.rust-lang.org/book); nih-plug ProducerGrid, (CLAP Plugin Format: Everything Music Producers Need to Know in 2026); truce.audio Documentation and GitHub Repository (truce-audio/truce); Intel® 64 and IA-32 Architectures Optimization Reference Manual (Section on MXCSR/FTZ/DAZ flags) or Stack Overflow, "Flushing denormalised numbers to zero". &lt;/p&gt;

</description>
      <category>cpp</category>
      <category>dsp</category>
      <category>audiodev</category>
      <category>vst</category>
    </item>
    <item>
      <title>On Optimization Objectives in Reinforcement Learning</title>
      <dc:creator>Garrin Costa, Jr.</dc:creator>
      <pubDate>Thu, 11 Jun 2026 19:26:10 +0000</pubDate>
      <link>https://dev.to/gmcjr/on-optimization-objectives-in-reinforcement-learning-44ba</link>
      <guid>https://dev.to/gmcjr/on-optimization-objectives-in-reinforcement-learning-44ba</guid>
      <description>&lt;h1&gt;
  
  
  Reinforcement Learning: Optimization and Objective Methods
&lt;/h1&gt;

&lt;p&gt;There are a few paradigms or methods of training involved in machine learning. Each employs a different approach to presenting a model with data and what the model should do with that input. Reinforcement learning is one such method we will explore in more detail. &lt;/p&gt;

&lt;p&gt;In supervised learning, you give the model labeled example data and then test the model with examples it has not yet seen. Think of it like studying with access to an answer key. In unsupervised learning, you give the model unlabeled data and it finds structure. Imagine watching a painting in pointillism render from start to finish. There's no order to it in the beginning. Eventually though, you might start to recognize an image forming. From there you might have an easier time predicting what the finished painting will look like.&lt;/p&gt;

&lt;p&gt;Reinforcement learning (RL) takes a different approach, in that there may be no explicit training data provided as examples - labelled or unlabelled. Rather, the input data received comes as progression of its own experience. The agent makes decisions, interacts directly with an environment, and receives feedback as a reward or penalty signal. It is essentially training by trial and error. &lt;/p&gt;

&lt;p&gt;(&lt;em&gt;minecraft gif&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;By aiming to maximize cumulative reward over time, the agent 'learns' how to behave in a given environment. This seems simple in theory but in practice, it’s one of the harder optimization problems in ML. You’re not minimizing a fixed loss function over a static dataset. The data the agent trains on depends on the actions it took, which depend on the policy it’s currently learning, which depends on the data it collected. It’s circular by design, and that circularity is where most of the difficulty comes from.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Agent Is Actually Optimizing
&lt;/h2&gt;

&lt;p&gt;Looking at RL objectives, we have the policy (the agent’s decision-making function), a discount factor between 0 and 1, and the reward at a specific time. The discount factor controls how much the agent weights future rewards versus immediate ones. If it is too low, it becomes concerned with only the next reward. Too high and it treats rewards 100 steps away as nearly equivalent to rewards right now. Balance is generally the ideal.&lt;/p&gt;

&lt;p&gt;This works differently from supervised ML objectives like MSE or cross-entropy. Those are computed over a fixed dataset — you know what you’re optimizing against before training starts. In RL, the objective depends on trajectory data the agent generates during training. You’re optimizing a target that shifts as the agent improves, using data the agent collected under an earlier, 'worse' version of itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three Approaches to Optimization
&lt;/h2&gt;

&lt;p&gt;There are three broad families of RL algorithms, each one taking a unique approach addressing policy improvement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Value-based methods&lt;/strong&gt; estimate how good each state or state-action pair is, then derive a policy from those estimates. The foundational example here is Q-learning: the agent learns a Q-function — Q(s, a) — that estimates expected future reward for taking action &lt;code&gt;a&lt;/code&gt; in state &lt;code&gt;s&lt;/code&gt;. Policy improvement is implicit: pick the action with the highest Q-value. The optimization objective is minimizing the Bellman error*, the difference between the current Q-value estimate and the target computed from actual experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Policy gradient methods&lt;/strong&gt; skip the value estimates and optimize the policy directly. They compute the gradient of J(π) with respect to the policy parameters and step in that direction. REINFORCE* is the classic version. The problem that arises here is policy gradients have high variance, especially early in training when the agent has seen little of the environment. The gradient estimates are noisy, and that noise slows convergence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actor-critic methods&lt;/strong&gt; combine both. The actor is the policy and decides actions. The critic is a value function and evaluates how good those actions were. The critic’s estimates reduce variance in the actor’s gradient updates. Most production-grade RL systems — PPO, A3C, SAC — are actor-critic architectures for exactly this reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems in Practice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Credit assignment:&lt;/strong&gt;  An agent plays a game and wins 200 moves later. Which moves mattered? The reward is clear but the attribution is not. Discount factors and value functions both exist, in part, to address this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exploration vs. exploitation:&lt;/strong&gt; An agent that only takes actions it already knows are good stops learning. An agent that constantly explores won’t converge on anything useful. Balancing these two is a design decision. Common approaches include epsilon-greedy exploration (taking a random action with probability ε) and entropy regularization (adding a term to the objective that rewards taking varied actions).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sample efficiency:&lt;/strong&gt; RL needs a lot of experience to learn from. A person can pick up a new video game and achieve competence in under an hour. A RL agent usually needs millions of environment interactions to do something similar. Model-based RL addresses this by building an internal model of the environment and planning ahead from it, rather than learning purely from direct experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reward Design as the Objective Function
&lt;/h2&gt;

&lt;p&gt;Clean mathematical formulation glosses over the fact that in most real RL problems, you don’t have a natural reward function. You must design one. Designing an effective reward function can be painful.&lt;/p&gt;

&lt;p&gt;The agent optimizes whatever you give it. If you reward a robot arm for moving toward a target but don’t penalize inefficient paths, it finds paths that increase the reward metric without doing what you wanted. This may not be a bug in the algorithm so much as it is the algorithm working correctly on a poorly defined objective.&lt;/p&gt;

&lt;p&gt;A good example comes from OpenAI’s early research: an agent trained to move fast in a simulated environment learned to make itself tall and then fall over repeatedly, because falling generated high velocity without the actual cost of locomotion. The reward function said “go fast,” and it did.&lt;/p&gt;

&lt;p&gt;This connects directly to a concept in a supervised ML context where objective functions and performance metrics are often different things. You optimize one to improve the other, and they don’t always agree on which model is best. In RL that gap is almost always present. The reward function you are optimizing is in general terms, an approximation, of the end goal, and the agent will find every corner case where the approximation breaks down.&lt;/p&gt;

&lt;h2&gt;
  
  
  How This Connects to Standard ML
&lt;/h2&gt;

&lt;p&gt;RL uses the same building blocks covered in core ML such as neural networks as function approximators, gradient descent for parameter updates, regularization to prevent overfitting (entropy terms work similarly to L2 penalties), and held-out evaluation environments that parallel cross-validation. The main difference is the sequential, interactive data collection process.&lt;/p&gt;

&lt;p&gt;Standard supervised learning assumes training data is independent and identically distributed. RL violates that assumption constantly. Each action changes the state of the environment, which affects what data gets collected next. The dataset and the model are coupled. That’s what makes RL its own subfield rather than just another model type — but the mathematical machinery underneath it is mostly the same machinery covered everywhere else in ML.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source material: M. Clark, Models Demystified — &lt;a href="https://m-clark.github.io/book-of-models/machine_learning.html" rel="noopener noreferrer"&gt;Chapter 10: Core Concepts in Machine Learning&lt;/a&gt; and &lt;a href="https://m-clark.github.io/book-of-models/ml_common_models.html" rel="noopener noreferrer"&gt;Chapter 11: Common Models in Machine Learning&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*This is the Bellman equation. It may be simplified even further if the time subscripts are dropped and the value of the next state is plugged in:&lt;/p&gt;

&lt;p&gt;V(x)=maxa∈Γ(x){F(x,a)+βV(T(x,a))}.&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwikimedia.org%2Fapi%2Frest_v1%2Fmedia%2Fmath%2Frender%2Fsvg%2Fb4538aab2a60e60f907534e02507bec4d8ecdde0" 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%2Fwikimedia.org%2Fapi%2Frest_v1%2Fmedia%2Fmath%2Frender%2Fsvg%2Fb4538aab2a60e60f907534e02507bec4d8ecdde0" alt="{\displaystyle V(x)=\max _{a\in \Gamma (x)}\{F(x,a)+\beta V(T(x,a))\}.}" width="38" height="4"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reinforcementlearning</category>
      <category>machinelearning</category>
      <category>algorithms</category>
      <category>neuralnetwork</category>
    </item>
    <item>
      <title>Know Your Environment: Building Fluency with Shortcuts, Terminals, and Git</title>
      <dc:creator>Garrin Costa, Jr.</dc:creator>
      <pubDate>Tue, 02 Jun 2026 14:09:43 +0000</pubDate>
      <link>https://dev.to/gmcjr/know-your-environment-building-fluency-with-shortcuts-terminals-and-git-5da0</link>
      <guid>https://dev.to/gmcjr/know-your-environment-building-fluency-with-shortcuts-terminals-and-git-5da0</guid>
      <description>&lt;p&gt;&lt;code&gt;Cmd+C&lt;/code&gt;, &lt;code&gt;Cmd+V&lt;/code&gt;, &lt;code&gt;Cmd+Z&lt;/code&gt; — the basics settle into procedural memory quickly. Beyond that, most shortcuts remain things we intend to learn eventually.&lt;/p&gt;

&lt;p&gt;The resources are easy to find. Most applications expose shortcuts directly in their menus, publish reference pages, and allow custom key bindings. Yet a 2005 study by Lane, Napier, Peres, and Sandor found that even experienced users relied on keyboard shortcuts less than 10% of the time, and that time spent using a program had little relationship with keyboard shortcut proficiency. Exposure alone doesn't build skill.&lt;/p&gt;

&lt;p&gt;What builds it is intentional repetition — and a willingness to be slower before you're faster. Fitts and Posner's three-stage model of skill acquisition describes the progression: &lt;em&gt;cognitive&lt;/em&gt; (active recall, slower execution), &lt;em&gt;associative&lt;/em&gt; (familiarity forming, still requires attention), &lt;em&gt;autonomous&lt;/em&gt; (fires without thought). Remington, Yuen, and Pashler put a number on the crossover: after roughly 200 repetitions, keyboard shortcuts became consistently faster than menu navigation. A new shortcut might cost you a beat every time you reach for it on day one. By the end of the first week of consistent use, that friction is mostly gone.&lt;/p&gt;

&lt;p&gt;For developers working in digital environments all day, the environment itself is part of the work. Every unnecessary trip through a menu is a small interruption. Repeated across a session, across a week, those costs are real — and avoidable.&lt;/p&gt;

&lt;p&gt;What follows is a practical reference organized by layer: operating system, browser, VS Code, terminal, and Git. The goal is not completeness, but a high-value subset of shortcuts and workflows that address genuine friction in day-to-day development.&lt;/p&gt;




&lt;h2&gt;
  
  
  Operating System
&lt;/h2&gt;

&lt;p&gt;Developers move constantly between editors, terminals, browsers, documentation, and communication tools. A handful of OS-level shortcuts reduces the overhead of that navigation significantly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;th&gt;Windows/Linux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Switch applications&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Tab&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt+Tab&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch windows (same app)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Cmd+&lt;/code&gt;&lt;code&gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt+Esc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open system search&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Space&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Win+S&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hide application&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+H&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Win+D&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Minimize current window&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+M&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Win+↓&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Quit application&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Q&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt+F4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screenshot / screen capture&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Win+Shift+S&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Spotlight (&lt;code&gt;Cmd+Space&lt;/code&gt;) deserves particular attention. It launches applications, locates files, performs calculations, and searches system settings — all without leaving the keyboard or touching the Dock or Finder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Window Management
&lt;/h3&gt;

&lt;p&gt;macOS Sequoia introduced native tiling via drag-to-edge. For keyboard-driven window management with more control, &lt;a href="https://rectangleapp.com/" rel="noopener noreferrer"&gt;Rectangle&lt;/a&gt; (free) and &lt;a href="https://magnet.crowdcafe.com/" rel="noopener noreferrer"&gt;Magnet&lt;/a&gt; (paid) both provide configurable shortcuts for snapping windows to halves, thirds, corners, and specific displays.&lt;/p&gt;

&lt;p&gt;A typical development layout — editor on one side, browser or DevTools on the other, terminal on a second display — can be arranged entirely from the keyboard. Once those positions are muscle memory, context switching between tools stops requiring any deliberate navigation.&lt;/p&gt;

&lt;h2&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%2F6wx6bfl8g97mfqxpmi1l.png" alt="Multiple windows tiled between two screens" width="800" height="269"&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Browser
&lt;/h2&gt;

&lt;p&gt;Browsers function as documentation readers, debugging environments, and research platforms throughout a development session.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;th&gt;Windows/Linux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Focus address bar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+L&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New tab&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+T&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Close current tab&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+W&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reopen closed tab&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+T&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+T&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch to tab 1–9&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+1–9&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+1–9&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Navigate back / forward&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Cmd+[&lt;/code&gt; / &lt;code&gt;Cmd+]&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Alt+←&lt;/code&gt; / &lt;code&gt;Alt+→&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hard refresh (bypass cache)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+R&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open DevTools — elements&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Opt+I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+I&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open DevTools — console&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Opt+J&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+J&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find on page&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+F&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Cmd+Opt+J&lt;/code&gt; / &lt;code&gt;Ctrl+Shift+J&lt;/code&gt; opens DevTools directly to the console — no clicking through panels. For frontend work specifically, that one earns its place in muscle memory fast.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cmd+L&lt;/code&gt; / &lt;code&gt;Ctrl+L&lt;/code&gt; focuses the address bar immediately. Combined with typing a URL or search term and pressing Enter, it removes the mouse from routine browser navigation entirely.&lt;/p&gt;




&lt;h2&gt;
  
  
  VS Code
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Navigation &amp;amp; Interface
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;th&gt;Windows/Linux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Open file by name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+P&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Command palette&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global search&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle sidebar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+B&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle terminal panel&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+J&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+J&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New terminal&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+Shift+&lt;/code&gt;&lt;code&gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Ctrl+Shift+&lt;/code&gt;&lt;code&gt;&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split editor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+\&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+\&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go to definition&lt;/td&gt;
&lt;td&gt;&lt;code&gt;F12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;F12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rename symbol&lt;/td&gt;
&lt;td&gt;&lt;code&gt;F2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;F2&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View all keyboard shortcuts&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+K, Cmd+S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+K, Ctrl+S&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Cmd+P&lt;/code&gt; / &lt;code&gt;Ctrl+P&lt;/code&gt; opens any file by name — type a few characters and it filters in real time. With &lt;code&gt;Cmd+B&lt;/code&gt; to hide the sidebar and &lt;code&gt;Cmd+J&lt;/code&gt; to toggle the terminal, the file explorer panel becomes largely optional.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cmd+Shift+P&lt;/code&gt; / &lt;code&gt;Ctrl+Shift+P&lt;/code&gt; opens the command palette. For any action without a memorized shortcut, it's the fastest path.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Cmd+K, Cmd+S&lt;/code&gt; opens the full keyboard shortcuts editor. It's worth exploring — and anything that conflicts with existing habits can be remapped there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editing
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;macOS&lt;/th&gt;
&lt;th&gt;Windows/Linux&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Move line up / down&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Opt+↑&lt;/code&gt; / &lt;code&gt;Opt+↓&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Alt+↑&lt;/code&gt; / &lt;code&gt;Alt+↓&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Duplicate line&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Shift+Opt+↓&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Shift+Alt+↓&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select next occurrence&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+D&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select all occurrences&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Shift+L&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+L&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add cursor&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Opt+Click&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Alt+Click&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add cursor above / below&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Opt+↑/↓&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Alt+↑/↓&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add cursors across lines&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+Opt+Shift+↑/↓&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Alt+Shift+↑/↓&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Toggle comment&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Cmd+/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+/&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column selection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Shift+Opt+Drag&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Shift+Alt+Drag&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Multi-cursor editing is worth investing time in. Selecting all occurrences of a variable, renaming across multiple lines simultaneously, or applying the same edit to a column of values — these are the kinds of tasks that used to require find-and-replace or repeated manual edits.&lt;/p&gt;




&lt;h2&gt;
  
  
  Terminal &amp;amp; Shell
&lt;/h2&gt;

&lt;p&gt;Before building terminal shortcuts, it's worth knowing which shell you're actually in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$SHELL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A shell is the command interpreter between you and the operating system — handling command execution, history, aliases, functions, environment variables, and startup configuration. Most modern macOS installations default to zsh. Personal configuration for zsh lives in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After editing that file, reload it without opening a new terminal window:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shortcuts and aliases in this section assume zsh, though most apply equally to bash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Command Line Navigation
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Move to line start&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+A&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Move to line end&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+E&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete to line start&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+U&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete to line end&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+K&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delete previous word&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+W&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Search command history&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Ctrl+R&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;Ctrl+R&lt;/code&gt; initiates a reverse search through command history. Start typing any fragment of a previous command and it surfaces matches interactively — useful for long commands you remember running but don't want to retype.&lt;/p&gt;

&lt;h3&gt;
  
  
  Useful Commands
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Display command history&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history
history&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when you remember running a command but not its exact syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Print working directory&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The fastest way to confirm where you are in a directory structure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View large files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;less server.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;less&lt;/code&gt; allows scrolling through large files without flooding the terminal output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repeat previous command&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;A common use case: rerunning a command with elevated privileges after it fails without them:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shell Customization
&lt;/h3&gt;

&lt;p&gt;Aliases turn repetitive commands into single words. A few practical examples to add to &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;ll&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ls -la"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git status"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git push"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Small improvements compound. A few well-chosen aliases, combined with history search and readline shortcuts, reduce a meaningful amount of low-level friction every time a terminal opens.&lt;/p&gt;




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

&lt;h3&gt;
  
  
  Common Commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt;
git push
git pull
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;git status&lt;/code&gt; is the most frequently useful of these. When uncertain about the state of a repository — what's staged, what's modified, what branch you're on — it provides an immediate summary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Aliases
&lt;/h3&gt;

&lt;p&gt;Add these to &lt;code&gt;~/.gitconfig&lt;/code&gt; under &lt;code&gt;[alias]&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[alias]&lt;/span&gt;
  &lt;span class="py"&gt;st&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;status -sb&lt;/span&gt;
  &lt;span class="py"&gt;aa&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;add .&lt;/span&gt;
  &lt;span class="py"&gt;cm&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;commit -m&lt;/span&gt;
  &lt;span class="py"&gt;ps&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;push&lt;/span&gt;
  &lt;span class="py"&gt;pl&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;pull&lt;/span&gt;
  &lt;span class="py"&gt;lg&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;log --oneline --graph --decorate&lt;/span&gt;
  &lt;span class="py"&gt;undo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;reset HEAD~1 --mixed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or as shell aliases in &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gst&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git status -sb'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gaa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git add .'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gcm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git commit -m'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git push'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gpl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git pull'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'git log --oneline --graph --decorate'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;gl&lt;/code&gt; is worth calling out specifically. The &lt;code&gt;--oneline --graph --decorate&lt;/code&gt; flags render commit history and branch structure in a format that's actually readable — a significant improvement over the default &lt;code&gt;git log&lt;/code&gt; output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recovery Commands
&lt;/h3&gt;

&lt;p&gt;Most Git commands create history rather than destroy it. A few commands that help when things go wrong:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Inspect unstaged changes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git diff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review modifications before staging or committing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Restore a file to its last committed state&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore filename.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Save work temporarily without committing&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful when switching tasks mid-work. &lt;code&gt;git stash pop&lt;/code&gt; restores it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Switch branches&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch feature-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more explicit alternative to &lt;code&gt;git checkout&lt;/code&gt; for branch switching.&lt;/p&gt;




&lt;h2&gt;
  
  
  Deliberate Practice
&lt;/h2&gt;

&lt;p&gt;Reading about shortcuts can be useful. Acquiring them requires  repetition. Deliberate action.&lt;/p&gt;

&lt;p&gt;To accompany this article, I built a small workshop repository designed around that idea. The project walks through common development tasks using the same layers covered here — OS navigation, browser workflows, terminal commands, Git operations, and VS Code shortcuts.&lt;/p&gt;

&lt;p&gt;Participants can fork and clone the repository, navigate the filesystem, open the project in VS Code, and complete progressively larger tasks. Instructions are embedded in the project files, and automated tests provide feedback as each task is completed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Gmcjr/developer-shortcuts-workshop.git" rel="noopener noreferrer"&gt;Developer Shortcuts Workshop&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Start Small
&lt;/h2&gt;

&lt;p&gt;Pick one shortcut — ideally one that addresses something you actually do repeatedly. Use it every time that action comes up, even when it's slower than what you'd normally reach for. That's stage one of the acquisition arc. It's temporary.&lt;/p&gt;

&lt;p&gt;By the end of a week of consistent use, the shortcut is close to automatic. At that point, add another.&lt;/p&gt;

&lt;p&gt;The environment stops being an obstacle when the tools in it no longer require conscious attention. That happens one shortcut at a time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Source Notes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Lane, D. M., Napier, H. A., Peres, S. C., &amp;amp; Sandor, A. (2005).&lt;/strong&gt; &lt;em&gt;Hidden costs of graphical user interfaces: Failure to make the transition from menus and icon toolbars to keyboard shortcuts. International Journal of Human-Computer Interaction, 18(2), 133–144.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Results showed that shortcut use was very low (less than 10% of the time) and that the number of hours participants had been using the program did not predict the frequency of shortcut use."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;Fitts, P. M., &amp;amp; Posner, M. I. (1967).&lt;/strong&gt; &lt;em&gt;Human Performance.&lt;/em&gt; Brooks/Cole.&lt;/p&gt;

&lt;p&gt;Original source for the three-stage model of skill acquisition: cognitive, associative, and autonomous. The model describes how a learner moves from effortful, conscious execution of a skill toward automatic execution requiring minimal attentional resources.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Remington, R. W., Yuen, H. W. H., &amp;amp; Pashler, H. (2016).&lt;/strong&gt; &lt;em&gt;With practice, keyboard shortcuts become faster than menu selection: A crossover interaction. Journal of Experimental Psychology: Applied, 22(1), 95–106. DOI: 10.1037/xap0000069&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It is widely believed that a graphical user interface (GUI) is superior to a command line interface (CLI) for novice users, but less efficient than the CLI after practice. However, there appears to be no detailed study of the crossover interaction that this implies... The predicted crossover was observed after approximately 200 responses. Experiment 2 showed that following training all but 1 subject in the CLI-trained group chose to continue using shortcuts. These results suggest that frequency of shortcut use is a function of ease of retrieval, which develops over the course of multiple repetitions of the command."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Full References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lane, D. M., Napier, H. A., Peres, S. C., &amp;amp; Sandor, A. (2005). Hidden costs of graphical user interfaces: Failure to make the transition from menus and icon toolbars to keyboard shortcuts. &lt;em&gt;International Journal of Human-Computer Interaction, 18&lt;/em&gt;(2), 133–144.&lt;/li&gt;
&lt;li&gt;Fitts, P. M., &amp;amp; Posner, M. I. (1967). &lt;em&gt;Human Performance.&lt;/em&gt; Brooks/Cole.&lt;/li&gt;
&lt;li&gt;Remington, R. W., Yuen, H. W. H., &amp;amp; Pashler, H. (2016). With practice, keyboard shortcuts become faster than menu selection: A crossover interaction. &lt;em&gt;Journal of Experimental Psychology: Applied, 22&lt;/em&gt;(1), 95–106. DOI: 10.1037/xap0000069&lt;/li&gt;
&lt;li&gt;Fagarasanu, M., &amp;amp; Kumar, S. (2003). Carpal tunnel syndrome due to keyboarding and mouse tasks: A review. &lt;em&gt;International Journal of Industrial Ergonomics, 31&lt;/em&gt;(2), 119–136.&lt;/li&gt;
&lt;li&gt;Jardina, J. R., Peres, S. C., Nguyen, V., Megasari, A., Griggs, K. R., Pinales, R., &amp;amp; Amos, A. N. (2009). Keyboard shortcut users: They are faster at more than just typing. &lt;em&gt;Proceedings of the Human Factors and Ergonomics Society Annual Meeting, 53&lt;/em&gt;(15).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>shortcuts</category>
      <category>keycommands</category>
      <category>productivity</category>
      <category>untethered</category>
    </item>
    <item>
      <title>What’s Actually Happening When You Use Git</title>
      <dc:creator>Garrin Costa, Jr.</dc:creator>
      <pubDate>Mon, 25 May 2026 13:48:05 +0000</pubDate>
      <link>https://dev.to/gmcjr/whats-actually-happening-when-you-use-git-464e</link>
      <guid>https://dev.to/gmcjr/whats-actually-happening-when-you-use-git-464e</guid>
      <description>&lt;p&gt;I’d been using Git comfortably for months before getting uncomfortable with how little I actually understood.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git add&lt;/code&gt;. &lt;code&gt;git commit&lt;/code&gt;. &lt;code&gt;git push&lt;/code&gt; were memory at this point. But ask me what Git was actually doing under the hood? I couldn’t tell you. I had some (mostly wrong) assumptions but that was about it.&lt;/p&gt;

&lt;p&gt;Then I discovered the &lt;code&gt;.git/&lt;/code&gt; directory…&lt;/p&gt;




&lt;h2&gt;
  
  
  Git Is Not What You Think It Is
&lt;/h2&gt;

&lt;p&gt;Many people think of Git as a “track changes” tool. That’s the way I thought of it. Like the version history in a Google Doc. That’s not wrong, but it’s not the whole picture.&lt;/p&gt;

&lt;p&gt;Git’s creator, Linus Torvalds, described it more precisely:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Git is fundamentally a content-addressable filesystem with a VCS user interface written on top of it.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, what is a content-addressable filesystem?&lt;/p&gt;

&lt;p&gt;Instead of storing files by name or location, Git stores them by their &lt;strong&gt;content&lt;/strong&gt;. Every piece of data gets run through a hashing algorithm (SHA-1) that produces a unique 40-character fingerprint. That fingerprint is the file’s identity in Git’s database. The same content will always return the same hash, always.&lt;/p&gt;

&lt;p&gt;Understanding this immediately explained much of what felt confusing about Git.&lt;/p&gt;




&lt;h2&gt;
  
  
  The &lt;code&gt;.git/&lt;/code&gt; Directory Is Your Entire Repository
&lt;/h2&gt;

&lt;p&gt;Open any Git project and run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; .git/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HEAD    config    description    hooks    info    objects    refs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;.git/&lt;/code&gt; is a hidden directory created when a Git repository is initialized.&lt;br&gt;
This directory is your entire repository. Every commit, every version of every file, the full history — all of it lives inside &lt;code&gt;.git/&lt;/code&gt;. Your working directory (the files you actually edit) is just a projection of what’s in there.&lt;/p&gt;

&lt;p&gt;You can copy &lt;code&gt;.git/&lt;/code&gt; somewhere else, and you’ll have everything. On the other hand, if you delete &lt;code&gt;.git/&lt;/code&gt; you lose your entire history. Not just your latest changes. Everything.&lt;br&gt;
It’s hidden for a good reason, but it is hugely helpful to be aware of it.&lt;/p&gt;

&lt;p&gt;Two very important directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;objects/&lt;/code&gt;&lt;/strong&gt; — Git’s content database. Every blob, tree, and commit lives here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;refs/&lt;/code&gt;&lt;/strong&gt; — Pointers. Branch names, tags, remotes. All of them are just pointers to commits in &lt;code&gt;objects/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Three Objects. One Chain.
&lt;/h2&gt;

&lt;p&gt;Git stores everything as one of three object types. Understanding these three types makes everything else click.&lt;/p&gt;
&lt;h3&gt;
  
  
  Blob — The File
&lt;/h3&gt;

&lt;p&gt;A blob (Binary Large OBject) is an immutable object with a header. It contains the raw file content and nothing more.&lt;br&gt;
It does not store the filename or its location. It has no reference to itself or any other files.&lt;br&gt;
If one character in a file changes, Git creates a brand new blob with a completely different SHA. The old one stays untouched.&lt;/p&gt;

&lt;p&gt;Run this on any blob SHA to see for yourself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cat-file &lt;span class="nt"&gt;-p&lt;/span&gt; &amp;lt;blob SHA&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll see the raw file content. No filename. No path. Just the content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tree — The Snapshot
&lt;/h3&gt;

&lt;p&gt;A tree object represents a directory. It’s a list of entries — each one containing a file mode, object type, SHA, and filename.&lt;/p&gt;

&lt;p&gt;This is where filenames live. The tree connects a name to a blob. Run &lt;code&gt;git cat-file -p&lt;/code&gt; on a tree SHA and you’ll see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100644 blob b7aec520dec0a7516c18eb4c68b64ae1eb9b5a5e    README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mode, type, SHA, filename. The tree is the snapshot of your project at a given moment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Commit — The Pointer
&lt;/h3&gt;

&lt;p&gt;A commit object is simpler than most people expect. Run &lt;code&gt;git cat-file -p&lt;/code&gt; on a commit SHA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;tree&lt;/span&gt; &lt;span class="m"&gt;7102&lt;/span&gt;&lt;span class="n"&gt;e6ffc1a508e552d53f28bbeb0a976124d7e6&lt;/span&gt;
&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="n"&gt;d48a0fbe5c378c69ad9522883d1d2f8dbe5ebd69&lt;/span&gt;
&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="n"&gt;garrin&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;abcdefg&lt;/span&gt;@&lt;span class="m"&gt;123&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;&amp;gt; &lt;span class="m"&gt;1779654747&lt;/span&gt; -&lt;span class="m"&gt;0500&lt;/span&gt;
&lt;span class="n"&gt;committer&lt;/span&gt; &lt;span class="n"&gt;garrin&lt;/span&gt; &amp;lt;&lt;span class="n"&gt;abcdefg&lt;/span&gt;@&lt;span class="m"&gt;123&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;&amp;gt; &lt;span class="m"&gt;1779654747&lt;/span&gt; -&lt;span class="m"&gt;0500&lt;/span&gt;

&lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. A commit is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A pointer to a tree (the snapshot)&lt;/li&gt;
&lt;li&gt;A pointer to its parent commit (the history)&lt;/li&gt;
&lt;li&gt;Metadata that includes the author (who made changes/wrote the code) and committer (who made the commit), as well as when the commit was made, and the commit message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The chain is always:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;commit → tree → blob(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;There’s actually a fourth object type — the annotated tag. I won’t go into detail here, but the annotated tag wraps a commit with its own metadata and SHA, and is often used for marking official releases.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The History Is a Graph, Not a Line
&lt;/h2&gt;

&lt;p&gt;The chain — commit → tree → blob — implies something linear. It isn’t.&lt;/p&gt;

&lt;p&gt;Every commit points to its parent. Most commits have one. Merge commits have two. Over time, those parent-child relationships form a &lt;strong&gt;DAG: a Directed Acyclic Graph&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Directed means the edges go one way — a commit points to its parent, never the reverse. Acyclic means no loops — you can’t follow the chain and end up back where you started. Graph means the structure branches and rejoins freely.&lt;/p&gt;

&lt;p&gt;This is why &lt;code&gt;git log&lt;/code&gt; can look like a tree but isn’t one. Trees don’t rejoin. A DAG can. Every time you merge two branches, the merge commit has two parent pointers — two incoming edges — and the graph folds back on itself.&lt;/p&gt;

&lt;p&gt;Understanding that Git’s history is a DAG explains a lot: why &lt;code&gt;git log --graph&lt;/code&gt; draws forks and merges the way it does, why reachability matters (an object is “live” if you can reach it by following edges from a named ref), and why Git’s garbage collector targets objects with no incoming path from any branch or tag.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stuff That Trips People Up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A Branch Is a Text File
&lt;/h3&gt;

&lt;p&gt;Run this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; .git/refs/heads/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll get a single SHA. That’s your &lt;code&gt;main&lt;/code&gt; branch. A 41-character text file. That’s the entire concept of a branch in Git — a file containing the SHA of the commit it currently points to.&lt;/p&gt;

&lt;p&gt;Creating a branch creates a file. Switching branches changes which file HEAD points to. Deleting a branch deletes the file.&lt;/p&gt;

&lt;p&gt;Which brings us to something important.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deleting a Branch Doesn’t Delete Your Commits
&lt;/h3&gt;

&lt;p&gt;When you delete a branch, you delete the pointer. You do not delete the objects in &lt;code&gt;.git/objects/&lt;/code&gt;. The commits, trees, and blobs that branch pointed to are still in the database. They’re just unreachable by name.&lt;/p&gt;

&lt;p&gt;You can prove it. Delete a branch, then run &lt;code&gt;git cat-file -p&lt;/code&gt; on a commit SHA that was on it. It’s still there.&lt;/p&gt;

&lt;p&gt;Git’s garbage collector (&lt;code&gt;git gc&lt;/code&gt;) will eventually clean up truly unreachable objects — but not for at least two weeks by default. Which means if you accidentally delete a branch, &lt;code&gt;git reflog&lt;/code&gt; can save you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Staging Already Writes to the Database
&lt;/h3&gt;

&lt;p&gt;Most people think &lt;code&gt;git add&lt;/code&gt; just “queues” a file for the next commit. It does more than that.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;git add&lt;/code&gt;, Git immediately:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hashes your file content&lt;/li&gt;
&lt;li&gt;Creates a blob object&lt;/li&gt;
&lt;li&gt;Writes it to &lt;code&gt;.git/objects/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Updates the index (staging area) to track it&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The blob is already stored before you ever run &lt;code&gt;git commit&lt;/code&gt;. The commit just formalizes it — creating the tree and commit objects that make the blob part of your permanent history.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;git reset&lt;/code&gt; Moves a Pointer. It Doesn’t Delete Data.
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;git reset --hard &amp;lt;SHA&amp;gt;&lt;/code&gt; feels destructive. It’s not — at least not immediately.&lt;/p&gt;

&lt;p&gt;What it actually does: moves the branch pointer back to the specified commit. The commits you “reset away” are still in &lt;code&gt;.git/objects/&lt;/code&gt;. They’re just unreachable from your current branch.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;git reflog&lt;/code&gt; after a reset and you’ll see every place HEAD has pointed. Your “lost” commits are listed there, recoverable by SHA.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git revert&lt;/code&gt; works differently. Instead of moving a pointer, it creates a brand new commit that applies the inverse of a previous commit’s changes. History is preserved. This is why &lt;code&gt;git revert&lt;/code&gt; is safe on shared branches and &lt;code&gt;git reset&lt;/code&gt; is not — reset rewrites history, revert adds to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Merge Commits Have Two Parents
&lt;/h3&gt;

&lt;p&gt;When you merge two branches and there’s a conflict, Git compares three blobs: the common ancestor, your version, and their version. This is called a three-way merge.&lt;/p&gt;

&lt;p&gt;If the same lines changed on both sides, Git writes conflict markers to your working directory and waits for you to resolve them. Once you do, &lt;code&gt;git add&lt;/code&gt; creates a new blob. Then &lt;code&gt;git commit&lt;/code&gt; creates a &lt;strong&gt;merge commit&lt;/strong&gt; — the only commit type with two parent pointers, one for each branch tip.&lt;/p&gt;

&lt;p&gt;That two-parent structure is exactly what the DAG looks like in the object database.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Mental Model Matters
&lt;/h2&gt;

&lt;p&gt;You don’t need to know this stuff to use Git day-to-day. But once you do, a few things happen:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detached HEAD stops being scary. It just means HEAD is pointing directly at a commit SHA instead of a branch name.&lt;/li&gt;
&lt;li&gt;Merge conflicts make sense. Two commits changed the same lines. Git can’t pick — it’s asking you to resolve a pointer conflict.&lt;/li&gt;
&lt;li&gt;“Lost” commits stop feeling lost. The objects are almost always still there. &lt;code&gt;git reflog&lt;/code&gt; is your safety net.&lt;/li&gt;
&lt;li&gt;You stop being afraid of &lt;code&gt;git reset&lt;/code&gt;, &lt;code&gt;git rebase&lt;/code&gt;, and other commands that feel dangerous.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git log --graph&lt;/code&gt; stops being decorative. It’s a literal rendering of the DAG — every fork is a branch tip, every convergence is a merge commit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Git isn’t magic. It’s a content-addressable filesystem with a great interface. A few text files, a database of hashed objects, and a set of rules for how they point to each other.&lt;/p&gt;

&lt;p&gt;Open &lt;code&gt;.git/&lt;/code&gt; and look around. It’s less mysterious than you think.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Further reading:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain" rel="noopener noreferrer"&gt;Pro Git, Chapter 10 — Git Internals&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;a href="https://jwiegley.github.io/git-from-the-bottom-up/" rel="noopener noreferrer"&gt;Git from the Bottom Up — John Wiegley&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>softwaredevelopment</category>
      <category>versioncontrol</category>
      <category>gitinternals</category>
    </item>
    <item>
      <title>What is jQuery Really? A Look Under the Hood</title>
      <dc:creator>Garrin Costa, Jr.</dc:creator>
      <pubDate>Sat, 25 Apr 2026 18:25:40 +0000</pubDate>
      <link>https://dev.to/gmcjr/what-is-jquery-really-a-look-under-the-hood-2h0l</link>
      <guid>https://dev.to/gmcjr/what-is-jquery-really-a-look-under-the-hood-2h0l</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is jQuery Really?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;jQuery can drastically simplify working with HTML, CSS, and JavaScript. Taking a little time to understand how a tool works — the mechanism that drives it — is often the difference between having access to a tool and having command over it.&lt;/p&gt;

&lt;p&gt;To better understand what jQuery is doing under the hood, it is helpful to understand a little bit about the DOM. The DOM (Document Object Model) is a programming interface, built by browsers, which represents the structure of a web document in memory. It is created when a webpage is loaded, representing the document with a tree-like structure. The DOM can be thought of like a bridge or a hub, allowing a webpage's content, styling, and interactivity to be accessed and manipulated dynamically.&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%2F23md6mouwa91jit98h7e.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23md6mouwa91jit98h7e.jpg" alt="A look under the hood — engine components exposed, illustrating the mechanism beneath the surface." width="800" height="533"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A look under the hood — engine components exposed, illustrating the mechanism beneath the surface.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The DOM Problem jQuery Solves&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The DOM exposes a set of built-in browser APIs for accessing and manipulating elements. These APIs offer a world of capabilities and give us precise control, but they are verbose and low-level by design, requiring a lot of explicit instruction for even simple operations.&lt;/p&gt;

&lt;p&gt;jQuery wraps those verbose native APIs in shorter, more readable methods. We write the jQuery shorthand — jQuery handles the verbose part under the hood.&lt;/p&gt;

&lt;p&gt;The example below demonstrates a simple DOM interaction. We're going to grab a button on a webpage and change its color when clicked — the same operation written first in vanilla JavaScript, then in jQuery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&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;As you might notice, the code needed to perform relatively simple modifications can get cumbersome. This is just ONE modification.&lt;/p&gt;

&lt;p&gt;Now here's the same operation done with jQuery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&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;jQuery collapses our JavaScript into just a few lines of clean, readable code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;$ is Just a Function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As we pull back the curtain on jQuery, let's first look at the &lt;code&gt;$&lt;/code&gt; symbol.&lt;/p&gt;

&lt;p&gt;A common misconception many beginners have about this is that &lt;code&gt;$&lt;/code&gt; is special syntax — something built into JavaScript itself. Perhaps assuming JavaScript just knows what &lt;code&gt;$&lt;/code&gt; means.&lt;/p&gt;

&lt;p&gt;However, that is not the case. We know that &lt;code&gt;$&lt;/code&gt; is a valid character to use when naming variables in JavaScript, but that's all. On its own, &lt;code&gt;$&lt;/code&gt; means nothing to JavaScript unless defined — which is exactly what happens when jQuery is imported. Both &lt;code&gt;jQuery&lt;/code&gt; and its alias &lt;code&gt;$&lt;/code&gt; are defined as the jQuery function. By convention, most developers use &lt;code&gt;$&lt;/code&gt;, but either works — what matters is consistency. &lt;/p&gt;

&lt;p&gt;We pass element selectors into the function as arguments. It returns an array-like container (the jQuery object) that contains the selected DOM nodes. This gives us access to jQuery's methods, which we can execute on the selected elements.&lt;/p&gt;

&lt;p&gt;To get access to the jQuery library and use it in a project, you can download the library and then in your project's HTML file, create a script tag with a &lt;code&gt;src&lt;/code&gt; attribute that points to your copy of jQuery:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Local download --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"jquery.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another option is to load jQuery via CDN:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- CDN --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://code.jquery.com/jquery-4.0.0.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What You Actually Get Back&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unlike vanilla JavaScript which returns raw DOM elements directly, jQuery returns an array-like container holding the nodes. With jQuery, we manipulate elements through this container, not directly.&lt;/p&gt;

&lt;p&gt;You can see what this looks like for yourself. Open your DevTools console on any jQuery page and run &lt;code&gt;$('p')&lt;/code&gt;. What you get back should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;T {0: p, 1: p, 2: p, 3: p, 4: p, 5: p, 6: p, 7: p, 8: p, 9: p.copyright, 10: p, length: 11, prevObject: T}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you're seeing is the jQuery object. It contains indexed elements and a &lt;code&gt;length&lt;/code&gt; — the number of matched elements — along with some internal jQuery properties (&lt;code&gt;prevObject&lt;/code&gt;) that are beyond the scope of this article. If we expand it, we can see a vast array of methods and properties now accessible to us. This behavior of returning the jQuery object enables us to write the same code whether our selector matches one element or many — jQuery handles the iteration. &lt;/p&gt;

&lt;p&gt;Vanilla JavaScript requires a manual loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;paragraphs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;paragraphs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;paragraphs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&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;Whereas jQuery silently iterates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;p&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much simpler in form, easy to follow, and easy to chain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Chaining Works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When we call a jQuery function, what we get back is the jQuery object, rather than the raw node that we're operating on. This is by design. What's special about this behavior is that the jQuery object — that container that wraps our raw data — comes equipped with many of jQuery's built-in methods and properties. It gives us something to operate on. This is what makes chaining jQuery methods so simple and effective.&lt;/p&gt;

&lt;p&gt;Why would we want to chain methods? What makes this so useful? Take a look at this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;background-color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slideUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slideDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we've performed three different operations on our &lt;code&gt;#button&lt;/code&gt; element without having to re-select it three times. It's simple, logical, and sleek.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Handling&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Event handlers wait for a specific event and invoke a callback function when that event occurs. jQuery makes this operation concise and readable. With jQuery, &lt;code&gt;.on()&lt;/code&gt; is the universal event handler. Though not the only way to implement event handling, it is preferred for flexibility and consistency. It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// do something&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;jQuery also provides shorthand methods for specific event types — here are a few common ones.&lt;/p&gt;

&lt;p&gt;Let's say we have some card elements on our page and we want to blur the background when we hover on a card. This requires a couple of functions. In jQuery, we can do this like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#card&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expanded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;addClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blurred&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;removeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;expanded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;removeClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blurred&lt;/span&gt;&lt;span class="dl"&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;Our &lt;code&gt;$&lt;/code&gt; is a function, into which we pass the &lt;code&gt;#card&lt;/code&gt; element selector. Since jQuery returns its container object, we can then chain &lt;code&gt;.hover()&lt;/code&gt; to the object and pass the functions that will perform our desired action. Those functions can also call the jQuery object to do so.&lt;/p&gt;

&lt;p&gt;Here's an example of showing/hiding options based on checkbox state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#checkbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;change&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#options-list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toggle&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;We start with calling &lt;code&gt;$&lt;/code&gt; and pass into it the &lt;code&gt;#checkbox&lt;/code&gt; selector. We implement the &lt;code&gt;.change()&lt;/code&gt; jQuery method on the returned object, letting us pass a callback function which passes another &lt;code&gt;$&lt;/code&gt; call with our next element selector as its argument, returning the jQuery object onto which we can apply the &lt;code&gt;.toggle()&lt;/code&gt; method. Clean and concise.&lt;/p&gt;

&lt;p&gt;And here's one more example showing how we might use jQuery to implement an event listener that starts music playback on spacebar press:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;keydown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;music&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;play&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;This again shows how simple and readable our code can be when implementing operations that often prove tedious and difficult to follow otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I hope this has helped in showing some of jQuery's capabilities and usefulness, as well as given some insight into what's going on under the hood. A deeper understanding of how jQuery interacts with our code makes bugs easier to avoid — and when they do occur, easier to debug. It also deepens our understanding of JavaScript as a whole.&lt;/p&gt;

&lt;p&gt;Another benefit to understanding a library like this is that it can serve as a template for understanding ANY library. While syntax, structure, and individual details will vary, the broader concepts often overlap. This can make expanding our range of knowledge and broadening our toolsets a much less daunting and more rewarding experience.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>jquery</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
