<?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: Mark Erikson</title>
    <description>The latest articles on DEV Community by Mark Erikson (@markerikson).</description>
    <link>https://dev.to/markerikson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1192%2F1128784.jpeg</url>
      <title>DEV Community: Mark Erikson</title>
      <link>https://dev.to/markerikson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/markerikson"/>
    <language>en</language>
    <item>
      <title>Coding Career Advice: Using Git for Version Control Effectively</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Wed, 27 Jan 2021 15:00:00 +0000</pubDate>
      <link>https://dev.to/markerikson/coding-career-advice-using-git-for-version-control-effectively-fdj</link>
      <guid>https://dev.to/markerikson/coding-career-advice-using-git-for-version-control-effectively-fdj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Git has become the standard tool for software development version control. Other VCS tools exist, and some work better than Git for certain scenarios, but most of today's development world relies on using Git. So, becoming comfortable with Git and knowing how to use it effectively is a key skill for any software developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I'd like to pass along some of the most useful Git concepts and tips&lt;/strong&gt; that I've learned over the last few years. In addition, I've covered &lt;strong&gt;background info on how Git works and common operations&lt;/strong&gt; , and there's some &lt;strong&gt;specific usage patterns I've found to be especially valuable&lt;/strong&gt; when working with a team and trying to understand a codebase.&lt;/p&gt;

&lt;p&gt;As usual, none of the info or advice in this post is completely new or original, and there's many other sites that cover the same topics (and probably explain them better). I'm just trying to provide an overview of the relevant material and provide enough details that you can do further research and learning from there.&lt;/p&gt;

&lt;p&gt;This post is largely based on my slideset &lt;a href="https://blog.isquaredsoftware.com/2019/10/presentation-git-internals-rewrite/" rel="noopener noreferrer"&gt;&lt;strong&gt;Git Under the Hood: Internals, Techniques, and Rewriting History&lt;/strong&gt;&lt;/a&gt;, and I talked about rewriting repo history in my post &lt;a href="https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/" rel="noopener noreferrer"&gt;&lt;strong&gt;Rewriting Your Git History and JS Source for Fun and Profit&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Contents
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
Introduction

&lt;ul&gt;
&lt;li&gt;Table of Contents&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Git Fundamentals

&lt;ul&gt;
&lt;li&gt;
Git Terms and Concepts Overview

&lt;ul&gt;
&lt;li&gt;Git Basics&lt;/li&gt;
&lt;li&gt;Sharing Data Between Repositories&lt;/li&gt;
&lt;li&gt;Branches&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Understanding Git Internals&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;Git Tools&lt;/li&gt;

&lt;li&gt;

Git Techniques

&lt;ul&gt;
&lt;li&gt;Improving CLI Logging&lt;/li&gt;
&lt;li&gt;Preparing Commits in Pieces&lt;/li&gt;
&lt;li&gt;Stashing Changes&lt;/li&gt;
&lt;li&gt;
Working with Branches

&lt;ul&gt;
&lt;li&gt;Creating and Switching Branches&lt;/li&gt;
&lt;li&gt;Fetching, Pushing, and Pulling Branches&lt;/li&gt;
&lt;li&gt;Merging Branches&lt;/li&gt;
&lt;li&gt;Feature Branch Strategies&lt;/li&gt;
&lt;li&gt;Pull Requests&lt;/li&gt;
&lt;li&gt;Updating Branches in the Background&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Rewriting Git History

&lt;ul&gt;
&lt;li&gt;Amending Commits&lt;/li&gt;
&lt;li&gt;Resetting Branches&lt;/li&gt;
&lt;li&gt;Rebasing Branches&lt;/li&gt;
&lt;li&gt;Reverting Commits&lt;/li&gt;
&lt;li&gt;Cherry-Picking&lt;/li&gt;
&lt;li&gt;Interactive Rebasing&lt;/li&gt;
&lt;li&gt;Reflog&lt;/li&gt;
&lt;li&gt;Advanced History Rewriting&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;

Git Patterns and Best Practices

&lt;ul&gt;
&lt;li&gt;Write Good Commit Messages&lt;/li&gt;
&lt;li&gt;Make Small, Focused Commits&lt;/li&gt;
&lt;li&gt;Clean Up Commit History Before Pushing&lt;/li&gt;
&lt;li&gt;Only Rewrite Unpushed History&lt;/li&gt;
&lt;li&gt;Keep Feature Branches Short-Lived&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Code Archeology with Git

&lt;ul&gt;
&lt;li&gt;Displaying Historical File Changes&lt;/li&gt;
&lt;li&gt;Bisecting Bugs&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Final Thoughts&lt;/li&gt;

&lt;li&gt;Further Information&lt;/li&gt;

&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Git is notoriously difficult to work with, especially using the command line&lt;/strong&gt;. The CLI commands and options are confusing, mismatched, and hard to remember. There's phrases and warnings like "detached &lt;code&gt;HEAD&lt;/code&gt;". Git, frankly, is not easy to learn and kinda scary.&lt;/p&gt;

&lt;p&gt;The good news is that &lt;strong&gt;once you understand &lt;em&gt;how&lt;/em&gt; Git works, it becomes an extremely powerful tool that offers a lot of flexibility&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git Terms and Concepts Overview
&lt;/h3&gt;

&lt;p&gt;While I'm not going to turn this into a complete "Git tutorial from scratch", it's worth reviewing some of the key concepts.&lt;/p&gt;

&lt;h4&gt;
  
  
  Git Basics
&lt;/h4&gt;

&lt;p&gt;Git is a tool for tracking changes to file content over time. A Git &lt;em&gt;repository&lt;/em&gt; is a folder that has a &lt;code&gt;.git&lt;/code&gt; folder inside. The &lt;code&gt;.git&lt;/code&gt; folder contains all the metadata and stored history of the project's changes.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;working copy&lt;/em&gt; is all other folders and files in the repository folder that Git is storing and tracking. Any newly created files start out &lt;em&gt;untracked&lt;/em&gt;. Git knows that the files are there, but you haven't told Git to save them.&lt;/p&gt;

&lt;p&gt;To tell Git to start tracking a file, you &lt;em&gt;add&lt;/em&gt; the file (&lt;code&gt;git add some-file&lt;/code&gt;). Git then saves a copy of the file in an internal section called the &lt;em&gt;staging area&lt;/em&gt;. Staged files are not being saved permanently, yet. Instead, they represent the set of files and contents that &lt;em&gt;will&lt;/em&gt; be saved when you actually tell Git to save them.&lt;/p&gt;

&lt;p&gt;Once you've added one or more files to the staging area, you can save them by &lt;em&gt;committing&lt;/em&gt; them. "Commit" is both a verb and a noun here: we "commit" files to save them, and every time we save them, we make a "commit".&lt;/p&gt;

&lt;p&gt;Git commits contain a certain set of files and their contents, at a specific point in time. They also contain metadata, including the author's name and email address, and a &lt;em&gt;commit message&lt;/em&gt; that you write to describe the changes that were saved.&lt;/p&gt;

&lt;p&gt;After a file has been added at least once, making further changes to that file will cause Git to mark it as &lt;em&gt;modified&lt;/em&gt;. That means that Git knows the contents are different, but you haven't told Git to save the new changes yet. Once you add that file to the staging area again, Git sees that its latest copy of the file is the same as what's on disk, so it describes the file as &lt;em&gt;unchanged&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sharing Data Between Repositories
&lt;/h4&gt;

&lt;p&gt;Each Git repository folder is standalone. However, Git repositories can be shared across folders, computers, and networks, allowing developers to collaborate on the same codebase. A Git repo can be configured with the URL of another repo, allowing the two repos to send commits back and forth. Each URL entry is called a &lt;em&gt;remote&lt;/em&gt;. Downloading commit data from a remote repo is a &lt;em&gt;fetch&lt;/em&gt; or a &lt;em&gt;pull&lt;/em&gt; (with slight differences in behavior), and uploading commit data from local to remote is a &lt;em&gt;push&lt;/em&gt;. Downloading a complete repo from scratch is making a &lt;em&gt;clone&lt;/em&gt; of that repo.&lt;/p&gt;

&lt;p&gt;Repositories normally have a default remote repo they point to, called the &lt;em&gt;origin&lt;/em&gt;. Whenever you clone a repo, the new local repo points to the remote source as the origin, but that entry can be changed later. Repos can be configured to talk to many other repos at once, and can push and pull data from any remote.&lt;/p&gt;

&lt;h4&gt;
  
  
  Branches
&lt;/h4&gt;

&lt;p&gt;Git commits are tracked using &lt;em&gt;branches&lt;/em&gt;. A branch is like a pointer to the latest commit in a specific series of commits. Any time you make a new commit, Git bumps that branch pointer to point to the newest commit. You can make many branches within a repo, and most devs create a new branch for each task they work on. You can also make &lt;em&gt;tags&lt;/em&gt;, which also point to a specific commit, but don't get moved or changed automatically. Tags are normally used to identify checkpoints and releases, so you can easily jump back and see how the code was at that point in time.&lt;/p&gt;

&lt;p&gt;Changes from multiple branches can be brought together using a &lt;em&gt;merge&lt;/em&gt; process. If some of the changes apply to the same lines of code, there is a &lt;em&gt;merge conflict&lt;/em&gt;, and it's up to you as the developer to look at the mismatched changes and &lt;em&gt;resolve&lt;/em&gt; the conflict by picking out what the right contents are.&lt;/p&gt;

&lt;p&gt;Historically, most repos use a branch called &lt;code&gt;master&lt;/code&gt; as the primary development branch. More recently, the community has started switching to use a primary branch named &lt;code&gt;main&lt;/code&gt; instead. But, you can configure Git to use any branch name as the "default development branch" if you want.&lt;/p&gt;

&lt;p&gt;Git uses the term &lt;em&gt;checking out&lt;/em&gt; to refer to updating the working copy files on disk, based on previously committed values. Typically you check out a branch, which overwrites the files on disk to match the files as they exist in the latest commit of the branch. However, you can check out other versions of files as well&lt;/p&gt;

&lt;p&gt;Uncommitted changes can be copied and saved for later by creating a &lt;em&gt;stash&lt;/em&gt;. A stash is kind of like an unnamed commit - it again points to specific files at a certain point in time, but it doesn't exist in a branch. Stashed changes can later be applied on top of your working copy.&lt;/p&gt;

&lt;p&gt;Overall, the Git data workflow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-staging-workflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-staging-workflow.png" alt="Git blob"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Git Internals
&lt;/h3&gt;

&lt;p&gt;I really feel that &lt;strong&gt;understanding Git's internal data structures is critical to understanding how Git works and how to use it correctly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Git tracks all content using SHA1 hashes of byte data. Running any specific sequence of bytes through the hashing function calculates a specific hex string as a result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sha1&lt;/span&gt;

&lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abcd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;81fe8bfe87576c3ecb22426f8e57847382917acf&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;abce&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0a431a7631cabf6b11b984a943127b5e0aa9d687&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;readme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;README.md&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readme&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;45257c0245c56a4d5990827b044f897c674c8512&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git hashes files and data structures, then stores them inside the &lt;code&gt;.git&lt;/code&gt; folder based on the hash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/my-project
  /.git
    /objects
      /00
      /01
      ...
      /81
        81fe8bfe87576c3ecb22426f8e57847382917acf
      /82
      ...
      /fe
      /ff

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git has three primary internal data structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;blobs&lt;/em&gt; are file contents, and identified by a hash of the file's bytes&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;file trees&lt;/em&gt; associate folder and file names with file blobs, and are identified by a hash of the file tree data structure&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;commits&lt;/em&gt; contain metadata (author, timestamp, message), point to a specific file tree, and are identified by a hash of the commit data structure&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Contains&lt;/th&gt;
&lt;th&gt;Identified By&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blob&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File contents&lt;/td&gt;
&lt;td&gt;Hash of the file's bytes&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fobject-blob.png" alt="Git blob"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Associates names and folder definitions with file blobs&lt;/td&gt;
&lt;td&gt;Hash of the file tree data structure&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fobject-tree.png" alt="Git file tree"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Commit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Metadata for author, commit timestamps, and message&lt;/td&gt;
&lt;td&gt;Hash of the commit data structure&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fobject-commit.png" alt="Git commit"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A file tree may point to multiple other file trees for subfolders:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fobjects-example.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fobjects-example.png" alt="Git nested file trees"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Commit objects themselves form a linked list, which points backwards to earlier commits based on their hashes: &lt;code&gt;A &amp;lt;- B &amp;lt;- C &amp;lt;- D&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fcommit-list.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fcommit-list.png" alt="Git commit linked list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Git "ref" is a name label that points to a specific commit. Branches are names associated with a given ref, where each time a new commit is made, the ref is updated to point to that latest commit. So, you can start from the branch ref pointer, then walk backwards through the chain of commits to see the history.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fbranch-pointer-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fbranch-pointer-2.png" alt="Git branch pointers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HEAD&lt;/code&gt; is a ref that points to "whatever the current active commit" is. Normally this is the same as the current branch pointer, but if you check out a specific earlier commit, you get the ever-popular warning about a "detached &lt;code&gt;HEAD&lt;/code&gt;". This just means that &lt;code&gt;HEAD&lt;/code&gt; is pointing to a specific commit instead of a branch, and if you make any new commits, they won't be part of any branch.&lt;/p&gt;

&lt;p&gt;Because commits are a linked list based on hashes, and the hashes are based on byte contents of files and other structures, changing any one bit in an earlier commit would have a ripple effect - every hash of each commit after that would be different.&lt;/p&gt;

&lt;p&gt;Git commit objects are &lt;em&gt;immutable&lt;/em&gt; - once created, they cannot actually be changed. This means that you can't change history, exactly - you can only create an alternate history.&lt;/p&gt;

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

&lt;p&gt;I've seen a lot of arguments about whether it's better to use a Git GUI tool, or use Git from the command line. To those people, I say: &lt;strong&gt;why not both?&lt;/strong&gt; :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fwhy-not-both.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fwhy-not-both.gif" alt="Why not both?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I find that &lt;strong&gt;having a Git GUI tool is absolutely invaluable&lt;/strong&gt;. It makes visualizing the state of the repository and its branches much easier, and many operations are &lt;em&gt;way&lt;/em&gt; simpler via a GUI. For example, I can view the diffs for many pieces of a file at once, and selectively add specific changes to the staging area by clicking "Add Hunk" or CTRL-clicking a few lines to select them and clicking "Add Lines". This is much simpler and more intuitive than trying to use Git's "patch editing" text UI to manipulate pieces of changes. Interactive rebasing is also &lt;em&gt;much&lt;/em&gt; easier to do via a GUI. I can't remember what the different options like "pick" mean, but it's straightforward to use a GUI listview with arrow buttons that lets you reorder commits and squash them together.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;strong&gt;it's often faster to create or switch branches from the CLI&lt;/strong&gt;. You can add all changed files to the staging area with a single command of &lt;code&gt;git add -u&lt;/code&gt;. And of course, if you are using a remote system via SSH, you probably do only have the Git CLI available.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;I use &lt;em&gt;both&lt;/em&gt; a Git GUI, &lt;em&gt;and&lt;/em&gt; the CLI, based on what tasks I'm doing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I primarily use &lt;a href="https://sourcetreeapp.com/" rel="noopener noreferrer"&gt;Atlassian SourceTree&lt;/a&gt; (Win, Mac). It's very powerful, with a lot of options, and has a good built-in UI for interactive rebasing. It also happens to be free. The biggest downside is that it doesn't have a way to view the contents of the repo file tree as of a given commit.&lt;/p&gt;

&lt;p&gt;Other Git tools I've used in some form include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://gitextensions.github.io/" rel="noopener noreferrer"&gt;Git Extensions for Windows&lt;/a&gt; (Win): integrates with Windows Explorer to let you perform Git operations from the filesystem. I mostly use this to do a quick view of a given file's history if I happen to be browsing the folder contents of the repo.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://git-fork.com/" rel="noopener noreferrer"&gt;Git Fork&lt;/a&gt; (Win, Mac): excellent UI design, and does have an interactive rebase UI. Recently switched from being free to $50, but likely worth paying for.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sublimemerge.com/" rel="noopener noreferrer"&gt;Sublime Merge&lt;/a&gt; (Win, Mac, Linux): from the makers of Sublime Text. Fewer options and tool integrations, but very snappy. Tells you what CLI operations it's doing when you try to push or pull, so it expects familiarity with the CLI. $100, but will run for a while with nag messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also &lt;a href="https://www.git-tower.com/windows" rel="noopener noreferrer"&gt;Tower&lt;/a&gt; (Win, Mac) and &lt;a href="https://www.gitkraken.com/git-client" rel="noopener noreferrer"&gt;Git Kraken&lt;/a&gt; (Win, Mac, Linux), which have slick UIs but require yearly subscriptions, and &lt;a href="https://git-scm.com/downloads/guis" rel="noopener noreferrer"&gt;a laundry list of other smaller Git GUIs&lt;/a&gt;. There's even "text-based UI" tools like &lt;a href="https://github.com/jesseduffield/lazygit" rel="noopener noreferrer"&gt;&lt;code&gt;lazygit&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/extrawurst/gitui" rel="noopener noreferrer"&gt;&lt;code&gt;gitui&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://github.com/chriswalz/bit" rel="noopener noreferrer"&gt;&lt;code&gt;bit&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All major IDEs have Git integration. &lt;a href="https://www.jetbrains.com/idea/features/" rel="noopener noreferrer"&gt;JetBrains IDEs like IntelliJ and WebStorm have excellent Git capabilities&lt;/a&gt;. &lt;a href="https://code.visualstudio.com/docs/editor/versioncontrol" rel="noopener noreferrer"&gt;VS Code has adequate Git integration&lt;/a&gt;, but really needs &lt;a href="https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack" rel="noopener noreferrer"&gt;additional extensions like Git History and GitLens&lt;/a&gt; to be useful.&lt;/p&gt;

&lt;p&gt;I also really prefer using external diff tools for comparing complete files, or fixing merge conflicts. I personally use &lt;a href="https://www.scootersoftware.com/" rel="noopener noreferrer"&gt;Beyond Compare&lt;/a&gt; as my external diff tool, and &lt;a href="https://sourcegear.com/diffmerge/" rel="noopener noreferrer"&gt;DiffMerge&lt;/a&gt; as my conflict resolution diffing tool.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Improving CLI Logging
&lt;/h3&gt;

&lt;p&gt;The default &lt;code&gt;git log&lt;/code&gt; output is ugly and hard to read. Whenever I start using Git on a new machine, the very first thing I do is browse to &lt;a href="https://coderwall.com/p/euwpig/a-better-git-log" rel="noopener noreferrer"&gt;https://coderwall.com/p/euwpig/a-better-git-log&lt;/a&gt; and copy-paste the instructions for creating a &lt;code&gt;git lg&lt;/code&gt; alias to set up a much pretter CLI logging view that shows the branch and commit message history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&amp;gt;%Creset' --abbrev-commit"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives us this view whenever we run &lt;code&gt;git lg&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-lg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-lg.jpg" alt="git lg output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href="https://www.atlassian.com/git/tutorials/git-log" rel="noopener noreferrer"&gt;&lt;code&gt;git log&lt;/code&gt; accepts a variety of filtering options&lt;/a&gt;, including text strings, dates, branches, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preparing Commits in Pieces
&lt;/h3&gt;

&lt;p&gt;I've seen comments that complain that the Git staging area is confusing. To me, &lt;strong&gt;the staging area is one of the most valuable features of Git&lt;/strong&gt; - it lets me carefully craft commits that contain &lt;em&gt;only&lt;/em&gt; the code that belongs together.&lt;/p&gt;

&lt;p&gt;When I work on a task, I frequently end up modifying multiple files before I'm ready to make a commit. However, &lt;strong&gt;the changes might logically belong in several smaller commits instead of one big commit&lt;/strong&gt;. If I do &lt;code&gt;git add some-file&lt;/code&gt;, it adds &lt;em&gt;all&lt;/em&gt; the current changes in the file to the staging area. Instead, &lt;strong&gt;I often want to stage just a couple sections from file A, and a couple sections from file B, and maybe all of file C, because those are the changes that should go together in one commit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can do this from the commandline using the &lt;code&gt;git add -p&lt;/code&gt; flag, which brings up a text UI that lets you view each "hunk" of changes in a file, and decide whether to stage that hunk or not. However, &lt;strong&gt;I strongly recommend using a Git GUI tool like SourceTree for adding pieces of files&lt;/strong&gt; , because it's easier to click "Add Hunk" or CTRL-click a couple lines and click "Add Lines" than it is try to decipher what the command abbreviations in the text UI actually mean:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-add-hunk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-add-hunk.jpg"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fsourcetree-stage-hunks.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fsourcetree-stage-hunks.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've got these pieces added, you can make a commit with just chose changes, and repeat the process for the next commit. This is a key part of the "making small commits" practice that I cover below.&lt;/p&gt;

&lt;p&gt;On the flip side, sometimes you &lt;em&gt;do&lt;/em&gt; just want to add everything that's been changed at once. In that case, the fast way is to run &lt;code&gt;git add -u&lt;/code&gt; from the command line, which adds all modified files to the staging area.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stashing Changes
&lt;/h3&gt;

&lt;p&gt;Stashes are most useful when you've got some modified files that aren't committed, and need to set those aside to work on a different branch for a while. Git's list of stashes acts like a stack data structure, but you can also supply names for stash entries when you create them. Creating stash entries normally resets the modified files back to the latest commit, but you can choose to leave the modifications in place.&lt;/p&gt;

&lt;p&gt;From the CLI, the main options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git stash&lt;/code&gt;: save a copy of local changes for later reuse, and clears the working directory/index

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git stash push&lt;/code&gt;: creates a new stash entry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git stash pop&lt;/code&gt; applies changes from the top stash entry and removes it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git stash apply stash@{2}&lt;/code&gt;: applies changes from the third stash entry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git stash -p&lt;/code&gt;: choose specific pieces to stash&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git checkout stash@{2} -- someFile&lt;/code&gt;: retrieve a specific file contents from the stash&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;But, this is another situation where it's particularly useful to use a GUI instead. It's easier to just click a "Stash" button in a toolbar and type in a name for the entry to create one, or to expand a "Stashes" section of a treeview, right-click an entry, and "Apply Stash" to apply a stash.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working with Branches
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Creating and Switching Branches
&lt;/h4&gt;

&lt;p&gt;Git has a bunch of different commands for working with branches. The most common way to create a branch is actually with &lt;strong&gt;&lt;code&gt;git checkout -b NAME_OF_NEW_BRANCH&lt;/code&gt;&lt;/strong&gt;. That creates a new branch, starting from the latest commit on the current branch, and switches to it.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;git checkout NAME_OF_EXISTING_BRANCH&lt;/code&gt; (without the &lt;code&gt;-b&lt;/code&gt; flag) to switch to an existing branch.&lt;/p&gt;

&lt;p&gt;There's many other branching commands - see &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging" rel="noopener noreferrer"&gt;the Git docs&lt;/a&gt; and other pages like &lt;a href="https://devhints.io/git-branch" rel="noopener noreferrer"&gt;this Git branching cheatsheet&lt;/a&gt; for lists of commands and options.&lt;/p&gt;

&lt;h4&gt;
  
  
  Fetching, Pushing, and Pulling Branches
&lt;/h4&gt;

&lt;p&gt;Most Git network operation commands accept the name of the remote repo to talk to, but assume that you want to talk to the &lt;code&gt;origin&lt;/code&gt; remote repo by default if you don't specify a remote name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git fetch&lt;/code&gt; tells Git to contact another repo, and download copies of all commits that the local repo doesn't have stored. This includes information on branches in the remote repo as well.&lt;/p&gt;

&lt;p&gt;Once your repo has downloaded the list of remote branches, you can create a &lt;em&gt;local&lt;/em&gt; branch based on the remote branch's name, with &lt;code&gt;git checkout NAME_OF_REMOTE_BRANCH&lt;/code&gt;. Git will create a new branch that points to the same commit. It also sets up the local branch to &lt;em&gt;track&lt;/em&gt; the remote branch, which means that any pushes from the local branch will update the remote branch.&lt;/p&gt;

&lt;p&gt;Later, you can update the remote branch with the new commits you made locally, with &lt;code&gt;git push&lt;/code&gt;. You can also push local branches taht the remote repo doesn't know about yet.&lt;/p&gt;

&lt;p&gt;If the remote branch has commits you don't have in your local branch, &lt;code&gt;git pull&lt;/code&gt; will both fetch the set of new commits into your local repo, &lt;em&gt;and&lt;/em&gt; update your local branch to contain those commits.&lt;/p&gt;

&lt;p&gt;If you rewrite history on your local branch so that it's different than the remote branch, a &lt;code&gt;git push&lt;/code&gt; attempt will fail with an error. You can &lt;em&gt;force push&lt;/em&gt; , which will hard-update the remote branch to use these commits instead. &lt;strong&gt;Force pushing is semi-dangerous, depending on workflow.&lt;/strong&gt; If someone else pulled the old history, and you force-push, now they have a conflict to deal with. Force pushing is a valuable tool if you need it, and can be a legitimate solution to fixing problems or repeatedly updating a PR, but should be used cautiously. Think of it as a chainsaw - if you need it, you need it, you just have to be very careful when using it :)&lt;/p&gt;

&lt;h4&gt;
  
  
  Merging Branches
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Merging&lt;/em&gt; allows you to take changes and history that exist on branch B, and combine them into the changes on your current branch A. The assumption is that both branches have a common set of ancestor commits, and two different sets of changes (either to different files, or even the same files). Merging creates a new "merge commit" on the current branch that has all of the changes together in one spot. This is used to let developers collaborate by writing code separately, but combine their changes together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fmerging-after.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fmerging-after.png" alt="Merging branches - before"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merging is done with &lt;code&gt;git merge OTHER_BRANCH_NAME&lt;/code&gt;, which tells Git to merge from the other branch into the current branch.&lt;/p&gt;

&lt;p&gt;If the changes on the two branches interfere with each other, there's a merge conflict. Git will mark the file with text strings indicating the two mismatched sections. It's up to you to fix the problem, save the corrected file, add it, and finish the merge commit. I like using SourceGear DiffMerge as a GUI tool for fixing conflicts, but VS Code also does a nice job of highlighting conflict markers in files and offering hover buttons to pick one side or the other.&lt;/p&gt;

&lt;h4&gt;
  
  
  Feature Branch Strategies
&lt;/h4&gt;

&lt;p&gt;Most teams use some kind of a "feature branch" strategy for development. They have a primary development branch such as &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;master&lt;/code&gt;, or &lt;code&gt;develop&lt;/code&gt;. Any time a developer starts work on a new task, they create a new branch based on the primary branch, and often using the name and ID of a task/issue as the branch name: &lt;code&gt;git checkout -b feature/myapp-123-build-todos-list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The developer works on their feature for a while. Once the work is complete, they push the branch up to the team's central repository, other team members review the changes, the developer makes any needed fixes from the review, and then the feature branch is merged back into the primary development branch.&lt;/p&gt;

&lt;p&gt;Developers may need to pull down changes that have been added to the primary branch, then "merge down" from the primary branch into their feature branch. Merging the feature branch back into the primary branch is referred to as "merging up".&lt;/p&gt;

&lt;h4&gt;
  
  
  Pull Requests
&lt;/h4&gt;

&lt;p&gt;If you've worked with Git at all, you've probably heard the term "pull request" (also know as a "PR" for short, or occasionally "merge request") before. Strictly speaking, a "pull request" isn't even a Git concept - it's a merging workflow that is built on top of Git by repository hosting sites and tools like Github, Gitlab, and Bitbucket.&lt;/p&gt;

&lt;p&gt;Pull Requests are an approach to doing code reviews and handling merging at the central Git repo/server level. This is typically associated with using feature branches. A developer pushes up their completed feature branch, and creates a PR that will merge &lt;code&gt;some-feature&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt;. Other devs can look at the page for the PR, see the file diffs, and leave comments on specific lines suggesting changes. The feature dev makes more commits based on those suggestions, pushes them up, and the PR is updated to reflect the changes. After other team members approve, the PR can be merged and the feature branch can be deleted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Updating Branches in the Background
&lt;/h4&gt;

&lt;p&gt;Normally, the main way to update a local copy of a branch is to &lt;code&gt;git checkout some-branch&lt;/code&gt; and then &lt;code&gt;git pull&lt;/code&gt;. But, if I'm working on a feature branch, I often have unsaved changes and don't want to switch over to the main branch just to do a pull.&lt;/p&gt;

&lt;p&gt;There's &lt;a href="https://stackoverflow.com/a/17722977/62937" rel="noopener noreferrer"&gt;&lt;strong&gt;a really useful trick for doing a "background pull" of a branch without checking it out&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;git fetch &amp;lt;remote&amp;gt; &amp;lt;remoteBranch&amp;gt;:&amp;lt;localBranch&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, say I'm on &lt;code&gt;features/some-feature&lt;/code&gt;, and I want to update my &lt;code&gt;main&lt;/code&gt; branch without switching to it. Typically the local branch and remote branch have the same name. So, I can run:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;git fetch origin main:main&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and Git will download any new commits on the remote &lt;code&gt;origin/main&lt;/code&gt; branch, then update my local &lt;code&gt;main&lt;/code&gt; branch to have those commits too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rewriting Git History
&lt;/h3&gt;

&lt;p&gt;There's a variety of ways to alter the history in a Git repository. Each technique is useful in different situations, and these are often valuable for fixing earlier problems. As mentioned earlier, Git commits are immutable, so you can never actually modify them - you can only &lt;em&gt;replace&lt;/em&gt; commits with new ones. So, &lt;strong&gt;when we "rewrite history", we're actually creating an "alternate history" instead&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It's critical that &lt;strong&gt;you should only ever rewrite history that is still local to your own repository and has never been pushed up to another repository!&lt;/strong&gt; As long as commits haven't been pushed, no one else cares about them, and you can rewrite them to your heart's content. But, once they've been pushed, someone else's Git repo clone may be relying on the old history, and changing that history will likely cause conflicts for them.&lt;/p&gt;

&lt;h4&gt;
  
  
  Amending Commits
&lt;/h4&gt;

&lt;p&gt;The easiest technique for rewriting history is to "amend" the latest commit.&lt;/p&gt;

&lt;p&gt;Amending a commit really means replacing it with a slightly different one. This can be done via &lt;code&gt;git commit --amend&lt;/code&gt;, or a corresponding option in a GUI tool:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-amend.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-amend.png" alt="Amending Git commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Technically, the old commit still exists in Git's storage, but the current branch ref now points to the newly created commit instead.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resetting Branches
&lt;/h4&gt;

&lt;p&gt;Since branch refs are pointers to a given commit, we can &lt;em&gt;reset&lt;/em&gt; a branch by updating the ref to point to an earlier commit. This is typically used to roll back some of the commits you made.&lt;/p&gt;

&lt;p&gt;When you reset a branch, you have three options for what happens to the files on disk and in the staging area:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git reset&lt;/code&gt;: move a branch pointer to point to a different commit

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--soft&lt;/code&gt;: keep the current files on disk and in the staging area&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--mixed&lt;/code&gt;: keep the current files on disk, but clear the staging area&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--hard&lt;/code&gt;: clear the staging area &lt;em&gt;and&lt;/em&gt; make the working directory look exactly like this specific commit&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So, &lt;code&gt;git reset --soft&lt;/code&gt; is fairly "safe" to do, because it doesn't change any files on disk. &lt;code&gt;git reset --hard&lt;/code&gt; is "dangerous", because it will wipe out any files that were changed during these commits &lt;em&gt;or&lt;/em&gt; that haven't been committed yet, and replace them all with the files from this exact commit.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git reset&lt;/code&gt; requires a commit identifier as an argument. This could be a specific commit hash ( &lt;code&gt;git reset ABCD1234&lt;/code&gt; ), or &lt;a href="https://devhints.io/git-revisions" rel="noopener noreferrer"&gt;some other revision identifier&lt;/a&gt;. You can even update your current branch to point to the same commit as a different branch ( &lt;code&gt;git reset --hard some-other-branch&lt;/code&gt; ).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Freset-commit.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Freset-commit.svg" alt="Resetting Git commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Rebasing Branches
&lt;/h4&gt;

&lt;p&gt;"Rebasing" is a technique that is an alternative to merging for updating one branch with another's changes. Instead of combining the two sets of changes directly, rebasing rewrites history to act as if the current branch was created &lt;em&gt;now&lt;/em&gt;, off the latest commits on the source branch, instead of starting from the earlier commits. Similar to merging, this is done with &lt;code&gt;git rebase OTHER_BRANCH_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Imagine that the &lt;code&gt;main&lt;/code&gt; branch has commits &lt;code&gt;A &amp;lt;- B&lt;/code&gt; to start with, and we make a feature branch starting from commit B. Now, someone else merges some more work into &lt;code&gt;main&lt;/code&gt;, giving it commits &lt;code&gt;A &amp;lt;- B &amp;lt;- C &amp;lt;- D&lt;/code&gt;. If we rebase our feature branch against &lt;code&gt;main&lt;/code&gt;, it's kind of like cutting off the line of our feature branch, transplanting it to the end, and pretending we really started this branch after commit &lt;code&gt;D&lt;/code&gt; instead of &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frebase.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frebase.svg" alt="Resetting Git commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Reverting Commits
&lt;/h4&gt;

&lt;p&gt;Resetting a branch effectively throws away the newer commits. What if we want to undo the changes in an earlier commit, but keep the history since then?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reverting&lt;/em&gt; a commit with &lt;code&gt;git revert&lt;/code&gt; creates a new commit that has the opposite changes of the commit you specified. It doesn't remove the original commit, so the history isn't actually modified - it just inverts the changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frevert-concept.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frevert-concept.png" alt="Reverting Git commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Cherry-Picking
&lt;/h4&gt;

&lt;p&gt;Cherry-picking allows you to copy the &lt;em&gt;changes&lt;/em&gt; in specific commits, and apply those as new commits onto a different branch. For example, maybe there's an urgent patch that has to be created directly onto a hotfix branch and deployed to production, but you need to also make sure that &lt;code&gt;main&lt;/code&gt; has that commit as well. You can cherry-pick the individual commit from the hotfix branch over onto &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git cherry-pick&lt;/code&gt; accepts either a single commit reference, or a commit range. Note that the range excludes the first commit you list. if I run &lt;code&gt;git cherry-pick A..E&lt;/code&gt;, then it will copy commits &lt;code&gt;B,C,D,E&lt;/code&gt; over onto this branch. This creates new commits with new hashes (because the timestamps and parent commits are different), but preserves the diffs and commit metadata.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_004.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_004.png" alt="Reverting Git commits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Interactive Rebasing
&lt;/h4&gt;

&lt;p&gt;"Rebasing" involves rewriting the entire history of a branch. There is a variation on this called "interactive rebasing", which allows you to selectively modify earlier commits on a branch. This is done with &lt;code&gt;git rebase -i STARTING_COMMIT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Interactive rebasing lets you perform several different types of modifications. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit the message for a commit&lt;/li&gt;
&lt;li&gt;Reorder commits&lt;/li&gt;
&lt;li&gt;Squash multiple commits together&lt;/li&gt;
&lt;li&gt;Remove commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you specify the desired changes to the commit history, Git will execute the modifications you listed, and update all commits after the starting point accordingly. As with other history rewriting operations, this always produces a new set of commits after any changed commit, with new hashes even if the rest of the contents haven't changed due to the parent commits changing.&lt;/p&gt;

&lt;p&gt;Running an interactive rebase from the CLI brings up a list of all commits after the starting commit in your text editor, along with a column of odd command names like "pick" and "squash". You rework the commits by actually modifying the text in the file, and then saving and exiting. For example, if you want to swap a couple commits, you'd cut one of the text lines and paste it in a different location.&lt;/p&gt;

&lt;p&gt;I find this very unintuitive to work with, so &lt;strong&gt;I &lt;em&gt;strongly&lt;/em&gt; recommend using a Git GUI for any interactive rebase operations&lt;/strong&gt;. SourceTree and Fork have pretty good UIs for performing interactive rebasing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_002.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_002.png"&gt;&lt;/a&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_003.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Frewriting_history_003.png"&gt;&lt;/a&gt;&lt;br&gt;
 &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fsourcetree_interactive_rebase.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fsourcetree_interactive_rebase.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Reflog
&lt;/h4&gt;

&lt;p&gt;It's actually very hard to completely wipe out your Git commits and permanently lose work. Even if you do a &lt;code&gt;git reset --hard&lt;/code&gt; and the commits &lt;em&gt;appear&lt;/em&gt; to have vanished, Git still has a copy of those commits saved internally.&lt;/p&gt;

&lt;p&gt;If you do end up in a situation where you can't see those commits referenced from any tag or branch, you can use the Git &lt;em&gt;reflog&lt;/em&gt; to look back and find them again. The reflog shows all commits, no matter what branch they're on or whether there's still a meaningful pointer to that commit. That way you can check them out again, create a new tag or branch pointing to those commits, or at least see the diffs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Freflog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Freflog.png" alt="Git reflog"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Advanced History Rewriting
&lt;/h4&gt;

&lt;p&gt;Finally, Git supports some very advanced tools for rewriting history at the whole repository level. In particular, &lt;code&gt;git filter-branch&lt;/code&gt; lets you perform tasks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rewriting file names and paths in the history (example: changing files in &lt;code&gt;./src&lt;/code&gt; so that they now appear to be in the repo root)&lt;/li&gt;
&lt;li&gt;creating a new repo that contains just certain folders from the original, but with all their history&lt;/li&gt;
&lt;li&gt;rewriting actual file contents in many historical commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;git filter-branch&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; notoriously slow, so there's other external tools that can perform similar tasks. While I haven't used it, &lt;a href="https://github.com/newren/git-filter-repo" rel="noopener noreferrer"&gt;https://github.com/newren/git-filter-repo&lt;/a&gt; claims to be able to run the same kinds of operations much more quickly, and is apparently now even recommended by the actual Git docs.&lt;/p&gt;

&lt;p&gt;Sometimes repos end up with very large files cluttering the history, and you want to rewrite the history to pretend those files never existed. A tool called &lt;a href="https://rtyley.github.io/bfg-repo-cleaner/" rel="noopener noreferrer"&gt;the BFG Repo Cleaner&lt;/a&gt; does a good job of that.&lt;/p&gt;

&lt;p&gt;If these existing tools don't do what you need, you can always write your own. &lt;a href="https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/" rel="noopener noreferrer"&gt;I once wrote a set of Python-based tools to rewrite the JS source for for an entire repository with multiple years of history&lt;/a&gt;, including optimizing it to run in just a few hours.&lt;/p&gt;

&lt;p&gt;These tools are very powerful and should not be something you use for day-to-day tasks. Think of them as fire extinguishers. You hope you never need to use them, but it's good to have it sitting around in case something happens.&lt;/p&gt;
&lt;h2&gt;
  
  
  Git Patterns and Best Practices
&lt;/h2&gt;

&lt;p&gt;So now that we've covered a bunch of commands and technical details, how do you actually &lt;em&gt;use&lt;/em&gt; Git well? Here's the things that I've found to be most helpful:&lt;/p&gt;
&lt;h3&gt;
  
  
  Write Good Commit Messages
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It's critical to write good commit messages&lt;/strong&gt;. It's not just a chore to satisfy the Git tools. You're leaving notes to any future developers on this project as to what changes were made, or even more importantly, &lt;em&gt;why&lt;/em&gt; those changes were made. Anyone can look at a set of diffs from a commit and see the changed lines, but without a good commit message, you may have no idea what the reason was to make those changes in the first place.&lt;/p&gt;

&lt;p&gt;There's lots of good articles out there discussing rules for writing commit messages, with plenty of good advice. I personally don't care so much about things like "max 72 characters per line" or "use present tense for the top line and past tense for other lines", although there's valid reasons to do those things. To me, the critical rules are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Always start the commit message with a relevant issue tracker ID number&lt;/strong&gt; if there is one. That way you can always go back to the issue tracker later to see more details on what the specific task was supposed to be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First line should be a short high-level summary of the &lt;em&gt;intent&lt;/em&gt; of the changes&lt;/strong&gt;. This line of the message is what will be shown in any Git history log display, so it needs to both fit in one line, and clearly describe the commit overall. Aim more for the &lt;em&gt;purpose&lt;/em&gt; of the changes than a specific list of "what changed" in this line.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you have any further details, add a blank line, then write additional paragraphs or bullet points&lt;/strong&gt;. Write as much as you want here! This section will usually be collapsed by default in a Git UI, but can be expanded to show more details. I've seen some excellent commit messages that were multiple paragraphs long, and they provided important context for why changes were being made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical example of this format would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MYAPP-123: Rewrite todos slice logic for clarity

- Added Redux Toolkit
- Replaced handwritten reducer with `createSlice`. This simplified the logic considerably, 
  because we can now use Immer and it auto-generates the action creators for us.
- Updated `TodosList` to use the selectors generated by the slice.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Make Small, Focused Commits
&lt;/h3&gt;

&lt;p&gt;This goes hand-in-hand with the advice to write good commit messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commits should be relatively small and self-contained, conceptually&lt;/strong&gt;. One commit might touch several files, but the changes in those files should be closely related to each other. There's multiple reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes it easier to describe the changes in the commit&lt;/li&gt;
&lt;li&gt;It's easier to look at that one commit and see what changes it includes&lt;/li&gt;
&lt;li&gt;If the commit needs to be reverted later, there's fewer other changes that would be affected&lt;/li&gt;
&lt;li&gt;When someone looks at the line-by-line history, there will be more specific comments associated with each line ("Fixed bug X" instead of "Made a bunch of changes", etc)&lt;/li&gt;
&lt;li&gt;It's easier to bisect the commit history and narrow down what changes might have caused a particular bug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, say I'm adding a new JS library to a project. I would make one commit that just updates &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;yarn.lock&lt;/code&gt;, then put the initial code changes using that library into a separate commit. You can see an example of this commit approach in &lt;a href="https://github.com/reduxjs/redux-fundamentals-example-app/commits/tutorial-steps" rel="noopener noreferrer"&gt;the commits for the "Redux Fundamentals" tutorial example app&lt;/a&gt; I wrote.&lt;/p&gt;

&lt;p&gt;To me, &lt;strong&gt;the commit history should "tell a story" of how a given task was accomplished&lt;/strong&gt;. Someone should be able to read through the series of commits, whether it be during the PR review process or years down the road, and be able to understand my thought process for what changes I made and why I made them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clean Up Commit History Before Pushing
&lt;/h3&gt;

&lt;p&gt;I frequently have to make "WIP" commits as I'm working on a task. Maybe I've just made a bunch of edits, the code is now mostly working, and I want to record a checkpoint before I keep going. Or, maybe I forgot to commit a particular bit of code, added it in another commit later, but it doesn't really belong as part of the "story" that I'm telling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I often use interactive rebase to clean up my commits before I push a branch for a PR&lt;/strong&gt;. Just because I have some junk commits in my history locally doesn't mean that the rest of the world needs to know or care that was part of my actual progress for this task. The "story" that I'm telling with my commits is sort of the idealized version - ie, "let's pretend that I did this task perfectly without any mistakes along the way".&lt;/p&gt;

&lt;h3&gt;
  
  
  Only Rewrite Unpushed History
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier: as long as a branch is still local and hasn't been pushed, it's fair game - rewrite it all you want! Once it's been pushed, though, you should avoid rewriting it.&lt;/p&gt;

&lt;p&gt;The one main exception to that is if the branch is still up for PR, and you redo the history. At that point, most likely no one depends on it yet, so you can get away with force-pushing the branch to update the PR. (The React team does this frequently.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Keep Feature Branches Short-Lived
&lt;/h3&gt;

&lt;p&gt;There's no hard rule about how many lines of code or commits can be in a branch. In general, though, try to keep feature branches relatively short-lived. That way the size of the changes to merge in a PR is smaller, and it's less likely that you'll need to pull down changes from someone else.&lt;/p&gt;

&lt;p&gt;Some people argue about whether it's better to &lt;em&gt;merge&lt;/em&gt; feature branches back into the primary branch, or &lt;em&gt;rebase&lt;/em&gt; them when they're done to keep the main branch history "clean and linear". I kinda like having merge commits, personally - I prefer seeing when things got merged in. The important thing is to pick a convention as a team and stick with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Archeology with Git
&lt;/h2&gt;

&lt;p&gt;So why do all these good commit practices matter?&lt;/p&gt;

&lt;p&gt;Say you're working in a codebase with multiple years of history. One day, you're assigned a task to work on some portion of the codebase. Maybe it's fixing a bug that just popped up, or adding a new feature. You open up a file, and there's hundreds of lines of code inside. You read through it, and it's kind of ugly - there's a bunch of extra conditions in the logic, and you're really not sure how it ended up this way.&lt;/p&gt;

&lt;p&gt;Reading through that file tells you &lt;em&gt;what&lt;/em&gt; the code does, &lt;em&gt;now&lt;/em&gt;. Unless the file has a lot of good comments, there may not be much information for &lt;em&gt;why&lt;/em&gt; the code is like that, or &lt;em&gt;how&lt;/em&gt; it got that way. We naturally have a tendency to assume that "whatever code is there currently must be correct", but that's not always true :)&lt;/p&gt;

&lt;p&gt;That's where having a good Git history is critical. Digging through a file's history can show you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who wrote each line of code&lt;/li&gt;
&lt;li&gt;When that code was changed, and what &lt;em&gt;other&lt;/em&gt; code changed at the same time&lt;/li&gt;
&lt;li&gt;What task the changes were part of&lt;/li&gt;
&lt;li&gt;What the intent was behind the change&lt;/li&gt;
&lt;li&gt;What the author was thinking at the time&lt;/li&gt;
&lt;li&gt;When a bug was introduced&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These can all be extremely valuable pieces of information when tracking down a bug or working on a feature.&lt;/p&gt;

&lt;h3&gt;
  
  
  Displaying Historical File Changes
&lt;/h3&gt;

&lt;p&gt;There's a variety of ways to view the history of changes to a file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git log&lt;/code&gt; lets you look at the commits that affected a specific file. IDEs and Git GUIs let you explore the history of a file as well, showing each commit its diffs, often including the ability to diff two arbitrary versions of a file. Some Git GUIs also let you explore the entire repo file tree as of a specific commit.&lt;/p&gt;

&lt;p&gt;Git has a feature called &lt;code&gt;git blame&lt;/code&gt;, which prints the commit ID, author, and timestamp for each line. The CLI output is hard to read, but every good IDE has the ability to show file blame information next to the actual code in a file. IDEs typically enhance the blame information to show you more details on the author, the commit message, and the commits before and after this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-file-blame.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.isquaredsoftware.com%2Fimages%2F2021-01-career-advice-git-usage%2Fgit-file-blame.png" alt="VS Code file blame view"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github offers a "blame" view as well, and makes it easy to jump back to view an earlier version of the repo. Github also lets you browse specific file versions and trees. For example, &lt;a href="https://github.com/reduxjs/react-redux/tree/v7.1.2" rel="noopener noreferrer"&gt;https://github.com/reduxjs/react-redux/tree/v7.1.2&lt;/a&gt; shows the React-Redux codebase as of tag &lt;code&gt;v7.1.2&lt;/code&gt;, and &lt;a href="https://github.com/reduxjs/react-redux/blob/5f495b23bcf3f03e0bee85fa5f7b9c2afc193457/src/components/connectAdvanced.js" rel="noopener noreferrer"&gt;https://github.com/reduxjs/react-redux/blob/5f495b23bcf3f03e0bee85fa5f7b9c2afc193457/src/components/connectAdvanced.js&lt;/a&gt; shows that exact file version. (Press &lt;code&gt;y&lt;/code&gt; while browsing a file on Github to change the URL to the exact file hash.)&lt;/p&gt;

&lt;h3&gt;
  
  
  Bisecting Bugs
&lt;/h3&gt;

&lt;p&gt;Git has a really neat command called &lt;code&gt;git bisect&lt;/code&gt;, which you can use to help find the exact commit where a bug was introduced. When you run &lt;code&gt;git bisect&lt;/code&gt;, you can give it a commit range where you &lt;em&gt;think&lt;/em&gt; the problem started. Git will then check out one commit, let you run whatever steps you need to with the app to determine if the bug is present or not, and then say &lt;code&gt;git bisect good&lt;/code&gt; or &lt;code&gt;git bisect bad&lt;/code&gt;. It then jumps to another commit and lets you repeat the process. It follows a splitting pattern that lets you narrow down the potential problem commit in just a few steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As software developers, we use lots of tools. Everyone has their own preferences for things like text editors and such, but everyone on a team is going to use the same version control system. In today's world, that's inevitably Git.&lt;/p&gt;

&lt;p&gt;Given how critical Git is to modern development, anything you can do to use it more effectively will pay dividends down the road, and anyone reading your commits will appreciate the effort you put into clearly describing what changes are happening and why. It might be a teammate reading your PR, an intern exploring the codebase next year, or even yourself revisiting code that you wrote many years ago.&lt;/p&gt;

&lt;p&gt;Ultimately, &lt;strong&gt;good Git practices are a key part of long-term codebase maintainability&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Git Tutorials&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/what-is-git" rel="noopener noreferrer"&gt;Atlassian Git tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://speakerdeck.com/alicebartlett/git-for-humans" rel="noopener noreferrer"&gt;Git for Humans slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Git Internals&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.githubusercontent.com/pluralsight/git-internals-pdf/master/drafts/peepcode-git.pdf" rel="noopener noreferrer"&gt;Git Internals ebook (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jwiegley.github.io/git-from-the-bottom-up/" rel="noopener noreferrer"&gt;Git from the Bottom Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/" rel="noopener noreferrer"&gt;A Visual Guide to Git Internals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/2020-12-17-commits-are-snapshots-not-diffs/" rel="noopener noreferrer"&gt;Commits are Snapshots, Not Diffs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://yurichev.com/news/20201220_git/" rel="noopener noreferrer"&gt;Git Internals exploration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Commit Messages&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://chris.beams.io/posts/git-commit/" rel="noopener noreferrer"&gt;How to Write a Git Commit Message&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.openstack.org/wiki/GitCommitMessages" rel="noopener noreferrer"&gt;Git Commit Message Good Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Operations&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.bloomca.me/2017/11/17/git-beyond-the-basics.html" rel="noopener noreferrer"&gt;Git Beyond the Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stosb.com/blog/advanced-git-commands-you-will-actually-use/" rel="noopener noreferrer"&gt;Advanced Git Commands You Will Actually Use&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cheat Sheets&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://marklodato.github.io/visual-git-guide/index-en.html" rel="noopener noreferrer"&gt;A Visual Git Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.git-tower.com/blog/git-cheat-sheet/" rel="noopener noreferrer"&gt;Tower Git Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gist.github.com/akras14/3d242d80af8388ebca60" rel="noopener noreferrer"&gt;akras14 Git Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DevHints Git cheat sheets: &lt;a href="https://devhints.io/git-revisions" rel="noopener noreferrer"&gt;revision syntax&lt;/a&gt;, &lt;a href="https://devhints.io/git-log" rel="noopener noreferrer"&gt;log syntax&lt;/a&gt;, &lt;a href="https://devhints.io/git-branch" rel="noopener noreferrer"&gt;branching commands&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Other Resources&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/k88hudson/git-flight-rules" rel="noopener noreferrer"&gt;Git Flight Rules: a guide for when things go wrong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markerikson/react-redux-links/blob/master/git-resources.md" rel="noopener noreferrer"&gt;React/Redux Links: Git Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>career</category>
      <category>git</category>
    </item>
    <item>
      <title>Coding Career Advice: Searching and Evaluating Online Information Efficiently</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Tue, 24 Nov 2020 03:00:00 +0000</pubDate>
      <link>https://dev.to/markerikson/coding-career-advice-searching-and-evaluating-online-information-efficiently-ca6</link>
      <guid>https://dev.to/markerikson/coding-career-advice-searching-and-evaluating-online-information-efficiently-ca6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;A while back I saw &lt;a href="https://twitter.com/bodil/status/1308783627908583430"&gt;this excellent quote on Twitter&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When I learn something today, I usually do it by piecing together clues gleaned from out of date tutorials and random forum posts until a coherent picture forms, and that is a skill you should practice relentlessly because it's the most valuable skill you will ever acquire.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I attribute much of my success as a developer to my ability to search for information online quickly and efficiently, absorb key pieces of info from the relevant search results, and then synthesize that information into a potential solution.&lt;/p&gt;

&lt;p&gt;To be honest, this is a really hard topic for me to write about, because it's something I've been doing my whole online life. It's kind of like trying to describe "How to learn and speak English" as a native speaker. It's not something I can exactly describe based on learning it, because it's a skill I naturally developed back during the dawn of the Web. It's also not something I think about, because by now it's entirely instinctive. Similarly, I can't go tell anyone "start using the internet back in 1995", or "spend most of your childhood learning to speed-read" - clearly that doesn't scale or actually help anyone else :)&lt;/p&gt;

&lt;p&gt;That said, I firmly believe that developing a strong ability to search for and evaluate information online is a key skill that every developer should aim for. I actually already described a form of this in my earlier post on &lt;a href="https://dev.to/markerikson/coding-career-advice-evaluating-software-libraries-and-tools-15bi-temp-slug-1312953"&gt;evaluating software libraries and tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here's my suggestions for a general set of steps to follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Suggested Search and Evaluation Process
&lt;/h2&gt;

&lt;p&gt;Know &lt;em&gt;what&lt;/em&gt; it is you're trying to find. Obviously you don't know the exact details yet, otherwise you wouldn't be looking :) But, think of it as drawing an outline, and then trying to find a picture that matches that outline. The better idea you have up front of what you're looking for, the easier it is to look at a result and say "this does or does not match what I'm looking for"&lt;/p&gt;

&lt;p&gt;Know &lt;em&gt;where&lt;/em&gt; to look for relevant information. Google is the typical starting point, but I'll use the search feature on other sites for specific things: NPM for JS libraries, Twitter for tweets, Github for code repos or usage snippets, and so on.&lt;/p&gt;

&lt;p&gt;Use specific phrases and keywords as part of your search. You might not even know what the relevant keywords are to begin with, but after opening up a few initial results, you might find some info that's in the same general category as what you're looking for. Start up a new search using specific relevant phrases you just found, and keep narrowing the results down based on those. (I'll throw an extra-special shout out to &lt;a href="https://dev.to/swyx/how-to-google-your-errors-2l6o"&gt;Shawn Swyx Wang's post on "How to Google Your Error Messages"&lt;/a&gt;, which both has some excellent advice for a common problem &lt;em&gt;and&lt;/em&gt; tweet-quotes me in the process.)&lt;/p&gt;

&lt;p&gt;Learn to skim search results quickly and do an initial filtering pass based on likely relevance. This includes looking at page titles or software library names, "last updated at" dates, URLs, and anything else in the actual search results list that can give you a sense of whether a given result is likely to be relevant and trustworthy. Learn to immediately disqualify search results as "too old", "likely spam or clickbait", or "just not relevant" as you move your eyes down the results list. Pop open potential candidates in a new tab for later review, and keep skimming results.&lt;/p&gt;

&lt;p&gt;Once you've got an initial set of potentially useful results opened up, skim the pages and get a sense of what the actual content is and whether it's worth looking at further. Consider the source (blog, docs site, tutorial), date, author, length, apparent level of detail, and overall content. If it doesn't look relevant, close the tab and move on to the next one. The emphasis here is on trying to figure out which of these results should be kept for the the real deeper reading and understanding portion of the process.&lt;/p&gt;

&lt;p&gt;Now that you have a good list of likely meaningful results, go back through them in more detail. You might want to take notes on your findings, bookmark some of the results and save them for later, or start up new searches based on some of the keywords you find.&lt;/p&gt;

&lt;p&gt;Finally, you should have accumulated a good set of info from across all these results. Maybe none of those pieces of info directly solves your problem by itself, but it's possible to take &lt;em&gt;some&lt;/em&gt; of the info as a basis for putting together your own solution. Think of it as lego blocks - maybe you didn't find a complete pre-assembled kit, but you've got enough blocks that you can build something yourself.&lt;/p&gt;

&lt;p&gt;Note that these steps aren't limited to Google searches. They apply as you look at just about any other search site or tool, even if you're looking for something like a software library on NPM.&lt;/p&gt;

&lt;p&gt;Additionally, one of the main reasons why I still use Firefox as my primary browser is the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/tree-style-tab/"&gt;Tree Style Tabs addon&lt;/a&gt;. It lets you switch from a row of tabs on top of the browser, to a sidebar that has a tree of tabs that can be nested and collapsed at any level. This makes it &lt;em&gt;much&lt;/em&gt; easier to have a large number of tabs open at once, including grouping results from different searches based on the starting page. (My understanding is that Chrome addons can't do the same kind of UI changes that Firefox addons can, and last I checked there wasn't a good equivalent of Tree Style Tabs for Chrome. Could easily have changed since the last time I looked, though.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;I'll briefly describe some specific cases where I went through this process myself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git History Rewriting
&lt;/h3&gt;

&lt;p&gt;In my post &lt;a href="https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/"&gt;Rewriting Git History and JS Source for Fun and Profit&lt;/a&gt;, I described how I completely migrated our team's Git repository history, by stripping out unused files and rewriting the JS source to modernize it at all points in the history of the codebase.&lt;/p&gt;

&lt;p&gt;When I started this task, I had some prior experience with rewriting Git history. I frequently used commands like &lt;code&gt;rebase&lt;/code&gt; in my daily work, and I had used &lt;code&gt;git filter-branch&lt;/code&gt; a few times. I also generally understood how Git's data structures worked, and that tools like JS codemods existed. So, I understood the general shape of what I wanted to do ("create an alternate Git history but with changed content", "rewrite JS source automatically on a large scale") and key terms that I needed to look for ("&lt;code&gt;git filter-branch&lt;/code&gt;", "rewrite Git history", "JS codemod"). I also assumed that what I wanted to do &lt;em&gt;must&lt;/em&gt; be possible, &lt;em&gt;somehow&lt;/em&gt; - I just didn't know the exact technical details of how.&lt;/p&gt;

&lt;p&gt;I probably spent at least a week doing initial research on this. I didn't find an exact solution, but I did find several critical resources that gave me much deeper understanding, key terms to look for, and ideas that shaped my potential solution:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://manishearth.github.io/blog/2017/03/05/understanding-git-filter-branch/"&gt;Understanding Git Filter-branch and the Git Storage Model&lt;/a&gt;: helped clarify my understanding of how &lt;code&gt;filter-branch&lt;/code&gt; works and how Git stores its data&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.bitleaks.net/blog/large-scale-git-history-rewrites/"&gt;Large scale Git history rewrites&lt;/a&gt;: gave me the idea for doing some of this work in Python&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wincent.com/blog/filter-branch"&gt;A tale of three filter-branches&lt;/a&gt;: described a rewrite process, and linked to a Ruby script that did low-level Git repo manipulation to speed up the rewrite work&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/sergelevin/pylter-branch"&gt;&lt;code&gt;sergelevin/pylter-branch&lt;/code&gt;&lt;/a&gt;: a Python lib that builds on &lt;code&gt;pygit2&lt;/code&gt; to provide an abstraction for iterating over Git history and rewriting it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of those pieces by itself was the entire solution, but together they gave me enough understanding to figure out how to build the actual solution I needed.&lt;/p&gt;

&lt;p&gt;By the time I was done building this, I had learned enough to write &lt;a href="https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/"&gt;a 6000-word blog post on the topic, off the top of my head, in about 5 hours&lt;/a&gt; :)&lt;/p&gt;

&lt;h3&gt;
  
  
  Searching for Info on How to Search
&lt;/h3&gt;

&lt;p&gt;I started this evening by searching online and evaluating info on how to search online and evaluate info efficiently. (How meta!)&lt;/p&gt;

&lt;p&gt;My first search was for &lt;a href="https://www.google.com/search?q=how+to+search+for+information+on+the+internet"&gt;&lt;code&gt;how to search for information on the internet&lt;/code&gt;&lt;/a&gt;. In a sense I didn't follow my own advice here, because that's more of a question or a phrase than specific keywords, but I didn't quite know where to start looking for details on this topic. Most of these results were either blogspam about search engine optimization, or too narrowly focused on how to actually type things into a search engine rather than how to look at the results. I also avoided any results with dates older than the last couple years, on the grounds that they probably weren't as relevant.&lt;/p&gt;

&lt;p&gt;That initial search turned into &lt;a href="https://www.google.com/search?q=effectively+evaluating+search+results"&gt;&lt;code&gt;effectively evaluating search results&lt;/code&gt;&lt;/a&gt;, which produced some better hits. I also saw the phrase "digital literacy", realized that was a relevant aspect of this topic, and searched for &lt;a href="https://www.google.com/search?q=digital+literacy+searching+for+information"&gt;&lt;code&gt;digital literacy searching for information&lt;/code&gt;&lt;/a&gt;. These queries gave me some better results, including a number of academic-related pages like university libraries.&lt;/p&gt;

&lt;p&gt;Ultimately, I didn't end up using those resources to write this post, but I have linked the best results in the "Further Information" section below.&lt;/p&gt;

&lt;h3&gt;
  
  
  React-Redux, React Native, and Jest
&lt;/h3&gt;

&lt;p&gt;Last year I fixed &lt;a href="https://github.com/reduxjs/react-redux/releases/tag/v7.1.2"&gt;a bug in React-Redux where it broke under React Native&lt;/a&gt;. As part of that, I needed to update our test suite to make it correctly test behavior with React Native, vs just ReactDOM.&lt;/p&gt;

&lt;p&gt;I remember having seen a tweet that day about "all the stuff I googled in a week as a software developer", so for fun I wrote down &lt;a href="https://gist.github.com/markerikson/5a7ea2d1053c2714d6d709294c970536"&gt;every Google search I did while trying to solve this particular React Native test setup problem&lt;/a&gt;. This included searches like &lt;code&gt;react uselayouteffect ssr&lt;/code&gt; to find a particular issue thread I knew existed in the React repo, &lt;code&gt;jest mockComponent.js Support for the experimental syntax 'classProperties' isn't currently enabled&lt;/code&gt; to find a solution to a particular error message I was seeing, and &lt;code&gt;microsoft ipod naming&lt;/code&gt; as a sidebar based on a discussion with a friend, to find the classic Microsoft self-parody video on how they're so bad at naming things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.mindtools.com/pages/article/internet-searching.htm"&gt;Seven Ways to Find What You Want On the Internet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libguides.library.curtin.edu.au/c.php?g=909870&amp;amp;p=6553346"&gt;Curtin University Library - Effective Internet Searching&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.girton.cam.ac.uk/e-guides/effective-internet-searching"&gt;Girton College - Planning a search strategy and picking a search engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libguides.exeter.ac.uk/searchtechniques/planning"&gt;University of Exeter - Effective Search Techniques&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.kathleenamorris.com/2018/11/20/evaluate-websites/"&gt;How to Evaluate Websites: A Guide for Teachers and Students&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://libguides.starkstate.edu/websites"&gt;Stark State Library - How to Evaluate Websites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.lib.byu.edu/c.php?g=216340&amp;amp;p=1428395"&gt;BYU Library - Step by Step Research Strategy Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.webwise.ie/teachers/advice-teachers/digital-literacy-skills-finding-information/"&gt;Webwise - Digital Literacy: Ten Steps to Better Web Research&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.iste.org/explore/Digital-and-media-literacy/Media-literacy-starts-with-SEARCHing-the-internet"&gt;Media Literacy Starts with SEARCHing the Internet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/swyx/how-to-google-your-errors-2l6o"&gt;How to Google Your Error Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://swizec.com/blog/reader-question:-how-do-you-learn-programming-topics"&gt;How do you learn programming topics?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Announcing the new "Redux Fundamentals" core docs tutorial!</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Mon, 02 Nov 2020 15:02:40 +0000</pubDate>
      <link>https://dev.to/markerikson/announcing-the-new-redux-fundamentals-core-docs-tutorial-1dic</link>
      <guid>https://dev.to/markerikson/announcing-the-new-redux-fundamentals-core-docs-tutorial-1dic</guid>
      <description>&lt;p&gt;I'm &lt;em&gt;very&lt;/em&gt; excited to announce that:&lt;/p&gt;

&lt;p&gt;📖📖The new "Redux Fundamentals" core docs tutorial is LIVE!📖📖&lt;/p&gt;

&lt;p&gt;This is a complete rewrite of the old "Basics/Advanced" tutorial, and teaches "how Redux works and how to use it" from the ground up:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://redux.js.org/tutorials/fundamentals/part-1-overview"&gt;https://redux.js.org/tutorials/fundamentals/part-1-overview&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The goals for the rewrite were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improve explanations&lt;/li&gt;
&lt;li&gt;Drop outdated references ("Flux", "container components")&lt;/li&gt;
&lt;li&gt;Show simpler patterns (inline action types, single-file logic)&lt;/li&gt;
&lt;li&gt;Explain how Redux works "bottom-up"&lt;/li&gt;
&lt;li&gt;Teach modern practices&lt;/li&gt;
&lt;li&gt;Show how Redux Toolkit simplifies Redux logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tutorial still builds a todo example app, but it's now a real app that gets bigger as the tutorial goes along and is used to demonstrate all concepts including async logic.&lt;/p&gt;

&lt;p&gt;We've got numerous CodeSandboxes throughout the tutorial showing the changes at different steps.&lt;/p&gt;

&lt;p&gt;This effort pairs with &lt;a href="https://redux.js.org/tutorials/essentials/part-1-overview-concepts"&gt;our "Redux Essentials" tutorial&lt;/a&gt;, which teaches "how to use Redux, the right way" for real-world usage.&lt;/p&gt;

&lt;p&gt;Like with the "Essentials" tutorial, each page now starts with "What You'll Learn" and ends with "What You've Learned" summaries. There's callout boxes with links to more info, and expandable "Detailed Explanation" sections that give more background.&lt;/p&gt;

&lt;p&gt;All of the old tutorial pages have been removed entirely, and we've added redirects pointing to matching content in the new "Fundamentals" pages instead.&lt;/p&gt;

&lt;p&gt;That completes the effort to rewrite our tutorials, but there's still a lot more docs work left to do!  We've got many more pages that need to be updated / reorganized, and we want to add new material as well.&lt;/p&gt;

&lt;p&gt;If you'd like to contribute, see this issue:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/reduxjs/redux/issues/3592"&gt;https://github.com/reduxjs/redux/issues/3592&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redux</category>
    </item>
    <item>
      <title>Coding Career Advice: Evaluating Software Libraries and Tools</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Tue, 22 Sep 2020 04:30:00 +0000</pubDate>
      <link>https://dev.to/markerikson/coding-career-advice-evaluating-software-libraries-and-tools-506j</link>
      <guid>https://dev.to/markerikson/coding-career-advice-evaluating-software-libraries-and-tools-506j</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As a senior developer, I spend a &lt;em&gt;lot&lt;/em&gt; of my time looking at tools and libraries to decide if they're something we can or should use as part of our projects. I've developed a strong ability to quickly filter through lists of possible tools to narrow them down, and then do further research on the remaining candidates.&lt;/p&gt;

&lt;p&gt;This is definitely not the kind of skill that they teach you in school, which is sad given the way modern software development is strongly dependent on reusing libraries.&lt;/p&gt;

&lt;p&gt;To help with that, here's some of the things I take into consideration when evaluating tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Correctly Evaluate Third-Party Software Libraries and Tools
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Starting Point: Search Locations
&lt;/h3&gt;

&lt;p&gt;For software libraries, you should typically start with the appropriate package manager site for the language you're using, such as &lt;a href="https://www.npmjs.com/"&gt;NPM&lt;/a&gt; for JavaScript, &lt;a href="https://pypi.org/"&gt;PyPi&lt;/a&gt; for Python, or &lt;a href="https://search.maven.org/"&gt;Maven Central&lt;/a&gt; for Java). If you're looking for non-library tools such as IDEs, Google is your best bet.&lt;/p&gt;

&lt;p&gt;Searching for keywords on those sites should turn up a list of things that are &lt;em&gt;potentially&lt;/em&gt; relevant.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential Evaluation Criteria
&lt;/h3&gt;

&lt;p&gt;When choosing &lt;em&gt;any&lt;/em&gt; tool, you have to evaluate it on multiple criteria. Here's an (incomplete) list of things you may want to consider when looking at any software library or tool that you're considering using:&lt;/p&gt;

&lt;h4&gt;
  
  
  Zeroth Pass: Relevance
&lt;/h4&gt;

&lt;p&gt;The first step is to select a list of tools that actually look relevant to your topic. For example, searching NPM for &lt;code&gt;react number input&lt;/code&gt; right now turns up 219 hits. There's probably only a much smaller number that actually match what you're looking for. Skim through the hits and pop open the most likely looking options based on the initial descriptions.&lt;/p&gt;

&lt;h4&gt;
  
  
  First Pass: Basic Suitability
&lt;/h4&gt;

&lt;p&gt;Now that you've got the initial candidate list, it's time to determine which of these &lt;em&gt;may&lt;/em&gt; be a good possibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this even solve the problems I have right now?&lt;/li&gt;
&lt;li&gt;Does it solve those problems &lt;em&gt;well&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;What's the license of this tool? Is it compatible with my company's policies?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The goal of using any tool is to solve a problem you have. If a tool doesn't solve your problem, you shouldn't even consider using it in the first place&lt;/strong&gt;. (Note that this implies that you should understand what problems you're trying to solve &lt;em&gt;before&lt;/em&gt; you start investigating tools to help with them :) )&lt;/p&gt;

&lt;p&gt;Along with that, there's the question of whether a tool is something you can use based on legal or policy concerns. For example, many companies disallow use of GPL-licensed software libraries to avoid any possible issues mixing their proprietary code with GPL-licensed code and being forced to distribute their own code publicly. Other companies might restrict libraries and applications based on the nationality of the authors, purchased licensing terms, or license costs.&lt;/p&gt;

&lt;p&gt;One-line summary of the most common open-source (OSS) licenses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MIT, BSD: use the code for whatever you want, just credit the original author&lt;/li&gt;
&lt;li&gt;LGPL: Use it as long as you don't modify the original library&lt;/li&gt;
&lt;li&gt;GPL: If you use it, your own software must be licensed under the GPL as well, and your source must be made available on request&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know ahead of time that you can't use a particular tool, there's no point in digging into it further.&lt;/p&gt;

&lt;h4&gt;
  
  
  Second Pass: Detailed Evaluations
&lt;/h4&gt;

&lt;p&gt;Once you've narrowed down the list down to the top 3-4 choices, you can do a more detailed evaluation of each of them.&lt;/p&gt;

&lt;p&gt;Here's some of the criteria that I take into consideration. I don't necessarily have these in a formal checklist, but they're usually in the back of my head in some form. (This list is biased towards OSS software libraries, particularly for JavaScript, but most apply more broadly as well).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How easy is it to use?&lt;/li&gt;
&lt;li&gt;What's the size of the community?

&lt;ul&gt;
&lt;li&gt;How many projects appear to use this tool?&lt;/li&gt;
&lt;li&gt;How many downloads does this have weekly/monthly?&lt;/li&gt;
&lt;li&gt;How much info is there on using it outside the core docs?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What's the size of the ecosystem?

&lt;ul&gt;
&lt;li&gt;How many related packages exist?&lt;/li&gt;
&lt;li&gt;If we have an additional use case not solved by the core tool, do addons exist that handle that use case?&lt;/li&gt;
&lt;li&gt;How easy is it to extend or modify this tool?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;How easy is it to understand what the tool does internally and conceptually?&lt;/li&gt;
&lt;li&gt;How much documentation does this have? Is there an actual meaningful docs site, or is it just a Github readme?&lt;/li&gt;
&lt;li&gt;How well tested is this tool?&lt;/li&gt;
&lt;li&gt;How much prior experience does my team have with this tool or something similar?&lt;/li&gt;
&lt;li&gt;Is it well maintained?

&lt;ul&gt;
&lt;li&gt;How many bugs does it have?&lt;/li&gt;
&lt;li&gt;Has this ever had any critical vulnerabilities / CVEs? If so, how many, how often, and how long did they take to get fixed?&lt;/li&gt;
&lt;li&gt;How often do new releases occur? When was the last release?&lt;/li&gt;
&lt;li&gt;How many open issues / PRs are there?&lt;/li&gt;
&lt;li&gt;How fast will things get fixed if there's a bug?&lt;/li&gt;
&lt;li&gt;How many maintainers are there? Are they active?&lt;/li&gt;
&lt;li&gt;What's the long-term roadmap for this project?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;How many other dependencies does this tool have?

&lt;ul&gt;
&lt;li&gt;How many of them are runtime dependencies vs development-only dependencies?&lt;/li&gt;
&lt;li&gt;Do we need to be concerned about any of them?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;How much does this affect the architecture of our app?

&lt;ul&gt;
&lt;li&gt;Can we rip it out if we choose to switch to something else?&lt;/li&gt;
&lt;li&gt;How hard is it to upgrade this tool when a new version comes out?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Where does this fall in the "hype cycle"?

&lt;ul&gt;
&lt;li&gt;Brand new tool that is experimental? It works, but still only used by early adopters? Mainstream? Dying?&lt;/li&gt;
&lt;li&gt;Are people actively starting new projects with this tool, or are they moving away?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;What technical requirements and system constraints does this have?

&lt;ul&gt;
&lt;li&gt;What's the minimum runtime version?&lt;/li&gt;
&lt;li&gt;Are there size concerns, such as min+gzip size for a JS library used in the browser?
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't an all-inclusive list - there's likely other factors you might want to consider as well.&lt;/p&gt;

&lt;p&gt;These all affect a decision on whether using a given tool is a good idea or not for your team. It's also likely that some of these may be more relevant than others depending on your situation.&lt;/p&gt;

&lt;p&gt;Note that you could easily spend an infinite amount of time recursing through the transitive dependencies of a given tool, especially if this is a JavaScript package of some kind. For example, a brand new Create-React-App project only has a handful of dependencies: &lt;code&gt;react&lt;/code&gt;, &lt;code&gt;react-dom&lt;/code&gt;, &lt;code&gt;@testing-library/react&lt;/code&gt;, and &lt;code&gt;react-scripts&lt;/code&gt;. However, &lt;code&gt;react-scripts&lt;/code&gt; itself depends on &lt;a href="https://github.com/facebook/create-react-app/blob/025f2739ceb459c79a281ddc6e60d7fd7322ca24/packages/react-scripts/package.json#L30-L87"&gt;Jest, ESLint, Webpack, Babel, PostCSS, and a couple dozen other packages&lt;/a&gt;, and Webpack in turn ends up pulling in around 700 packages, for a final total of just over 1500 individual packages installed into your &lt;code&gt;node_modules&lt;/code&gt; folder. Clearly, inspecting every one of those manually is not feasible, so you have to draw a line somewhere. Given the rise of "supply chain" attacks, where malicious packages are deliberately created to steal information or cause harm, it's critical to make these decisions wisely.&lt;/p&gt;

&lt;p&gt;It can sometimes be worth doing a "trade study" to evaluate alternatives, especially if multiple people are involved in this decision. Define several categories, decide on the possible range of numeric scores for each category, and rate each tooling option in each category. You may want to add together the scores for each tool, or average them out. Also, you might want to weight some categories as being more important than others. I suggest defining the weights and scoring approach ahead of time, so that the final decision is more fair.&lt;/p&gt;

&lt;p&gt;When searching for critical security vulnerabilities like CVEs, you can use sites like &lt;a href="https://cve.mitre.org/cve/search_cve_list.html"&gt;https://cve.mitre.org/cve/search_cve_list.html&lt;/a&gt; and &lt;a href="https://nvd.nist.gov/vuln/search"&gt;https://nvd.nist.gov/vuln/search&lt;/a&gt; as references.&lt;/p&gt;

&lt;p&gt;For open-source projects on Github, it's worth looking at the number of stars, open issues, and PRs. Those aren't final decision criteria, but they &lt;em&gt;can&lt;/em&gt; give you a sense of the popularity and health of a project. Also keep an eye on the recent commits to get an idea how active it is.&lt;/p&gt;

&lt;p&gt;NPM shows a weekly download stats graph on the package description page, but I prefer using &lt;a href="https://npm-stat.com"&gt;npm-stat.com&lt;/a&gt;, which lets you compare the download stats for multiple packages over a specific period of time, with values shown for daily/weekly/monthly/yearly downloads totals.&lt;/p&gt;

&lt;p&gt;For JS client bundle size questions specifically, I strongly recommend using &lt;a href="https://bundlephobia.com/"&gt;Bundlephobia&lt;/a&gt; to determine the true cost of adding a given package to your app. Michel Weststrate's &lt;a href="https://github.com/mweststrate/import-size"&gt;&lt;code&gt;import-size&lt;/code&gt;&lt;/a&gt; util can also be helpful here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://tldrlegal.com/"&gt;TLDR Legal&lt;/a&gt;: shortened plain English explanations of common software licenses&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bundlephobia.com/"&gt;Bundlephobia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mweststrate/import-size"&gt;&lt;code&gt;mweststrate/import-size&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mechanicalc.com/reference/trade-study"&gt;Trade Study guidelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://npm-stat.com"&gt;npm-stat.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/panaseer-labs-engineering-data-science/17-criteria-to-kickstart-your-research-and-evaluation-of-third-party-libraries-373fa6f2541f"&gt;17 criteria for evaluating third-party libraries&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.freecodecamp.org/news/the-12-things-you-need-to-consider-when-evaluating-any-new-javascript-library-3908c4ed3f49/"&gt;The 12 Things You Need to Consider when Evaluating Any New JavaScript Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.sizeofvoid.com/2020/08/23/evaluating-3rd-party-libraries/"&gt;Evaluating 3rd party libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Coding Career Advice: Keeping a Daily Work Journal</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Tue, 22 Sep 2020 04:00:00 +0000</pubDate>
      <link>https://dev.to/markerikson/coding-career-advice-keeping-a-daily-work-journal-44ji</link>
      <guid>https://dev.to/markerikson/coding-career-advice-keeping-a-daily-work-journal-44ji</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As I've progressed through my career as a developer, I've learned a bunch of useful things based on my experiences. I've frequently shared some of these thoughts with other developers on my team and various folks I've chatted with online, so it's worth trying to write these down so I can share them more widely.&lt;/p&gt;

&lt;p&gt;None of these thoughts are particularly new, and in fact I'll try to link to other resources that say similar things. But, writing them down means I've got somewhere to point people to in the future, and maybe they'll be &lt;a href="https://xkcd.com/1053/"&gt;new to someone who hasn't seen these thoughts before&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; : For a much more extensive set of career advice on many topics, I strongly recommend Shawn Swyx Wang's book &lt;a href="https://www.learninpublic.org/"&gt;&lt;strong&gt;The Coding Career Handbook: Guides, Principles, Strategies, and Tactics from Code Newbie to Senior Dev&lt;/strong&gt;&lt;/a&gt;. There's a &lt;em&gt;ton&lt;/em&gt; of valuable info in there, and it's totally worth the purchase.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Tip #1: Keeping a Daily Work Journal
&lt;/h2&gt;

&lt;p&gt;At the start of 2013, I started keeping a daily work journal. &lt;strong&gt;At the end of every workday, I take 10-15 minutes to write down a few paragraphs covering what I did that day&lt;/strong&gt; , such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tasks I worked on and what specific things I did for those&lt;/li&gt;
&lt;li&gt;Conversations with other developers on my team and what topics we covered, or key takeways from discussions outside the team&lt;/li&gt;
&lt;li&gt;Problems I ran into, and (hopefully) how I solved them&lt;/li&gt;
&lt;li&gt;Where I left off at the end of the day&lt;/li&gt;
&lt;li&gt;What tasks I need to prioritize the next day&lt;/li&gt;
&lt;li&gt;Useful code snippets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't hit all of those points every day, but they're all common things I cover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Keep a Work Journal?
&lt;/h3&gt;

&lt;p&gt;Writing journal entries like this has a lot of potential benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When I pick up work after a long weekend, it reminds me what I'm even supposed to be working on now&lt;/li&gt;
&lt;li&gt;I sometimes run into a bug that I &lt;em&gt;know&lt;/em&gt; I solved months or even years ago. There's been several times I dug back into my notes and found the solution I'd written down the last time.&lt;/li&gt;
&lt;li&gt;It's often interesting to look back at how I approached problems years ago, and see how I've grown since then&lt;/li&gt;
&lt;li&gt;But most of all, &lt;strong&gt;it's &lt;em&gt;extremely&lt;/em&gt; valuable come performance review season. I can go back through every single workday of the past year, see exactly what tasks I worked on, and put together an extensive list of accomplishments for my self-evaluation writeup.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Journaling Tools
&lt;/h3&gt;

&lt;p&gt;I strongly prefer to write notes in Markdown format, with actual syntax highlighting in the Markdown text and the rendered output.&lt;/p&gt;

&lt;p&gt;I currently use &lt;a href="https://github.com/BoostIO/boost-releases/releases/tag/v0.16.1"&gt;the "legacy" Boostnote desktop app (v0.16)&lt;/a&gt;, although I may end up switching to the "modern" Boostnote app in the near future once it looks mature enough.  Boostnote does a pretty good job handling Markdown and syntax highlighting. It also has decent search capabilities.&lt;/p&gt;

&lt;p&gt;I've also been writing a lot of Markdown documentation in VS Code lately, and there's some notebook plugins for VS Code that look like they might be viable options as well.&lt;/p&gt;

&lt;p&gt;You should feel free to use whatever works best for you, electronic or analog, although I would suggest something electronic because it's probably easier to search for text keywords.&lt;/p&gt;

&lt;h3&gt;
  
  
  Journal Organization
&lt;/h3&gt;

&lt;p&gt;I have a separate folder for each month, typically named like &lt;code&gt;2020-09 (September)&lt;/code&gt;, and create a separate Markdown note for each day, named like &lt;code&gt;2020-09-21 (Monday)&lt;/code&gt;. Legacy Boostnote sadly doesn't have nested folders, so all folders for all years are flattened out, but that makes it pretty easy to jump straight to a period of time that I'm interested in. (Looks like new Boostnote does support nested folders, so that may be a reason for me to switch.)&lt;/p&gt;

&lt;p&gt;I also have a separate parent category for other notes organized by topics.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Journal Entry
&lt;/h3&gt;

&lt;p&gt;Here's a very slightly anonymized version of a real journal entry I wrote recently:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  2020-09-03 (Thursday)
&lt;/h3&gt;

&lt;p&gt;Talked to $DEV_1 and split the remaining "UI polish" tasks up.&lt;/p&gt;

&lt;p&gt;Fixed an issue with input cells not focusing in FF. Turns out FF doesn't trigger click events on disabled inputs. Had to apply &lt;code&gt;input[disabled] { pointer-events: none; }&lt;/code&gt;, per Stack Overflow.&lt;/p&gt;

&lt;p&gt;I tried to get sticky table columns to work, and bounced off that. Too tough for now, so we'll put that for later.&lt;/p&gt;

&lt;p&gt;Had a good talk with $UX_DESIGNER. He's been busy the last few weeks with other projects, so we caught up on the state of our work. He's going to see if he can get a couple other UX folks to look at what we've got. He'll also think about the best way to display things like the couple dozen columns for $BUSINESS_FEATURE.&lt;/p&gt;

&lt;p&gt;I tossed out the idea of showing $FEATURE instruction help as a separate new popup window. He agreed that was viable.&lt;/p&gt;

&lt;p&gt;Found &lt;code&gt;react-new-window&lt;/code&gt;, pulled that in. Was able to copy and paste field definitions from Excel and convert to HTML via &lt;a href="https://tableizer.journalistopia.com/"&gt;Tableizer&lt;/a&gt;. Threw together help pages for the three $FEATURE tabs so far.&lt;/p&gt;

&lt;p&gt;Reviewed $DEV_2's PR that had removal of dead $FEATURE code, backend models converted to TS, a unit test for deleting $ITEM, and a bunch of other cleanup. Looks pretty good overall.&lt;/p&gt;

&lt;p&gt;I'll try to knock off the remaining UI polish tasks next.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Further Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dbader.org/blog/keep-journals-to-become-a-better-developer"&gt;Keep journals to become a better developer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/jacquibo/why-you-should-keep-a-code-journal-code-journaling-pt-1-of-4-k35"&gt;Getting started with a code journal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.livecareer.com/resources/jobs/search/tracking-accomplishments-tools"&gt;Tools for Brainstorming and Tracking Accomplishments&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hbr.org/2017/07/the-more-senior-your-job-title-the-more-you-need-to-keep-a-journal"&gt;The More Senior Your Job Title, the More You Need to Keep a Journal&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://news.ycombinator.com/item?id=23768624"&gt;HN discussion thread&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>career</category>
    </item>
    <item>
      <title>Debugging Tips and Tales</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Sat, 19 Jan 2019 17:57:09 +0000</pubDate>
      <link>https://dev.to/markerikson/debugging-tips-and-tales-3n5i</link>
      <guid>https://dev.to/markerikson/debugging-tips-and-tales-3n5i</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally &lt;a href="https://blog.isquaredsoftware.com/2019/01/blogged-answers-debugging-tips/" rel="noopener noreferrer"&gt;posted on my blog&lt;/a&gt; at &lt;a href="https://blog.isquaredsoftware.com" rel="noopener noreferrer"&gt;https://blog.isquaredsoftware.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Last week's &lt;a href="https://twitter.com/hashtag/devdiscuss" rel="noopener noreferrer"&gt;#devdiscuss&lt;/a&gt; discussion was on the topic of &lt;a href="https://twitter.com/ThePracticalDev/status/1085357114464370688" rel="noopener noreferrer"&gt;debugging&lt;/a&gt;.  This is something I have a lot of opinions and advice on, &lt;a href="https://twitter.com/acemarke/status/1085357989391945728" rel="noopener noreferrer"&gt;so I replied with a quick list of my suggestions for better debugging&lt;/a&gt;.  It's worth recording those in blog post form as well.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Ben McCormick pointed me to a very similar post he wrote a few years back.  It's excellent, and you should read it too: &lt;a href="https://benmccormick.org/2014/08/19/the-debugging-toolbox" rel="noopener noreferrer"&gt;The Debugging Toolbox&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mark's Debugging Advice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1) Reproduce the Issue
&lt;/h3&gt;

&lt;p&gt;Reproducing the problem is key. If you can't reproduce the issue, it's harder to figure out what's going on and iterate on fixes. More importantly, if you can't repro, you probably can't prove that a "fix" actually works.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Errors Provide Useful Information
&lt;/h3&gt;

&lt;p&gt;Error messages and stack traces are important. &lt;a href="https://twitter.com/swyx" rel="noopener noreferrer"&gt;@swyx&lt;/a&gt; quoted me in a Dev post last year on this topic: &lt;a href="https://dev.to/swyx/how-to-google-your-errors-2l6o"&gt;How to Google Your Errors&lt;/a&gt; .  They usually give you a good starting point for where the problem is and why it's happening. Read the messages. Google them if needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3)  Learn to Use Debuggers
&lt;/h3&gt;

&lt;p&gt;Know your tools. Most debuggers work the same no matter what IDE / DevTools you're using. Understand breakpoints, watches, stepping. Use more advanced features like conditional breakpoints, or "watchpoints" to just log a message instead of stopping.&lt;/p&gt;

&lt;h3&gt;
  
  
  4) Print Logging is Important
&lt;/h3&gt;

&lt;p&gt;Sometimes an IDE debugger won't cut it, especially if it's a remote system or multi-threaded environment. Good ol' console/print debugging is still important. It helps to have lots of existing logging with different levels that you can enable via config files.&lt;/p&gt;

&lt;h3&gt;
  
  
  5) Debug With a Plan
&lt;/h3&gt;

&lt;p&gt;Go in with a hypothesis. Understand how the code &lt;em&gt;should&lt;/em&gt; behave first. Look at the actual behavior. You can probably make educated guesses for where things are diverging. Focus on those areas. Don't randomly tweak. Change &lt;em&gt;one&lt;/em&gt; thing at a time and compare results.  Narrow down possible causes based on that.&lt;/p&gt;

&lt;h3&gt;
  
  
  6) Don't Be Afraid
&lt;/h3&gt;

&lt;p&gt;Experience helps, but don't be afraid to dive in if you're new, because that's how you get experience :)  Even if an issue looks like it's really complex, take some time to break it down into smaller pieces.  &lt;a href="https://daveceddia.com/your-own-react-project-ideas/" rel="noopener noreferrer"&gt;Dave Ceddia&lt;/a&gt; and &lt;a href="https://goshakkk.name/no-tutorial-for-everything/" rel="noopener noreferrer"&gt;Gosha Arinich&lt;/a&gt; both wrote good advice on the topic of breaking down problems from the perspective of building a new project and learning new topics, but the same concept applies to debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  7) Know When To Keep Going, and When To Stop
&lt;/h3&gt;

&lt;p&gt;Persistence is good, and it takes time to build up mental context on an issue, but sometimes you gotta take a break. Plenty of times I've left work, gone home, relaxed, and figured out what the issue was overnight or in the morning.&lt;/p&gt;

&lt;p&gt;On that note, I'll recap a couple of my best debugging stories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tales of Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Case of the Wrong Case
&lt;/h3&gt;

&lt;p&gt;A few years ago. I had a Python service that was doing a bunch of number crunching, so I used &lt;a href="https://cython.org/" rel="noopener noreferrer"&gt;Cython&lt;/a&gt; to speed up the math-intensive portions of the code. Cython is a tool that can compile plain Python code to C so that it runs faster.  If you add extra type declarations, it can generate more efficient C code, because it knows what each variable type is.&lt;/p&gt;

&lt;p&gt;Cython has a few ways you can declare types.  You can rename your &lt;code&gt;.py&lt;/code&gt; files to &lt;code&gt;.pyx&lt;/code&gt; and add types directly in the code; you can use decorators to declare the types; or you can add separate &lt;code&gt;.pxd&lt;/code&gt; files that declare the types.  I set it up using the side-by-side file approach, which lets you leave your original Python files alone.  For this to work, the &lt;code&gt;.pxd&lt;/code&gt; file with the types has to match the exact name of the original &lt;code&gt;.py&lt;/code&gt; file. So, if I had &lt;code&gt;FileA.py&lt;/code&gt;, I'd also have &lt;code&gt;FileA.pxd&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I added type definitions for the Python functions and variables and referenced several C math functions from &lt;code&gt;&amp;lt;math.h&amp;gt;&lt;/code&gt;.  This service primarily runs on Linux, but I do most of my development on Windows.  I did the initial changes on my local Windows machine, tested the code, and it seemed to be working great. &lt;/p&gt;

&lt;p&gt;Unfortunately, when I went to run this on Linux, it compiled fine, but started throwing some weird exceptions buried deep down in the code. I hadn't actually written the math portion of this service myself, so I wasn't familiar with the actual logic.  I traced the problem pretty far down into the code, and finally concluded that a particular function was trying to call the &lt;code&gt;cos()&lt;/code&gt; trigonometry function, but the call was failing because &lt;code&gt;cos&lt;/code&gt; didn't seem to exist.  This didn't make any sense, because I was explicitly importing the C version of &lt;code&gt;cos&lt;/code&gt; from &lt;code&gt;&amp;lt;math.h&amp;gt;&lt;/code&gt; if using Cython, and importing the normal Python function from the &lt;code&gt;math&lt;/code&gt; module otherwise.&lt;/p&gt;

&lt;p&gt;Took me about 6 hours of tracing, investigating, and steadily growing confusion before I finally figured out what was going on: there was a single letter casing mismatch between a &lt;code&gt;.py&lt;/code&gt; file and its corresponding &lt;code&gt;.pxd&lt;/code&gt; file. One had a capital 'O', the other had a lower-case 'o'. This worked fine on Windows, because Windows file systems are case-insensitive (so &lt;code&gt;filea.txt&lt;/code&gt; is considered the same as &lt;code&gt;FileA.txt&lt;/code&gt;).  But, Linux file systems are case-sensitive, so files can have the same name with different letter cases.  Because of this, the Cython compiler never actually found the  &lt;code&gt;.pxd&lt;/code&gt;file to match the original &lt;code&gt;.py&lt;/code&gt; file, didn't get the right imports, and thus stuff eventually exploded.  The fix was to change the capital 'O' to a lower-case 'o', and it worked.&lt;/p&gt;

&lt;p&gt;Definitely a pretty high hours-of-work to number-of-characters-changed ratio :) &lt;/p&gt;

&lt;h3&gt;
  
  
  A Twisted Tale
&lt;/h3&gt;

&lt;p&gt;Recently, we got reports that one of our Python services appeared to be locking up entirely.  This particular service acts as a reverse proxy, forwarding HTTP requests to the rest of our system, and also handling authentication requests.&lt;/p&gt;

&lt;p&gt;The main symptom was that none of our app would load in the browser.  Oddly, there were no obvious errors in the logs, but that was because the logs for the service &lt;em&gt;stopped&lt;/em&gt; entirely at about the time the symptoms occurred.&lt;/p&gt;

&lt;p&gt;This Python service is built on &lt;a href="https://twistedmatrix.com/trac/" rel="noopener noreferrer"&gt;the Twisted network framework&lt;/a&gt;.  Twisted uses an &lt;a href="https://stackoverflow.com/a/35119594/62937" rel="noopener noreferrer"&gt;"event loop"&lt;/a&gt;, similar to how Javascript and Node.js work.  It has a queue of events, and for each event, runs the associated code to completion.  This is great if you have lots of IO that happens in the background.  But, it also means that if a particular script takes a long time to run, it can block the entire event loop and keep any other code from running.&lt;/p&gt;

&lt;p&gt;I was stumped by the issue for a while, but I had a couple guesses.  My hypothesis was that one of the external calls this service was making was never getting a response, and thus blocking the event loop from continuing.&lt;/p&gt;

&lt;p&gt;We cranked up the log levels for this service, restarted things, and waited for it to happen again.  When it did, I took a look at the logs.  Sure enough, the last thing the service was trying to do was make an external request to an LDAP server to query some user data.&lt;/p&gt;

&lt;p&gt;I did some testing and confirmed that all of the external requests were happening on the main thread, same as the event loop (which I did by modifying the logging config to print out the name of the thread where the log statement occurred).  I moved all those external requests to happen in background threads instead, and also fixed the timeout settings on the calls so that they don't block indefinitely.  &lt;/p&gt;

&lt;p&gt;The changes resolved the issue.  We later found out that the issues did actually correspond to times when the LDAP server had been experiencing 100% CPU usage, thus confirming the external cause.&lt;/p&gt;

&lt;p&gt;The moral of the story is that knowing how the underlying technologies behave allowed me to make an educated guess for the likely cause of the problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Debugging is a combination of gathering information, problem solving, and knowing how to use the tools you have available.  Articles and courses can teach you a lot of things, but debugging is something that I feel really requires practice and experience.  &lt;/p&gt;

&lt;p&gt;So, the next time you see your application spewing errors into the logs, or something just "doesn't work", &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GVnvl2dh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://geekifyinc.com/wp-content/uploads/2017/09/IMG_0333-1280.jpg" rel="noopener noreferrer"&gt;&lt;strong&gt;DON'T PANIC!&lt;/strong&gt;&lt;/a&gt;  You can figure this out :)&lt;/p&gt;

</description>
      <category>debugging</category>
    </item>
    <item>
      <title>Redux - Not Dead Yet!</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Thu, 29 Mar 2018 15:00:00 +0000</pubDate>
      <link>https://dev.to/markerikson/redux---not-dead-yet-1d9k</link>
      <guid>https://dev.to/markerikson/redux---not-dead-yet-1d9k</guid>
      <description>&lt;p&gt;I'm a Redux maintainer. There's been a lot of confusion, claims, and misinformation about Redux going around lately, and I want to help clear things up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Originally published on my blog at &lt;a href="http://blog.isquaredsoftware.com/"&gt;blog.isquaredsoftware.com&lt;/a&gt; as part of my &lt;a href="http://blog.isquaredsoftware.com/series/blogged-answers"&gt;“Blogged Answers” series&lt;/a&gt; .&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Redux dead, dying, deprecated, or about to be replaced?
&lt;/h3&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;h3&gt;
  
  
  Are there situations where you don't need Redux?
&lt;/h3&gt;

&lt;p&gt;Sure, but that's always been true.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Longer Explanation
&lt;/h2&gt;

&lt;p&gt;There's been a whole slew of comments and articles lately that boil down to people asking "Is Redux dead?", or asserting that "Tool X replaces Redux". I'll recap several sources of confusion, and explain what's actually going on.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Redux is Overused"
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Where's this coming from?
&lt;/h4&gt;

&lt;p&gt;Redux has been around for almost three years. In "JS library years", that's like... &lt;em&gt;forever&lt;/em&gt; :) It got very popular very quickly, and as a result, a lot of people were told they &lt;em&gt;had&lt;/em&gt; to use Redux, without actually understanding the tradeoffs involved and when it actually makes sense to use Redux. So, there's been some inevitable backlash, and people have looked for alternatives, including adopting other state management libraries or creating their own.&lt;/p&gt;

&lt;p&gt;As part of that, there was a wave of tweets about a month ago about how Redux was being overused. One in particular was from Cory House, a well-known author/teacher in the React community. That tweet and various others got heavily retweeted, and the ensuing discussion ricocheted around Twitter for a while.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clearing the Confusion
&lt;/h4&gt;

&lt;p&gt;The Redux maintainers (first Dan Abramov and Andrew Clark, now Tim Dorr and myself) have always said that &lt;a href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367"&gt;you might not need Redux&lt;/a&gt;. There are &lt;em&gt;excellent&lt;/em&gt; reasons to use Redux, but it may not be the best fit for your situation. &lt;strong&gt;Like any tool, it's important to understand the tradeoffs and benefits before deciding to use something&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I've seen plenty of comments amongst the Twitterati that people have opted to move away from Redux to something else. But, at the same time, &lt;strong&gt;my own estimates are that somewhere between 50-60% of all React apps use Redux&lt;/strong&gt;, plus all of its usage with other JS frameworks like Angular, Ember, and Vue, and that is a userbase that isn't just going to disappear overnight. (There's also a big gap between what gets chatted about at lightning speed on social media, and what people are actually doing in "the real world".)&lt;/p&gt;

&lt;p&gt;It's also worth noting that &lt;strong&gt;Redux is not owned by Facebook - it's a separate open-source project&lt;/strong&gt;. Both of its creators (Dan Abramov and Andrew Clark) now work at Facebook, but Tim Dorr and I have no affiliation with Facebook at all. We talk with the React team to help coordinate future plans, but Redux doesn't belong to them.&lt;/p&gt;

&lt;h3&gt;
  
  
  "The new Context API can replace Redux"
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Where's this coming from?
&lt;/h4&gt;

&lt;p&gt;React 16.3 is introducing a new stable version of the &lt;code&gt;context&lt;/code&gt; API, which is intended to replace the old unstable API. Context is specifically intended for the use case of passing data to deeply nested React components. That's one of the reasons why some people have chosen to use Redux, and so there's been claims that the new context API will replace Redux.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clearing the Confusion
&lt;/h4&gt;

&lt;p&gt;Yes, the new context API is going to be great for passing down data to deeply nested components - that's exactly what it was designed for. &lt;strong&gt;If you're only using Redux to avoid passing down props, context &lt;em&gt;could&lt;/em&gt; replace Redux - but then you probably didn't &lt;em&gt;need&lt;/em&gt; Redux in the first place&lt;/strong&gt;. Context also doesn't give you anything like the Redux DevTools, the ability to trace your state updates, middleware to add centralized application logic, and other powerful capabilities that Redux enables.&lt;/p&gt;

&lt;h3&gt;
  
  
  "GraphQL can replace Redux"
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Where's this coming from?
&lt;/h4&gt;

&lt;p&gt;Somewhat similarly, there's been a lot of noise around GraphQL and the Apollo Client. There have been articles specifically claiming that "GraphQL will let you replace Redux". Also, Apollo has a new &lt;code&gt;apollo-link-state&lt;/code&gt; addon that can handle client-side state, and there's been discussion that that can also help replace Redux.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clearing the Confusion
&lt;/h4&gt;

&lt;p&gt;I'd agree that data fetching via GraphQL, and especially with Apollo, will likely reduce or eliminate your data-fetching related Redux code. And again, if that's &lt;em&gt;all&lt;/em&gt; you were using Redux for, you probably wouldn't need Redux after moving all the data-fetching handling into Apollo. I'll even go so far as to say that &lt;code&gt;apollo-link-state&lt;/code&gt; could probably handle most of your other client-side state logic, and I think Apollo ships with a DevTools setup of its own. The Apollo team has been doing some pretty neat work, and while I don't &lt;em&gt;like&lt;/em&gt; seeing people switch away from Redux, ultimately we all want to build great apps that help our users. But, as with context, I'd say there's definitely use cases where Redux is going to work better than GraphQL + Apollo, and possibly without requiring as much buy-in throughout your architecture. This is especially true if you need to do more than just fetch data or update a couple local state values, like persisting user data through page reloads or implementing complex workflow logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Redux is being replaced by something from React"
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Where's this coming from?
&lt;/h4&gt;

&lt;p&gt;Finally, &lt;a href="https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html"&gt;Dan Abramov recently gave a great talk at JS Conf Iceland&lt;/a&gt; where he demoed two upcoming aspects of React's "async rendering": time-slicing will allow React to split up update calculations for smoother updates, and "React Suspense" will allow deeply nested components to delay their rendering until fetched data is available. Unfortunately, shortly after the talk, a site known for writing misleading and poorly-written articles about React put up a post claiming that "Dan Abramov announced a new 'future-fetcher' library that replaces Redux", and linked a tweet by Kent C Dodds with that statement as evidence.&lt;/p&gt;

&lt;h4&gt;
  
  
  Clearing the Confusion
&lt;/h4&gt;

&lt;p&gt;One of the problems with social media is that it's easy for misinformation to spread quickly. And especially in this case, because &lt;strong&gt;that widely-spread article about Dan announcing a "future-fetcher" library was completely and utterly wrong!&lt;/strong&gt; Dan's announcement was purely about async React capabilities, and had &lt;em&gt;nothing&lt;/em&gt; to do with Redux. In addition, Kent's tweet about Redux being replaced was literally a joke tweet in a joke Twitter "live-commentary" thread about the talk. The article was either a complete misunderstanding of the React ecosystem, or a deliberate attempt to spread confusion and FUD.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Future of Redux
&lt;/h2&gt;

&lt;p&gt;As a Redux maintainer, I can assure you that &lt;strong&gt;Redux isn't going anywhere&lt;/strong&gt;. The Redux core library is stable, and we've actually got a 4.0 beta release available. Despite the major version bump, it's really just about cleaning up some edge cases and improving the TypeScript typings. Besides that, &lt;a href="https://dev.to/markerikson/react-boston-2017-presentation-you-might-need-redux-and-its-ecosystem-315c-temp-slug-5525438"&gt;the Redux ecosystem is thriving&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;em&gt;real&lt;/em&gt; interesting near-future work is around the React-Redux library&lt;/strong&gt;. We're going to be updating it to work better with React's async capabilities. We have &lt;a href="https://github.com/reactjs/react-redux/issues/890"&gt;an open issue for discussion of how Redux will work with async React&lt;/a&gt;, and I created &lt;a href="https://github.com/reactjs/react-redux/pull/898"&gt;a proof of concept PR that updates &lt;code&gt;connect&lt;/code&gt; to use the new context API&lt;/a&gt;. There will be more work needed over the next few months, but we're committed to ensuring that React and Redux continue to be a great choice for building applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ready to Learn Redux?
&lt;/h2&gt;

&lt;p&gt;So with all that in mind, it's a great time to learn how to use Redux. As always, I'll close with some links to further resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://redux.js.org/"&gt;The official Redux docs&lt;/a&gt;. I just updated the README to include a quick list of learning resources, and there's a more extensive list of &lt;a href="https://redux.js.org/introduction/learning-resources"&gt;Redux learning resources&lt;/a&gt; that cover many aspects of using Redux.&lt;/li&gt;
&lt;li&gt;I've got a blog post with &lt;a href="https://dev.to/markerikson/blogged-answers-resources-for-learning-redux-24i5-temp-slug-1300254"&gt;my suggested list of resources for learning Redux&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My &lt;a href="https://github.com/markerikson/react-redux-links"&gt;React/Redux links list&lt;/a&gt; has an extensive section &lt;a href="https://github.com/markerikson/react-redux-links/blob/master/redux-tutorials.md"&gt;full of Redux tutorials&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;My &lt;a href="http://blog.isquaredsoftware.com/series/practical-redux/"&gt;"Practical Redux" blog tutorial series&lt;/a&gt; demonstrates a variety of real-world Redux and React techniques through building a sample application, and I've also created &lt;a href="https://www.educative.io/collection/5687753853370368/5707702298738688"&gt;an interactive "Practical Redux" course on Educative.io&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd also encourage people to really understand when and why they should use Redux. Some suggested articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://redux.js.org/faq/general#when-should-i-use-redux"&gt;The Redux FAQ entry on "When should I use Redux?"&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Dan Abramov's post &lt;a href="https://medium.com/@dan_abramov/you-might-not-need-redux-be46360cf367"&gt;You Might Not Need Redux&lt;/a&gt;, which discusses the tradeoffs Redux asks you to make and some of the benefits you get in return&lt;/li&gt;
&lt;li&gt;My two part post &lt;a href="https://dev.to/markerikson/idiomatic-redux-the-tao-of-redux-part-1---implementation-and-intent-1c1i-temp-slug-5403642"&gt;The Tao of Redux, Part 1 - Implementation and Intent&lt;/a&gt; and &lt;a href="https://dev.to/markerikson/idiomatic-redux-the-tao-of-redux-part-2---practice-and-philosophy-hml-temp-slug-2020452"&gt;The Tao of Redux, Part 2 - Practice and Philosophy&lt;/a&gt;, which look into the history and intent behind how Redux was designed, how it's &lt;em&gt;meant&lt;/em&gt; to be used, and why common usage patterns exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Learn Redux In Person from Me!
&lt;/h3&gt;

&lt;p&gt;Besides all the articles and posts and links, &lt;strong&gt;I'm going to be teaching a series of "Redux Fundamentals" workshops through Workshop.me!&lt;/strong&gt; I'm excited for this chance to spend a couple days helping people learn exactly how Redux works and how to use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://workshop.me/2018-04-react-redux/?a=mark"&gt;My first "Redux Fundamentals" workshop is April 19-20, in New York City&lt;/a&gt;&lt;/strong&gt;, with other workshop locations and dates TBD later this year. &lt;strong&gt;Tickets for the NYC workshop are still available!&lt;/strong&gt; If you're not in NYC, or are already comfortable with Redux, spread the word to someone you know who might be interested! :)&lt;/p&gt;

</description>
      <category>redux</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Sat, 23 Dec 2017 01:00:00 +0000</pubDate>
      <link>https://dev.to/markerikson/idiomatic-redux-using-reselect-selectors-for-encapsulation-and-performance-bm8</link>
      <guid>https://dev.to/markerikson/idiomatic-redux-using-reselect-selectors-for-encapsulation-and-performance-bm8</guid>
      <description>&lt;p&gt;&lt;em&gt;An overview of why and how to use Reselect with React and Redux&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This post was originally published on my blog at &lt;a href="http://blog.isquaredsoftware.com/2017/12/idiomatic-redux-using-reselect-selectors/"&gt;blog.isquaredsoftware.com&lt;/a&gt;, and is part of my &lt;a href="http://blog.isquaredsoftware.com/series/idiomatic-redux/"&gt;"Idiomatic Redux" blog series&lt;/a&gt; on good Redux usage practices.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In a good Redux architecture, you are encouraged to &lt;a href="https://redux.js.org/docs/recipes/ComputingDerivedData.html"&gt;keep your store state minimal, and derive data from the state as needed&lt;/a&gt;. As part of that process, we recommend that you use "selector functions" in your application, and use the Reselect library to help create those selectors. Here's a deeper look at why this is a good idea, and how to correctly use Reselect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basics of Selectors
&lt;/h2&gt;

&lt;p&gt;A "selector function" is simply any function that accepts the Redux store state (or part of the state) as an argument, and returns data that is based on that state. Selectors don't have to be written using a special library, and it doesn't matter whether you write them as arrow functions or the &lt;code&gt;function&lt;/code&gt; keyword. For example, these are all selectors:&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;const&lt;/span&gt; &lt;span class="nx"&gt;selectEntities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;selectItemIds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectSomeSpecificField&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deeply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;selectItemsWhoseNamesStartWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;namePrefix&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;namePrefix&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;filteredItems&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;You can call your selector functions whatever you want, but it's common to prefix them with &lt;code&gt;select&lt;/code&gt; or &lt;code&gt;get&lt;/code&gt;, or end the name with &lt;code&gt;Selector&lt;/code&gt;, like &lt;code&gt;selectFoo&lt;/code&gt;, &lt;code&gt;getFoo&lt;/code&gt;, or &lt;code&gt;fooSelector&lt;/code&gt; (see &lt;a href="https://twitter.com/_jayphelps/status/739905438116806656"&gt;this Twitter poll on naming selectors&lt;/a&gt; for discussion).&lt;/p&gt;

&lt;p&gt;The first reason to use selector functions is for encapsulation and reusability. Let's say that one of your &lt;code&gt;mapState&lt;/code&gt; functions 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;some&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;deeply&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nested&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&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;That's a totally legal statement. But, imagine that you've got several components that need to access that field. What happens if you need to make a change to where that piece of state lives? You would now have to go change &lt;em&gt;every&lt;/em&gt; &lt;code&gt;mapState&lt;/code&gt; function that references that value. So, in the same way that &lt;a href="http://blog.isquaredsoftware.com/2016/10/idiomatic-redux-why-use-action-creators/"&gt;we recommend using action creators to encapsulate details of creating actions&lt;/a&gt;, we recommend using selectors to encapsulate the knowledge of where a given piece of state lives. &lt;strong&gt;Ideally, only your reducer functions and selectors should know the exact state structure, so if you change where some state lives, you would only need to update those two pieces of logic&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;One common description of selectors is that they're like "queries into your state". You don't care about exactly how the query came up with the data you needed, just that you asked for the data and got back a result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reselect Usage and Memoization
&lt;/h2&gt;

&lt;p&gt;The next reason to use selectors is to improve performance. Performance optimization generally involves doing work faster, or finding ways to do less work. For a React-Redux app, selectors can help us do less work in a couple different ways.&lt;/p&gt;

&lt;p&gt;Let's imagine that we have a component that requires a very expensive filtering/sorting/transformation step for the data it needs. To start with, its &lt;code&gt;mapState&lt;/code&gt; function 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveFiltering&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveSorting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveTransformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortedData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transformedData&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;Right now, that expensive logic will re-run for &lt;em&gt;every&lt;/em&gt; dispatched action that results in a state update, even if the store state that was changed was in a part of the state tree that this component doesn't care about.&lt;/p&gt;

&lt;p&gt;What we really want is to only re-run these expensive steps if &lt;code&gt;state.someData&lt;/code&gt; has actually changed. This is where the idea of "memoization" comes in.&lt;/p&gt;

&lt;p&gt;Memoization is a form of caching. It involves tracking inputs to a function, and storing the inputs and the results for later reference. If a function is called with the same inputs as before, the function can skip doing the actual work, and return the same result it generated the last time it received those input values.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;a href="https://github.com/reactjs/reselect"&gt;Reselect library&lt;/a&gt; provides a way to create memoized selector functions.&lt;/strong&gt; Reselect's &lt;code&gt;createSelector&lt;/code&gt; function accepts one or more "input selector" functions, and an "output selector" function, and returns a new selector function for you to use.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;createSelector&lt;/code&gt; can accept multiple input selectors, which can be provided as separate arguments or as an array. The results from all the input selectors are provided as separate arguments to the output selector:&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;const&lt;/span&gt; &lt;span class="nx"&gt;selectA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectABC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectC&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do something with a, b, and c, and return a result&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Call the selector function and get a result&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectABC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// could also be written as separate arguments, and works exactly the same&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectABC2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;selectA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// do something with a, b, and c, and return a result&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;c&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;When you call the selector, Reselect will run your input selectors with all of the arguments you gave, and looks at the returned values. If any of the results are &lt;code&gt;===&lt;/code&gt; different than before, it will re-run the output selector, and pass in those results as the arguments. If all of the results are the same as the last time, it will skip re-running the output selector, and just return the cached final result from before.&lt;/p&gt;

&lt;p&gt;In typical Reselect usage, you write your top-level "input selectors" as plain functions, and use &lt;code&gt;createSelector&lt;/code&gt; to create memoized selectors that look up nested values:&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;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;a&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;first&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;b&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectA&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectA1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectA&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;first&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectA1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectB&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Output selector running&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;a1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Log: "Output selector running"&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 15&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secondResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// No log output&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;secondResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// 15&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the second time we called &lt;code&gt;selectResult&lt;/code&gt;, the "output selector" didn't execute. Because the results of &lt;code&gt;selectA1&lt;/code&gt; and &lt;code&gt;selectB&lt;/code&gt; were the same as the first call, &lt;code&gt;selectResult&lt;/code&gt; was able to return the memoized result from the first call.&lt;/p&gt;

&lt;p&gt;It's important to note that by default, Reselect only memoizes the most recent set of parameters. That means that if you call a selector repeatedly with different inputs, it will still return a result, but it will have to keep re-running the output selector to produce the result:&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;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// first call, not memoized&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// same inputs, memoized&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// different inputs, not memoized&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;someSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// different inputs from last time, not memoized&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, you can pass multiple arguments into a selector. Reselect will call all of the input selectors with those exact inputs:&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;const&lt;/span&gt; &lt;span class="nx"&gt;selectItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectItemId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectItemById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectItemId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  
&lt;span class="p"&gt;);&lt;/span&gt;  

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectItemById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/*
Internally, Reselect does something like this:

const firstArg = selectItems(state, 42);  
const secondArg = selectItemId(state, 42);  

const result = outputSelector(firstArg, secondArg);  
return result;  
*/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because of this, it's important that all of the "input selectors" you provide should accept the same types of parameters. Otherwise, the selectors will break.&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;const&lt;/span&gt; &lt;span class="nx"&gt;selectItems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="c1"&gt;// expects a number as the second argument&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectItemId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="c1"&gt;// expects an object as the second argument&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectOtherField&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;someObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someField&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectItemById&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectItemId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectOtherField&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;someField&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemId&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;In this example, &lt;code&gt;selectItemId&lt;/code&gt; expects that its second argument will be some simple value, while &lt;code&gt;selectOtherField&lt;/code&gt; expects that the second argument is an object. If you call &lt;code&gt;selectItemById(state, 42)&lt;/code&gt;, &lt;code&gt;selectOtherField&lt;/code&gt; will break because it's trying to access &lt;code&gt;42.someField&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can (and probably &lt;em&gt;should&lt;/em&gt;) use selector functions &lt;em&gt;anywhere&lt;/em&gt; in your application that you access the state tree&lt;/strong&gt;. That includes &lt;code&gt;mapState&lt;/code&gt; functions, thunks, sagas, observables, middleware, and even reducers.&lt;/p&gt;

&lt;p&gt;Selector functions are frequently co-located with reducers, since they both know about the state shape. However, it's up to you where you put your selector functions and how you organize them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optimizing Performance With Reselect
&lt;/h2&gt;

&lt;p&gt;Let's go back to the "expensive &lt;code&gt;mapState&lt;/code&gt;" example from earlier. We really want to only execute that expensive logic when &lt;code&gt;state.someData&lt;/code&gt; has changed. Putting the logic inside a memoized selector will do that.&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;const&lt;/span&gt; &lt;span class="nx"&gt;selectSomeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectFilteredSortedTransformedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;selectSomeData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filteredData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveFiltering&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sortedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveSorting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;expensiveTransformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sortedData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transformedData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectFilteredSortedTransformedData&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;transformedData&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 is a big performance improvement, for two reasons.&lt;/p&gt;

&lt;p&gt;First, now the expensive transformation only occurs if &lt;code&gt;state.someData&lt;/code&gt; is different. That means if we dispatch an action that updates &lt;code&gt;state.somethingElse&lt;/code&gt;, we won't do any real work in this &lt;code&gt;mapState&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Second, the React-Redux &lt;code&gt;connect&lt;/code&gt; function determines if your real component should re-render based on the contents of the objects you return from &lt;code&gt;mapState&lt;/code&gt;, using "shallow equality" comparisons. If any of the fields returned are &lt;code&gt;===&lt;/code&gt; different than the last time, then &lt;code&gt;connect&lt;/code&gt; will re-render your component. That means that you should avoid creating new references in a &lt;code&gt;mapState&lt;/code&gt; function unless needed. Array functions like &lt;code&gt;concat()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, and &lt;code&gt;filter()&lt;/code&gt; always return new array references, and so does the object spread operator. By using memoized selectors, we can return the same references if the data hasn't changed, and thus skip re-rendering the real component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced Optimizations with React-Redux
&lt;/h2&gt;

&lt;p&gt;There's a specific performance issue that can occur when you use memoized selectors with a component that can be rendered multiple times.&lt;/p&gt;

&lt;p&gt;Let's say that we have this component definition:&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;const&lt;/span&gt; &lt;span class="nx"&gt;mapState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectItemForThisComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SomeComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;;
&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mapState&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// later&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SomeComponent&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SomeComponent&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;SomeComponent&lt;/code&gt; is passing &lt;code&gt;ownProps.itemId&lt;/code&gt; as a parameter to the selector. When we render multiple instances of &lt;code&gt;&amp;lt;SomeComponent&amp;gt;&lt;/code&gt;, each of those instances are sharing the same instance of the &lt;code&gt;selectItemForThisComponent&lt;/code&gt; function. That means that when an action is dispatched, each separate instance of &lt;code&gt;&amp;lt;SomeComponent&amp;gt;&lt;/code&gt; will separately call the function, like:&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="c1"&gt;// first instance&lt;/span&gt;
&lt;span class="nx"&gt;selectItemForThisComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// second instance&lt;/span&gt;
&lt;span class="nx"&gt;selectItemForThisComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As described earlier, Reselect only memoizes on the most recent inputs (ie, it has a cache size of 1). That means that &lt;code&gt;selectItemForThisComponent&lt;/code&gt; will &lt;em&gt;never&lt;/em&gt; memoize correctly, because it's never being called with the same inputs back-to-back.&lt;/p&gt;

&lt;p&gt;This code will still run and work, but it's not fully optimized. For the absolute best performance, we need a separate copy of &lt;code&gt;selectItemForThisComponent&lt;/code&gt; for each instance of &lt;code&gt;&amp;lt;SomeComponent&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The React-Redux &lt;code&gt;connect&lt;/code&gt; function supports a special "factory function" syntax for &lt;code&gt;mapState&lt;/code&gt; and &lt;code&gt;mapDispatch&lt;/code&gt; functions, which can be used to create unique instances of selector functions for each component instance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the first call to a &lt;code&gt;mapState&lt;/code&gt; or &lt;code&gt;mapDispatch&lt;/code&gt; function returns a function instead of an object, &lt;code&gt;connect&lt;/code&gt; will use that returned function as the &lt;em&gt;real&lt;/em&gt; &lt;code&gt;mapState&lt;/code&gt; or &lt;code&gt;mapDispatch&lt;/code&gt; function. This gives you the ability to create component-instance-specific selectors inside the closure:&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;const&lt;/span&gt; &lt;span class="nx"&gt;makeUniqueSelectorInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;selectItems&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;selectItemId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;    

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;makeMapState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;selectItemForThisComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;makeUniqueSelectorInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;realMapState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;selectItemForThisComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ownProps&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;itemId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;makeMapState&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both component 1 and component 2 will get their own unique copies of &lt;code&gt;selectItemForThisComponent&lt;/code&gt;, and each copy will get called with consistently repeatable inputs, allowing proper memoization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Like &lt;a href="http://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/"&gt;other common Redux usage patterns&lt;/a&gt;, &lt;strong&gt;you are not required to use selector functions in a Redux app&lt;/strong&gt;. If you want to write deeply nested state lookups directly in your &lt;code&gt;mapState&lt;/code&gt; functions or thunks, you can. Similarly, you don't &lt;em&gt;have&lt;/em&gt; to use the Reselect library to create selectors - you can just write plain functions if you want.&lt;/p&gt;

&lt;p&gt;Having said that, &lt;strong&gt;you are encouraged to use selector functions, and to use the Reselect library for memoized selectors&lt;/strong&gt;. There's also many other options for creating selectors, including using functional programming utility libraries like lodash/fp and Ramda, and other alternatives to Reselect. There's also &lt;a href="https://github.com/markerikson/redux-ecosystem-links/blob/master/utilities.md#selectors"&gt;utility libraries that build on Reselect to handle specific use cases&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Selector basics and usage&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=frT3to2ACCw"&gt;ReactCasts #8: Selectors in Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codebrahma.com/reselect-tutorial-optimizing-react-redux-application-development-with-reselect/"&gt;Optimizing React Redux Application Development with Reselect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dashbouquet.com/blog/frontend-development/usage-of-reselect-in-a-react-redux-application"&gt;Usage of Reselect in a React-Redux Application&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@parkerdan/react-reselect-and-redux-b34017f8194c"&gt;React, Reselect, and Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markerikson/react-redux-links/blob/master/redux-reducers-selectors.md#selectors-and-normalization"&gt;React/Redux Links: Redux Reducers and Selectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markerikson/redux-ecosystem-links/blob/master/utilities.md#selectors"&gt;Redux Ecosystem Links: Utilities - Selectors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Organizing selectors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://egghead.io/lessons/javascript-redux-colocating-selectors-with-reducers"&gt;Dan Abramov's "Idiomatic Redux" video series: Colocating Selectors with Reducers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Randy Coulman's posts on selectors and encapsulation:

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://randycoulman.com//blog/2016/09/13/encapsulating-the-redux-state-tree/"&gt;Encapsulating the Redux State Tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://randycoulman.com/blog/2016/09/20/redux-reducer-selector-asymmetry/"&gt;Redux Reducer/Selector Asymmetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://randycoulman.com/blog/2016/09/27/modular-reducers-and-selectors/"&gt;Modular Reducers and Selectors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://randycoulman.com/blog/2016/11/29/globalizing-redux-selectors/"&gt;Globalizing Redux selectors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markerikson/react-redux-links/blob/master/redux-architecture.md#encapsulation-and-reusability"&gt;React/Redux Links: Redux Architecture - Encapsulation and Reusability&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;React/Redux Performance&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.isquaredsoftware.com/2017/01/practical-redux-part-6-connected-lists-forms-and-performance/"&gt;Practical Redux, Part 6: Connected Lists, Forms, and Performance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://somebody32.github.io/high-performance-redux/"&gt;High Performance Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markerikson/react-redux-links/blob/master/react-performance.md"&gt;React/Redux Links: Redux Performance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>redux</category>
      <category>javascript</category>
    </item>
    <item>
      <title>The Obligatory introduction</title>
      <dc:creator>Mark Erikson</dc:creator>
      <pubDate>Tue, 03 Jan 2017 21:54:51 +0000</pubDate>
      <link>https://dev.to/markerikson/the-obligatory-introduction</link>
      <guid>https://dev.to/markerikson/the-obligatory-introduction</guid>
      <description>&lt;p&gt;I'm a (mostly web) dev in southwest Ohio.  I'm a Redux maintainer, and write lots of stuff about React, Redux, and more.&lt;/p&gt;

&lt;p&gt;I keep a big list of links on React, Redux, at related topics, at &lt;a href="https://github.com/markerikson/react-redux-links" rel="noopener noreferrer"&gt;https://github.com/markerikson/react-redux-links&lt;/a&gt; , as well as a list of Redux addons at &lt;a href="https://github.com/markerikson/redux-ecosystem-links" rel="noopener noreferrer"&gt;https://github.com/markerikson/redux-ecosystem-links&lt;/a&gt; .  &lt;/p&gt;

&lt;p&gt;I blog at &lt;a href="http://blog.isquaredsoftware.com/" rel="noopener noreferrer"&gt;http://blog.isquaredsoftware.com/&lt;/a&gt; , and am on Twitter at @acemarke .&lt;/p&gt;

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