<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>carlos schults / blog</title>
    <description>Articles on software development and technology.</description>
    <link>https://carlosschults.net/</link>
    <atom:link href="https://carlosschults.net/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 29 May 2026 16:32:41 +0000</pubDate>
    <lastBuildDate>Fri, 29 May 2026 16:32:41 +0000</lastBuildDate>
    <generator>Jekyll v4.3.1</generator>
    
    
      <item>
        <title>Building git in Go From Scratch - Part 2</title>
        <description>&lt;p&gt;Welcome back to my journey of building git from scratch in Go, in order to learn more about both. If you don’t know what
I’m talking about, go read &lt;a href=&quot;/en/implementing-git-in-go&quot;&gt;the first post&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;its-been-a-while&quot;&gt;It’s Been a While&lt;/h2&gt;
&lt;p&gt;I published the first entry for this log of sorts on March 9th. What have I been up to, and why it took me so long to continue the series?&lt;/p&gt;

&lt;p&gt;The answer is what you probably already know: I’m a busy adult and don’t have much time. Also, there are other personal projects that demand my time.&lt;/p&gt;

&lt;p&gt;Anyway, enough with the excuses. Let’s talk about what I’ve managed to implement since the last update.&lt;/p&gt;

&lt;h2 id=&quot;plumbing-vs-porcelain-commands&quot;&gt;Plumbing vs Porcelain Commands&lt;/h2&gt;
&lt;p&gt;Before I go into more detail about what I implemented, I’ll need to digress a little bit and talk about a distinction that exists regarding git commands.&lt;/p&gt;

&lt;p&gt;When you think about git commands, what come to your mind are probably commands like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git init&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;, and so on. And even that only if you actually use commands. Many people simply use GUIs for everything and never manage to learn not even the basic commands.&lt;/p&gt;

&lt;p&gt;These are the so-called “porcelain” commands. They are the high-level commands, intended to be used by git’s end-users, like you and me.&lt;/p&gt;

&lt;p&gt;There is another layer of commands, which people call “plumbing” commands. Plumbing commands are the low-level commands, which perform the nitty-gritty data manipulation that enables the high-level commands to do their work.&lt;/p&gt;

&lt;p&gt;So, recently, I’ve been implementing some plumbing commands that act as the foundation for much of what git does. They are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;understanding-hash-object-and-cat-file&quot;&gt;Understanding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; And &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;I’m going to talk very briefly about what these commands do before I talk about my experience implementing them. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; is the command used to save some data as a blob (binary large object) inside a git repository. You give the command a piece of text, and it saves an object with that information, and gives you back a SHA1 hash.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; command does the opposite. You give it an object hash, and it returns you its contents (or size, or type, depending on how you call it).&lt;/p&gt;

&lt;h3 id=&quot;hashing-your-first-object&quot;&gt;Hashing Your First Object&lt;/h3&gt;
&lt;p&gt;Do you want to test it? Run the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | git hash-object &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After running this, you should see this exact hash as a result: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;45b983be36b73c0788dc9cbcb76cbb80fc7bb057&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;If you’re on Linux or another Unix system, you probably got the result above. The same is true for Windows if you’re using Git Bash. But if you’re on Windows and using the command prompt or powershell, your result was probably different. That happens because of different line endings between the systems.&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;What happened here is that git calculated a hash for the “hi” string and returned it to you. We’re using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--stdin&lt;/code&gt; flag so you can pipe the content from the standard input.&lt;/p&gt;

&lt;p&gt;However, that wasn’t saved anywhere. To actually write the data to disk, you need to use a different version of the command, and this time it needs to be inside a repository.&lt;/p&gt;

&lt;h3 id=&quot;saving-an-object&quot;&gt;Saving an Object&lt;/h3&gt;

&lt;p&gt;Go to some place, create a new folder and a new repo inside it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;testing-commands
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;testing-commands
git init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s good. Now, you can do this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | git hash-object &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is similar to how you used the command before, but notice the extra &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag. That means &lt;strong&gt;write&lt;/strong&gt; and it’s what makes git save the content to a file. You’ll still get the SHA1 hash as a response, same as before, but now you got a brand new blob git object saved somewhere. Wanna see it?&lt;/p&gt;

&lt;p&gt;Go to the folder where this repository lives, then go inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;testing-commands&lt;/code&gt; folder. As in, using a GUI, not in the command line. Change whatever configurations you need so you can see hidden folders and files. You’ll see a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; folder:&lt;/p&gt;

&lt;p&gt;Go inside this folder and you’ll see basically this structure:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;├───hooks
├───info
├───objects   
└───refs
- config
- description
- HEAD
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;description&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; are files, and the others are folders. Go inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt; folder. You’ll probably find an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pack&lt;/code&gt; folders there, but ignore them.&lt;/p&gt;

&lt;p&gt;What we’re really after here is a folder named with two characters. If you ran the commands above on Linux or using Git bash on Windows, it should be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;45&lt;/code&gt;. Otherwise, it should be the first two characters of whatever hash you got back after running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo hi | git hash-object -w --stdin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Go into that folder. Inside, you’ll find a file named after the remaining characters of the hash you got back. In my case, I see &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;b983be36b73c0788dc9cbcb76cbb80fc7bb057&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That is your blob.&lt;/strong&gt; That file is the object that git saved when you ran the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt; command with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag.&lt;/p&gt;

&lt;h3 id=&quot;reading-objects-back&quot;&gt;Reading Objects Back&lt;/h3&gt;
&lt;p&gt;Try opening the blob file using your text editor of choice. You’ll see that, yes, the file opens fine. But the contents are pure giberish. That’s because that’s a compressed, binary format. It isn’t plain text.&lt;/p&gt;

&lt;p&gt;This is what git does, in sequence:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;It creates a header, by concatenating the word “blob”, a space, and the size, in bytes of the contents. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;blob 2&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Then it concatenates that with a &lt;a href=&quot;https://en.wikipedia.org/wiki/Null_character&quot;&gt;null character&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;It then concatenates the actual content after that. In our example, “hi”.&lt;/li&gt;
  &lt;li&gt;It generates the SHA1 of the complete string.&lt;/li&gt;
  &lt;li&gt;If you’re not using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag, git then returns the SHA1 and that’s it.&lt;/li&gt;
  &lt;li&gt;In case you are using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag, it the compresses the complete string (header + null byte + contents)&lt;/li&gt;
  &lt;li&gt;It takes the two first characters of the SHA1 hash and creates a directory with that name, inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Finally, it creates a file inside that folder, named with the remaining characters of the SHA1 hash, and writes to this file the contents, compressed using zlib.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to read this data back, you use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; command, along with one of its flags. In order to just read the contents, you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file -p&lt;/code&gt;, where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-p&lt;/code&gt; flag means “pretty print”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git cat-file &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you run the command above, you get “hi” back. You can also use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t&lt;/code&gt; flag for the type of object, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt; to return its size in bytes:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git cat-file &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
blob

git cat-file &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;enter-go-gitter&quot;&gt;Enter Go-Gitter&lt;/h2&gt;
&lt;p&gt;Now that you understand what these two commands do, let’s talk about how I implemented them in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-gitter&lt;/code&gt;, starting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;implementing-hash-object&quot;&gt;Implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;My first step was implementing the most basic version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash-object&lt;/code&gt;, without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag. So, the command would be able to display the SHA1 hash for a given text, but not actually save it to disk yet.&lt;/p&gt;

&lt;p&gt;As you can see from the &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/3ae9cc58f32059cda6091aa27dbab4507cebbca7&quot;&gt;commit&lt;/a&gt;, this is far from an example of clean code. The code mixes argument parsing and actual logic into the same file. At this point, I hadn’t even created functions for each command, though I ended up doing that later.&lt;/p&gt;

&lt;p&gt;The part of the code that does the actual hashing turned out to be really simple, once I understood what the format was supposed to be:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;blob %s%c&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strconv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Itoa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hashedData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;hashedString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EncodeToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hashedData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hashedString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, as you can see we create the header by concatenating the word “blob” plus a space with the size of the contents and then the null character, here represented by the integer zero. Then we hash everything, encode it as a string and print that.&lt;/p&gt;

&lt;p&gt;It took me some googling to find out the necessary libraries and the syntax to do this in go, since my self-imposed rules say I can’t use LLMs for any code generation, but I ended up doing it fine.&lt;/p&gt;

&lt;p&gt;In the &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/8b08cb93545f3966b1485989ce67501e1a5ff3ba&quot;&gt;next commit&lt;/a&gt; I added support for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w&lt;/code&gt; flag. As you can see, at that point I created a function for the command.&lt;/p&gt;

&lt;p&gt;There isn’t much difference, really. What I added was some primitive argument parsing to figure out whether I should write to disk.&lt;/p&gt;

&lt;p&gt;Then, the actual code that does the writing:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saveFile&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// create the directory for the blob&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Mkdir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModePerm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// compress the content using zlib and save the file&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WriteFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0666&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It took me a bit of time to get this right. Mostly because at some point I was completely misunderstanding what git actually did. I thought I was supposed to compress and save the &lt;em&gt;hash&lt;/em&gt; that I calculated earlier. Yes, I know, makes no sense, but what can I say?&lt;/p&gt;

&lt;p&gt;Once I understood that, getting this to work was mainly a matter of figuring out the zlib compression part. Google and documentation did it for me, like in the old days.&lt;/p&gt;

&lt;h3 id=&quot;implementing-cat-file&quot;&gt;Implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat-file&lt;/code&gt; command was easier to implement, because it’s essentially just the opposite. Based on a hash, find the corresponding file, uncompress it, and read its contents.&lt;/p&gt;

&lt;p&gt;This time I created a dedicated function for the new command from the start, as shown in the &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/81c9f03e1ca76a483335876b42637833f8a0a524&quot;&gt;first commit&lt;/a&gt;. This commit only implements the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-p&lt;/code&gt; flag, though.&lt;/p&gt;

&lt;p&gt;This is an abridged version of the code from the commit above, stripped of the function boilerplate and also the error handling:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fullPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;filepath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.git/objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;folderName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fullPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewReader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;contentsWithoutHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contentsWithoutHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;h&lt;/code&gt; variable is the SHA1 the command receives. From that, we get the directory and file name, which we then use to assemble the full path, read the contents of the file and then uncompres it.&lt;/p&gt;

&lt;p&gt;Finally, I split the string by the null character and return the second part, which is whatever comes after the header.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/carlosschults/go-gitter/commit/56d10d3cb2ad0baa217a357b8f5d204eb5970620&quot;&gt;next commit&lt;/a&gt; after that implements the remaining flags. I won’t go line by line, since the important part is super simple:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uncompressedContents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\x00&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-p&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-t&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-s&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Go programmers reading this: I suspect this code isn’t the most beautiful and idiomatic Go you’ve ever seen, and I promise you that once I learn more about the language, I will refactor this. The priority for me at the moment was getting it to work.&lt;/p&gt;

&lt;h2 id=&quot;what-ive-learned-so-far&quot;&gt;What I’ve Learned So Far&lt;/h2&gt;
&lt;p&gt;The goal of this project is to learn the Go language and also more about Git’s implementation. So, what did I learn about both by completing these two commands?&lt;/p&gt;

&lt;p&gt;First, the Git side. I can say I was surprised about how simple is the way git saves objects. It is really just the type of the object, a space, the size, a null character to act as delimiter, and then the contents. I understood, at a high level, how git stored objects, but actually implementing it gave me an appreciation for how simple and elegant it all is.&lt;/p&gt;

&lt;p&gt;And about the Go side? Generally speaking, I really like it. I appreciate how readable the language is. I think even someone with zero experience in Go could read this code and at least get the gist of it, as long as they are already a programmer.&lt;/p&gt;

&lt;p&gt;I also like the fact that Go is opinionated. For instance, if you have an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; statement, you have to use the curly braces. Otherwise, your won’t compile. So, this is one less thing for programmers to fight about and to have coding standard meeting about and to write linter rules about. It makes life simpler.&lt;/p&gt;

&lt;p&gt;One aspect that I don’t like is the error handling. Having those if statements verifing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;err&lt;/code&gt; everywhere polutes the code. In C#/.NET, when there is an error that is something that should be absolutely impossible, I just let the exception bubble out until it reaches the top level exception handling middleware, where it gets logged and the user receives a message with the adequate level of detail.&lt;/p&gt;

&lt;p&gt;Maybe there’s some idiomatic way to do something like that in Go as well, but right now I’m not aware. But other than that, I really like the language so far.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;For the next step I’ll implement another plumbing command called &lt;a href=&quot;https://git-scm.com/docs/git-update-index&quot;&gt;update-index&lt;/a&gt;. This is necessary so I can stage changes and eventually commit them.&lt;/p&gt;

&lt;p&gt;If you want to play with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go-gitter&lt;/code&gt;, install it like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;github.com/carlosschults/go-gitter/ggt@latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then you can use the commands like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;hi | gtt hash-object &lt;span class=&quot;nt&quot;&gt;--stdin&lt;/span&gt;
ggt cat-file &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 45b983be36b73c0788dc9cbcb76cbb80fc7bb057
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should be able to hash something with real git and then reading it with go-gitter, and vice-versa.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and see you on the next update.&lt;/p&gt;
</description>
        <pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/building-git-in-go-part2</link>
        <guid isPermaLink="true">https://carlosschults.net/en/building-git-in-go-part2</guid>
        
        <category>projects</category>
        
        <category>git</category>
        
        <category>go</category>
        
        <category>go-gitter</category>
        
        
      </item>
    
      <item>
        <title>Your Commit Messages Suck. Let Me Show You How To Fix That</title>
        <description>&lt;p&gt;Your commit messages suck. They are, at best, useless. At worse, they are harmful and misleading.
I don’t say this to be mean. Quite the opposite, I mean this in the most charitable way possible. I’m here to help.&lt;/p&gt;

&lt;p&gt;If you know you’re the exception, you can stop reading. I’m serious, close this step and go watch some YouTube. There, I just gave you back some minutes, you’re welcome.&lt;/p&gt;

&lt;p&gt;Still here? That’s great, recognizing you have a problem is the first step to get better. As I was saying, your commit messages are useless.&lt;/p&gt;

&lt;p&gt;Don’t get offended. This is mostly not your fault. Chances are, nobody every taught you how to write good messages, or even why that’s important. And writing is freaking &lt;em&gt;hard&lt;/em&gt;, let me tell you.&lt;/p&gt;

&lt;p&gt;Good news is, you’ve finally got someone to help you. In this post, I will explain everything you need to know about terrible commit messages and, of course, how to write great ones instead.&lt;/p&gt;

&lt;h2 id=&quot;your-commit-messages-suck-because&quot;&gt;Your commit Messages Suck Because…&lt;/h2&gt;
&lt;p&gt;Why is it that most commit messages are so bad? In my experience, the reasons amount to the reason I’ll talk about now. Keep in mind that there is nothing scientific or data-driven about any of these. They’re all based on my personal experience.&lt;/p&gt;

&lt;h3 id=&quot;you-only-care-about-coding&quot;&gt;…You Only Care About Coding&lt;/h3&gt;
&lt;p&gt;If you’re like most developers, you only or mostly care about coding. This is where the fun lives, and everything else you see it as a waste of time.
Also, I acknowledge that you’re probably under a lot of pressure to perform, to deliver as much value as quickly as possible. So, what you want the most is finish what you’re doing, merge your PR and then get another ticket off of Jira/Azure/Linear to start implementing.&lt;/p&gt;

&lt;p&gt;What ends up happening is that anything that is not coding is treated like an afterthought and not given as much care. This includes testing, documenting, preparing a review of the implemented feature for the weekly retro and, of course, writing commit messages and PR descriptions.&lt;/p&gt;

&lt;h3 id=&quot;sometimes-you-dont-understand-what-youre-doing&quot;&gt;…Sometimes You Don’t Understand What You’re Doing&lt;/h3&gt;
&lt;p&gt;Great commit messages and great documentation in general should focus on the &lt;em&gt;why&lt;/em&gt; of things. What’s the motivation behind you making those changes? What’s the problem you’re trying to solve, why is it worth solving, in which way it helps your team and your company?&lt;/p&gt;

&lt;p&gt;It may seem crazy that a programmer would start working on a task he or she doesn’t fully understand. But I know I have, and bet you have too. Of course, how are you supposed to explain the why behind a change when even you don’t fully grasp it?&lt;/p&gt;

&lt;h3 id=&quot;writing-is-hard&quot;&gt;…Writing Is Hard&lt;/h3&gt;
&lt;p&gt;As Phil Karlton once put, &lt;a href=&quot;https://martinfowler.com/bliki/TwoHardThings.html&quot;&gt;there are only two hard things in computer science&lt;/a&gt;, and naming things is one of them.&lt;/p&gt;

&lt;p&gt;If you think about it, “naming things” is a form of writing. A subset of writing, if you will. So, yeah, writing commit messages is hard because writing, in general, is hard.&lt;/p&gt;

&lt;h3 id=&quot;nobody-has-taught-you&quot;&gt;…Nobody Has Taught You&lt;/h3&gt;
&lt;p&gt;I think that developer education often fails to teach lots of important things that you actually need as a software engineer. True error handling is one of them.&lt;/p&gt;

&lt;p&gt;Fair, they’ll teach you the mechanics of how a try-catch-finally work, but often they won’t teach you when to catch an exception, when not to catch it, when to throw an exception, when to log it or not, and so on.&lt;/p&gt;

&lt;p&gt;And writing commit messages is one of those things.&lt;/p&gt;

&lt;h3 id=&quot;github-taught-you-bad-habits&quot;&gt;…GitHub Taught You Bad Habits&lt;/h3&gt;
&lt;p&gt;Let’s get this out of the way: I use GitHub every day, and I love it. GitHub is the &lt;a href=&quot;https://en.wikipedia.org/wiki/Killer_application&quot;&gt;killer app&lt;/a&gt; for Git, and Git wouldn’t have gotten the same level of adoption without GitHub.&lt;/p&gt;

&lt;p&gt;That being said, I do believe that the popularity of GitHub and pull requests caused people to care more about pull requests than about the individual commits. And it does make sense: pull requests support discussions that live on as a historical artifacts of that project, they support attachments, rich text and what have you.&lt;/p&gt;

&lt;p&gt;So, it makes sense that some people don’t put a lot of effort writing good commit messages, claiming that they can write rich PR descriptions instead.&lt;/p&gt;

&lt;p&gt;Of course what ends up happening frequently is that they don’t write PR descriptions either!&lt;/p&gt;

&lt;h3 id=&quot;gits--m-option-trained-you-poorly&quot;&gt;…Git’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; Option Trained You Poorly&lt;/h3&gt;
&lt;p&gt;I think that most programmers don’t even know that commit messages can have a body with multiple lines. And the culprit here is the fact that most people teach the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit&lt;/code&gt;command like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Some message&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And not even mention that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; flag is just a convenience for when you have a one-line message, which should be the exception rather than the norm.&lt;/p&gt;

&lt;h3 id=&quot;you-dont-have-proper-commit-hygiene&quot;&gt;…You Don’t Have Proper Commit Hygiene&lt;/h3&gt;
&lt;p&gt;Writing commit messages that aren’t trash is part of a broader thing that some people call “version control hygiene.”&lt;/p&gt;

&lt;p&gt;This is exactly what it sounds like: don’t be a slob when writing code.&lt;/p&gt;

&lt;p&gt;Sometimes you struggle when writing a commit message because you work in a messy way. If your changes are a hodgepodge of bug fixes, refactorings, dead code and half-baked implementation ideas, of course you’re going to have a problem writing a descriptive and useful commit message.&lt;/p&gt;

&lt;p&gt;This is often caused by a lack of Git skills. If you don’t master tools like stashing, reseting, interactive rebasing and others, then you’re more likely to make a big mess out of your work.&lt;/p&gt;

&lt;h2 id=&quot;taxonomy-of-bad-commit-messages&quot;&gt;Taxonomy of Bad Commit Messages&lt;/h2&gt;
&lt;p&gt;I have found that commit messages can be bad in a few number of categories. I’ll cover now some of them.&lt;/p&gt;

&lt;h3 id=&quot;almost-useless-one-liner&quot;&gt;Almost Useless One-Liner&lt;/h3&gt;
&lt;p&gt;This is the one-line message that gives a high-level explanation of what the change was. I call it “almost” useless because at least the summary is accurate.&lt;/p&gt;

&lt;p&gt;It then fails to add any more context. I’m left with questions like:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;What was the problem that originated this change?&lt;/li&gt;
  &lt;li&gt;Why did the author consider this change to be the most optimal way of solving this issue?&lt;/li&gt;
  &lt;li&gt;Is there an issue or ticket associated with this work?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some examples, with my comments:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Added new index to table # what index? what table? to what purpose?
Enable EF Core execution strategy# what is this strategy thing? why did you have to enable it?
Added Required attribute to model # Which model? Also, isn&apos;t this a breaking change that will affect current users?
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;useless-one-liner&quot;&gt;Useless One-Liner&lt;/h3&gt;
&lt;p&gt;The useless one-liner is…well, like the almost useless one-liner, but completely useless.&lt;/p&gt;

&lt;p&gt;The examples don’t merit more comments:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;changes
ui
not working
more changes
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I mean, by the time you’re writing “changes” as a commit message, you might as well just say “potatoes”. Or write a joke. It would be just as useless but at least it might have been funny.&lt;/p&gt;

&lt;h3 id=&quot;ticket-system-reference-only&quot;&gt;Ticket System Reference Only&lt;/h3&gt;
&lt;p&gt;This is when people only add an id of issue/ticket/card from their issue system, and nothing more. Some examples:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;JIRA-42
AZ-2234
&lt;span class=&quot;c&quot;&gt;#125&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I think this category of commit messages manages to be both more useful but also more annoying then the previous ones. Yes, it’s more useful, since I can go always go to our ticketing system, look for the issue, and learn more about the work. Of course, nothing guarantees that the commit will only have changes related to the issue in question, but this is a conversation for another time.&lt;/p&gt;

&lt;p&gt;This is also more annoying because it requires the reader to stop and go to another place to get context for that change. I don’t know about you, but I’d like to learn the reason behind a commit from the commit itself, just like &lt;del&gt;God&lt;/del&gt;Linus intended.&lt;/p&gt;

&lt;p&gt;Besides the annoyance, there is a greater risk here: the possibility that, someday, your company will migrate from the current ticketing system and then you’ll be left without those descriptions. All companies I’ve worked for as a software developer have done at least one such migration, and I’m sure you probably have lived through at least one.&lt;/p&gt;

&lt;h3 id=&quot;the-misleading-one-liner&quot;&gt;The Misleading One-Liner&lt;/h3&gt;
&lt;p&gt;Sometimes you have a message that says something seemingly harmless, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Add PrintHtmlOutput() method&lt;/code&gt;. And then it turns out the changes also add a breaking change to an endpoint or change something in the way the application interacts with the database.&lt;/p&gt;

&lt;h2 id=&quot;you-will-write-great-commit-messages-when-you&quot;&gt;You Will Write Great Commit Messages When You…&lt;/h2&gt;
&lt;p&gt;Now you understand why you write bad commit messages, and &lt;em&gt;how&lt;/em&gt; they are bad. Ready to learn how to improve?&lt;/p&gt;

&lt;h3 id=&quot;stop-writing-one-liners&quot;&gt;…Stop Writing One-Liners&lt;/h3&gt;
&lt;p&gt;One-liners are great when the scope of your change is small. If your commit only fixes a typo, then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix typo&lt;/code&gt; is a valid commit message. But most often commits contain many more changes, and in those cases writing a one-liner is a missed opportunity to write a durable piece of documentation.&lt;/p&gt;

&lt;p&gt;So, please, stop using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-m&lt;/code&gt; flag when commiting. Write a proper body with more detail for most of your messages.&lt;/p&gt;

&lt;h3 id=&quot;lead-with-the-what-expand-with-the-why-and-how&quot;&gt;…Lead With The “What”, Expand With The “Why” and “How”&lt;/h3&gt;
&lt;p&gt;So, now you know you’re supposed to write a summary and a body for most of your commit messages. What should be in each?&lt;/p&gt;

&lt;p&gt;Simple: start with the summary, in which you describe &lt;em&gt;what&lt;/em&gt; you did. Make it descriptive but concise.&lt;/p&gt;

&lt;p&gt;Inside the body, describe what is the problem you’re trying to solve, or the reason that motivated the change. Then, explain how you solved it, but from a high-level perspective. Don’t add too much detail, because remember your reader can always see the diff.&lt;/p&gt;

&lt;p&gt;If necessary, add more information, such as:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;trade-offs involved in your decision&lt;/li&gt;
  &lt;li&gt;alternatives you considered but ultimately decided against&lt;/li&gt;
  &lt;li&gt;reference links for possibly unkown terms you used (for instance, a link to an Wikipedia article, or to Martin Fowler’s &lt;a href=&quot;https://refactoring.com/catalog/&quot;&gt;Catalog of Refactorings&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;reference links for the solution you employed (for instance, a link to a Stack Overflow answer)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;follow-the-5072-rule&quot;&gt;…Follow the 50/72 Rule&lt;/h3&gt;
&lt;p&gt;The 50/72 rule is the closest we have to a standard when it comes to commit messages. It was &lt;a href=&quot;https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html&quot;&gt;first proposed by Tim Pope&lt;/a&gt; and it goes like this:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Start with a summary, capitalized, and make it 50 characters long at the most&lt;/li&gt;
  &lt;li&gt;Add a blank line&lt;/li&gt;
  &lt;li&gt;Then you add a body, wrapping its lines at 72 chars at the most&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These limits may seem arbitrary, but there are historical reasons they’ve been picked. To make a long story short, they play nicely with many different tools that work with commit messages.&lt;/p&gt;

&lt;p&gt;Another important point is that you should write your summary in the imperative mood. That is, “Implement password hashing” instead of “Implemented password hashing”, for instance. At first, this might look weird, but this is the standard that Git itself uses. If you don’t believe, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git revert&lt;/code&gt; to revert a commit, and you’ll see that the generated commit’s message is in the imperative mood:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Revert &lt;span class=&quot;s2&quot;&gt;&quot;Add line of text&quot;&lt;/span&gt;

This reverts commit 5ab08c5d3ee7bfdb334406d418d96f76d08962fe.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See? “Revert” instead of “Reverted.”&lt;/p&gt;

&lt;p&gt;Additionally, and optionally, you can add a commit trailer. Commit trailers are metadata you can add to the bottom of your commit message, following the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Name: value&lt;/code&gt; syntax. They’re used to add useful metadata, such as who signed-off on a change, who co-authored something with you, and also to associate your commit to an issue or ticket.&lt;/p&gt;

&lt;p&gt;For instance, if you’re using GitHub issues, you can add a trailer like this:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Closes: #456&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And it would automatically associate the commit to the issue and close it. There are other keywords you can use, such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fixes&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resolves&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Resolved&lt;/code&gt;, and so on. You can learn more about automatically closing GH issues &lt;a href=&quot;https://docs.github.com/en/issues/tracking-your-work-with-issues/using-issues/linking-a-pull-request-to-an-issue&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;adopt-atomic-commits&quot;&gt;…Adopt Atomic Commits&lt;/h3&gt;
&lt;p&gt;The idea of atomic commits is simple: have a commit only contain changes that are logically related. This is the opposite of the lack of version control hygiene that I talked about earlier.&lt;/p&gt;

&lt;p&gt;So, let’s say you’re currently working on a feature. Then your boss tells you to stop and fix a bug. You go and fix the bug, and then you have your changes from the start of your feature implementation.&lt;/p&gt;

&lt;p&gt;Don’t commit everything together! Commit only the bug fix changes as a cohesive unit with a high-quality, descriptive message. Then you can go back to your feature and commit that.&lt;/p&gt;

&lt;p&gt;Doing things like these require you master the tools of Git. You need to know how to stage changes and commit only those instead of everything. You need to know how to stash. Often, you’ll need to know how to commit things and then edit that history.&lt;/p&gt;

&lt;p&gt;Those skills are worth having. Get them!&lt;/p&gt;

&lt;h3 id=&quot;commit-often-perfect-later&quot;&gt;…Commit Often, Perfect Later&lt;/h3&gt;
&lt;p&gt;You don’t have to wait until you’re “done” to commit. Instead, you should commit all of the time. Work in small increments, and commit along the way.&lt;/p&gt;

&lt;p&gt;That way, if you make mistakes and needs to throw some work away, you just revert a few minutes’ worth of work instead of hours. You also have those checkpoints you can go back to, should the power went off or something.&lt;/p&gt;

&lt;p&gt;For instance, people who practice TDD (test-drive development) often commit every time they reach the green phase. In other words, every time they make the tests pass.&lt;/p&gt;

&lt;p&gt;It’s also a good idea to leave all your commits clean. By that I mean, all of your commits, when applied, should leave your project in a state where it builds successfully and all tests pass. That makes it easier for you or someone else to use &lt;a href=&quot;/git-bisect-intro/&quot;&gt;git bisect in the future to find where a bug was introduced&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But if you follow this tip, you might end up with many tiny little commits that don’t have good messages, or that don’t represent a cohesive set of changes. How to solve this?&lt;/p&gt;

&lt;p&gt;The answer is: &lt;a href=&quot;/en/git-beautiful-history/&quot;&gt;you edit your history to make it look beautiful&lt;/a&gt;. Editing your history is frowned upon, and with good reason, when it’s a branch other people already depend on. But if you’re working on your own isolated branch and no one depends on your changes, you can do whatever you want up to that point. So, commit early and often, then amend and rebase your way into a history that makes sense and has great commit messages.&lt;/p&gt;

&lt;h2 id=&quot;examples-of-great-commit-messages&quot;&gt;Examples of Great Commit Messages&lt;/h2&gt;
&lt;p&gt;Now it’s finally time to show you some examples of valuable commit messages that incorporate everything we’ve been covering so far.&lt;/p&gt;

&lt;p&gt;For instance, instead of:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Added Required attribute to model
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Write:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Make PhoneNumber required on /reservations endpoint

The /reservations endpoint originally didn&lt;span class=&quot;s1&quot;&gt;&apos;t require a phone number.
The reservations were being accepted but, as data flowed to downstream
systems, the lack of phone number was causing some processes to crash.

We are now adding the [Required] attribute to the PhoneNumber property
on the ReservationRequestModel. This is a breaking change, so that&apos;&lt;/span&gt;s
why, as part of this changes, we are versioning the endpoint as 2.0

Fixes: AB#456
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;See how it goes:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;The message starts with a summary that describes what was done&lt;/li&gt;
  &lt;li&gt;The body starts with a problem statement, then explains how the current change solves it&lt;/li&gt;
  &lt;li&gt;Finally, we have a trailer to associate and close a ticket on our board&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the second example, let’s do something a bit more elaborate. Instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enable EF Core execution strategy&lt;/code&gt;, you can use:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Enable EF Core execution strategy &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Azure SQL

After migrating to Azure SQL, save operations started failing
intermittently &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;production with transient connection errors.
Azure SQL occasionally drops connections during scaling events
and failovers, and Entity Framework does not retry failed
operations by default.

Enabled the built-in SQL Server execution strategy &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;EF Core,
which automatically retries failed operations using exponential
backoff when a transient error is detected.

An execution strategy is a configurable EF Core component that
intercepts database operations and decides whether to retry
them on failure. The SQL Server provider ships with a strategy
that knows which error codes Azure SQL considers transient.

&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1]: https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency

Closes: &lt;span class=&quot;c&quot;&gt;#89&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Do all messages need this kind of in-depth message? Or course not. For instance, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Fix typo&lt;/code&gt; is a great commit message, if all you’re doing in that commit is fixing a typo. The same goes for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remove commented-out code&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Remove blank lines&lt;/code&gt;, and so on.
The length of your commit message needs to be directly proportional to the size/scope of your change.&lt;/p&gt;

&lt;h2 id=&quot;ai-changes-everything-ordoes-it&quot;&gt;AI Changes Everything. Or…Does It?&lt;/h2&gt;
&lt;p&gt;I know what you have been wondering all of this time. “But..but…but…what about AI?”&lt;/p&gt;

&lt;p&gt;My honest take is that AI changes little, if anything at all, of what we’ve been discussing.&lt;/p&gt;

&lt;p&gt;For starters, AI or not AI, the fundamentals remain the same:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Great commit messages should still focus more on the why instead of on the what and how.&lt;/li&gt;
  &lt;li&gt;The 50/72 is still a solid guideline to follow.&lt;/li&gt;
  &lt;li&gt;Using the imperative mood for summaries continues to be the standard for lots of tooling, including Git and GitHub themselves.&lt;/li&gt;
  &lt;li&gt;Great commit messages still carry immense value for future readers, which may include AI itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;But AI is great at writing commit messages? Why should I bother?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When it comes to commit messages, AI is, in fact, great at one thing. And that is summarizing a collection of changes and writing a very well-written, grammatically correct, professional-sounding…detailed listing of all the changes.&lt;/p&gt;

&lt;p&gt;Which is exactly what you shouldn’t be doing! Where AI fails is exactly the most important part, which, by now, you should be tired of reading: the why.&lt;/p&gt;

&lt;p&gt;I’m not saying you shouldn’t use AI to help you in crafting commit messages. Of course you can. I use it a lot. This is an example of prompt I frequently use with Claude, with some variations:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Write a concise, well-crafted commit message for the diff I&apos;m going to give you.
Make it more high-level, focusing on the why rather than listing all changes in great detail.
Follow these rules:
- Summary
	- Brief description of what was done
	- 50 chars at the most
	- Use imperative mood
	- Do not use conventional commits
- Body
	- Brief description of the &quot;how&quot;, but focus more on the reason for the changes
	- Use prose rather than bullet points.
	- Use past tense
	- Lines no longer than 72 chars
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then I run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff | clip&lt;/code&gt; and paste the results there with this prompt.&lt;/p&gt;

&lt;p&gt;What I get back is always a message that is very well-written, much more detailed about describing changes than what I’d like, and that completely misses the point of why we’re doing the changes. Which is completely unsurprising, because how on Earth would it know if I haven’t told it?&lt;/p&gt;

&lt;p&gt;Then, what I do is explain the reasons we did the change. And ask to try again, and make it more high level and include the explanation. Sometimes the second version I get is good enough, but often I need at least three until I’m satisfied.&lt;/p&gt;

&lt;p&gt;Do you understand the pattern? This is a collaboration between the AI and I. We are working together to craft a message. I’m not 100% offloading it to the AI.&lt;/p&gt;

&lt;p&gt;When I’m using Claude Code, those rules from above exist in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Claude.md&lt;/code&gt; file for the project. In this scenario, it tends to do much better understanding the “why”, because everything started with a prompt in which I explained the reason behind the change, and then we did a planning session before starting to implement the change.&lt;/p&gt;

&lt;p&gt;But even then, the AI often still needs a lot of guidance until it’s able to write a commit message that really focus on the reasons behind the change and gives information at the right level of abstraction. Left to its own devices, AI produces well-written messages that are essentially a diff in prose.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;By now, you’ve probably realized this was a fairly opinionated post. Some of the things covered here are very close to being a standard, such as the 50/72 rule and idea of writing the summaries using the imperative mood.&lt;/p&gt;

&lt;p&gt;However, some of what I’ve discussed are personal preferences. For instance, I usually don’t use &lt;a href=&quot;https://www.conventionalcommits.org/en/v1.0.0/&quot;&gt;Conventional Commits&lt;/a&gt;. The reasons for that go beyond the scope of this post, but they exist. But they’re also fairly personal, so I won’t hold it against you if you like to use Conventional Commits.&lt;/p&gt;

&lt;p&gt;The main takeway I want you to take from this post is: put some work into your commit messages. Don’t just write whatever; craft your messages. Work on them, hone them, until you can’t possibly improve them.&lt;/p&gt;

&lt;p&gt;Yeah, that’s hard. It might be frustrating. It might feel a waste of time spending 10, 15, or even 20 minutes crafting a message that your favorite LLM could have knocked out in seconds.&lt;/p&gt;

&lt;p&gt;But I guarantee you: years from now, when you’re investigating a critical production issue and then you’ve come across some great commit messages that offer valuable insights into why some changes were made…you’re going to be happy you did.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;
</description>
        <pubDate>Tue, 31 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/your-commit-messages-suck</link>
        <guid isPermaLink="true">https://carlosschults.net/en/your-commit-messages-suck</guid>
        
        <category>tutorial</category>
        
        <category>git</category>
        
        <category>rant</category>
        
        
      </item>
    
      <item>
        <title>Implementing git in Go From Scratch, For Fun and...Profit?</title>
        <description>&lt;p&gt;I’ve recently started working on my newest project: building git in Go, from scratch. What’s the point in that?, you might be wondering.&lt;/p&gt;

&lt;p&gt;Well, it’s quite a useless project in the sense that, you know, git has existed for 20 years. (Thanks, Linus).
My goal with this project is two-fold:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;learn the Go language&lt;/li&gt;
  &lt;li&gt;strengthen my knowledge about git internals&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;project-scope&quot;&gt;Project Scope&lt;/h2&gt;
&lt;p&gt;I don’t intend to implement 100% of git. That would be simply too hard. What I’m going to do is to implement a small subset of git commands, only in their most basic variations for the most part. 
This is the current list of what I intend to implement:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git init&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This list isn’t static. I might decide to implement more commands, or fewer. It all depends whether I feel like I’ve learned enough. We’ll see how this goes.&lt;/p&gt;

&lt;h2 id=&quot;project-workflow-i-really-didnt-know-what-to-call-this-section&quot;&gt;Project Workflow (I really didn’t know what to call this section)&lt;/h2&gt;
&lt;p&gt;How will I go about all of this, in practice? I’m already going, since I’ve started about a week ago. So, the way I am going about this is basically going through that list of commands, implementing one by one, and documenting my learnings on this blog.&lt;/p&gt;

&lt;p&gt;I’m not sure about the cadence of the blog posts yet, though. I feel like weekly updates are too much; since I only have about 30 to 50 minutes per day to work on this, I don’t want to lose too much time writing the updates themselves.&lt;/p&gt;

&lt;p&gt;So I guess I will start by writing the posts whenever I feel I’ve accumulated enough interesting updates to share, then I’ll share them. I might later settle into a regular cadence, but don’t count on that.&lt;/p&gt;

&lt;h2 id=&quot;about-llm-usage&quot;&gt;About LLM Usage&lt;/h2&gt;
&lt;p&gt;I’ve imposed some rules on myself for this project. The most important one is that zero code will be written by AI/LLMs. It would defeat the purpose, since the goal of this is to actually learn the language.&lt;/p&gt;

&lt;p&gt;That doesn’t mean I’m not using AI at all. I’m using Claude to help me plan the roadmap, so to speak. It’s been helping me decide the order of the commands that make more sense, what are the Go concepts that are required for me to build this and which ones I can skip, and so on.&lt;/p&gt;

&lt;p&gt;For my actual Go learning, I’m using the Go documentation and good-old search. Like the old days.&lt;/p&gt;

&lt;h2 id=&quot;building-git-in-go-the-first-update&quot;&gt;Building git in Go: The First Update&lt;/h2&gt;
&lt;p&gt;So, what have I done so far?
I’ve started this project on Monday, 2026-03-02. One week ago as the time of this writing. During the first three days, I’ve followed the &lt;a href=&quot;https://go.dev/tour/welcome/1&quot;&gt;Go Tour&lt;/a&gt; in order to remember the few things I knew about the language and to learn more of the fundamentals.&lt;/p&gt;

&lt;p&gt;On Thursday, I finished the tour. I skimmed the lessons about generics very quickly and completely skipped the ones about concurrency. On this day, I created the &lt;a href=&quot;https://github.com/carlosschults/go-gitter&quot;&gt;repository&lt;/a&gt; and wrote a “Hello World.”&lt;/p&gt;

&lt;p&gt;For some reason, I didn’t touch the project on Friday. Saturday was the day I actually implemented my first command, and the only one implemented so far: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggt init&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Oh yeah, by the way: my executable for this will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ggt&lt;/code&gt;, because the project itself is called &lt;strong&gt;go-gitter&lt;/strong&gt;. Yes, it’s silly, but I like silly names, what can I do?&lt;/p&gt;

&lt;p&gt;Implementing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; was very easy and I’m sure it’s only getting harder from now on. Creating a git repository is surprisingly easy, and it’s something you can do manually, without using git itself at all. Doubt it? Ok, I’ll teach you.&lt;/p&gt;

&lt;p&gt;Go somewhere in your computer and create a folder. Go inside this folder and create a new one called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt;. Exactly like this.&lt;/p&gt;

&lt;p&gt;Now, go inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; and create a text file called HEAD. Just like this, without any extensions. Inside this file, put the following text, then save it:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ref: refs/heads/main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next step: create two new folders, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refs&lt;/code&gt;. Inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;objects&lt;/code&gt;, create yet two empty folders: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;info&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pack&lt;/code&gt;. Inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refs&lt;/code&gt;, create &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;heads&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tags&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, using the terminal, go to the same level where the .git folder is and then run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git status&lt;/code&gt;. You’ll see a result like this:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;On branch main

No commits yet

nothing to commit (create/copy files and use &quot;git add&quot; to track)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Congrats! You’ve just created a git repo, manually. This is exactly what &lt;a href=&quot;https://github.com/carlosschults/go-gitter/blob/main/ggt/main.go&quot;&gt;my Go code is doing&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;follow-the-updates&quot;&gt;Follow the Updates&lt;/h2&gt;
&lt;p&gt;The updates to this progress will be tracked by the &lt;a href=&quot;/tag/go-gitter&quot;&gt;go-gitter&lt;/a&gt; tag, so you can bookmark that page, if you want. 
I’ve already linked to the repository, but here it is again, in case you’ve missed: &lt;a href=&quot;https://github.com/carlosschults/go-gitter&quot;&gt;go-gitter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading. See you on the next update.&lt;/p&gt;
</description>
        <pubDate>Mon, 09 Mar 2026 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/implementing-git-in-go</link>
        <guid isPermaLink="true">https://carlosschults.net/en/implementing-git-in-go</guid>
        
        <category>projects</category>
        
        <category>git</category>
        
        <category>go</category>
        
        <category>go-gitter</category>
        
        
      </item>
    
      <item>
        <title>What Are Breaking Changes?</title>
        <description>&lt;p&gt;&lt;img src=&quot;/img/what-are-breaking-changes/cover.jpg&quot; alt=&quot;&quot; /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@denisolvr?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Denis Oliveira&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/grayscale-photography-of-speedboat-yplNhhXxBtM?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m starting a series of articles in which I’ll define some concepts or terms that are common in software development, and I’m starting with &lt;strong&gt;Breaking Changes&lt;/strong&gt;. After all, why start with A like a normal person?&lt;/p&gt;

&lt;p&gt;Ok, but…why write such a series?&lt;/p&gt;

&lt;p&gt;Mainly because I want to create the resources I wish I had when I was starting out.&lt;/p&gt;

&lt;p&gt;Back then, it used to drive me crazy when people would just casually say things like I was already familiar with them.&lt;/p&gt;

&lt;p&gt;Mind you, I’m an &lt;del&gt;old&lt;/del&gt; experienced developer, which means in my time I didn’t have an AI buddy to just ask those things. Yeah, Google was already a thing, how &lt;del&gt;old&lt;/del&gt; experienced do you think I am? Jesus!&lt;/p&gt;

&lt;p&gt;The problem is that often explanations you’d find by Googling weren’t that great. Often, Stack Overflow helped, but not always. Nowadays, of course, you can ask your favorite LLM side-kick to explain things to you, if you don’t mind the generic tone, depleted of any authentic human voice or anecdotes.&lt;/p&gt;

&lt;p&gt;So, I’m writing these articles to help beginners out there understand a bit better some key software development concepts, one at a time, in a simple and hopefully engaging way, courtesy of yours truly.&lt;/p&gt;

&lt;p&gt;Let’s begin?&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-breaking-change&quot;&gt;What is a breaking change?&lt;/h2&gt;
&lt;p&gt;“Breaking change” means any change you make to your software that can cause the code of its users to break, after they upgrade. Breaking changes only make sense when you think about software that you create and somehow distribute for third-party users.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://imgs.xkcd.com/comics/workflow.png&quot; alt=&quot;The relevant XKCD&quot; title=&quot;There is always a relevant XKCD&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Think of things like:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;APIs&lt;/li&gt;
  &lt;li&gt;libraries/packages&lt;/li&gt;
  &lt;li&gt;frameworks&lt;/li&gt;
  &lt;li&gt;CLI tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s see an example. While developing an application for your company, you extracted some common functionality as a library and decided to publish that as an open-source package hosted on &lt;a href=&quot;https://www.nuget.org&quot;&gt;https://www.nuget.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After a while, you publish a new version in which you change the name of one of the most important and used methods inside the package. Users upgrade to your newest version and now their code doesn’t compile, because it still refers to the method using the original name. &lt;strong&gt;That’s a breaking change!&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTE
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Important: for something to be a breaking change, it’s not required that 100% of the users break when they upgrade. In our example, it’s possible that not all users were actually using that specific method in their code which means their code wouldn’t have broken. But the change is still a breaking change, because the potential for breaking is there.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;examples-of-breaking-changes&quot;&gt;Examples of Breaking Changes&lt;/h2&gt;

&lt;p&gt;In practice, what types of changes are breaking changes?&lt;/p&gt;

&lt;p&gt;I’d say the most common one, or at least what most people would think of as a breaking change, would be deleting or renaming things.&lt;/p&gt;

&lt;p&gt;If you rename an API endpoint, a public class or method from your package, or a command from your CLI, code that uses those things will no longer work. And, for all practical effects, renaming is the same as deleting, because that old version no longer exists.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/travolta.gif&quot; alt=&quot;&amp;quot;Confused John Travolta looking for something&amp;quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Where is the method that was here?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There are other types of breaking changes, though, so let’s review some of them.&lt;/p&gt;

&lt;h3 id=&quot;new-required-parameters&quot;&gt;New Required Parameters&lt;/h3&gt;

&lt;p&gt;If you add new parameters to a method, and they are required, then all existing code that calls the method will now fail to compile. The solution here would be to add new parameters as optional, or even create a new method.&lt;/p&gt;

&lt;h3 id=&quot;removed-optional-parameters-or-made-them-required&quot;&gt;Removed optional parameters or made them required&lt;/h3&gt;

&lt;p&gt;This is a logical continuation of the previous one. If you remove an optional parameter, code that calls that method padding the parameter will now break. On the other hand, if you make an optional parameter required, the opposite happens: now all of the places that don’t pass the parameter will break.&lt;/p&gt;

&lt;h3 id=&quot;new-members-added-to-an-interface&quot;&gt;New Members Added To An Interface&lt;/h3&gt;

&lt;p&gt;Here I’m talking specifically about statically typed languages that have the concept of an interface in which you define behaviors that client classes need to implement.&lt;/p&gt;

&lt;p&gt;Adding a new member to an interface is a breaking change because now all classes that implement it wouldn’t have implemented the new member.&lt;/p&gt;

&lt;p&gt;Recently-ish, the C# team solved this problem in a way that sparked some controversy: adding the possibility of &lt;a href=&quot;https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/&quot;&gt;implementing methods on the interfaces themselves!&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;changed-the-type-of-a-method-parameter&quot;&gt;Changed the Type of a Method Parameter&lt;/h3&gt;

&lt;p&gt;If you change the type of a parameter from, say, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;string&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt;, you’re making sure that a lot of client code will break.&lt;/p&gt;

&lt;h3 id=&quot;changed-return-type-of-a-method-or-function&quot;&gt;Changed return type of a method or function&lt;/h3&gt;

&lt;p&gt;Again, depending on the old and new types, this might not even break, but it’s still a breaking change in general.&lt;/p&gt;

&lt;h3 id=&quot;changed-parameter-order&quot;&gt;Changed parameter order&lt;/h3&gt;

&lt;p&gt;This one is interesting because it might break in a different way than the others. For most of the examples I’ve been giving so far, “breaking” means that the code that consumes your code will fail to compile.&lt;/p&gt;

&lt;p&gt;With this one, you can do it in such a way that the code still compiles, but it fails to work properly.&lt;/p&gt;

&lt;p&gt;For instance, see this code:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IReadOnlyList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetProductsByCategory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;categoryId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;companyId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// implementation&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you inverted the order between &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;categoryId&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;companyId&lt;/code&gt;, the code would still compile but it wouldn’t work properly. It’d still be a breaking change, but one that fails in a subtler way.&lt;/p&gt;

&lt;p&gt;Of course if the two parameters are of different types, then it would fail in the sense of failing to compile. And that’s why a lot of people argue that you shouldn’t use primitives for things like ids, but create your own &lt;a href=&quot;https://carlosschults.net/en/genai-tiny-types&quot;&gt;tiny types&lt;/a&gt; for that.&lt;/p&gt;

&lt;h3 id=&quot;modified-error-handling-behavior-throwing-different-exceptions&quot;&gt;Modified error handling behavior (throwing different exceptions)&lt;/h3&gt;

&lt;p&gt;If your method used to throw a certain type of exception and now it throws a different one, that’s a breaking change, because code that was written to catch that specific first exception won’t work for the new one, unless it inherits from the first one.&lt;/p&gt;

&lt;h3 id=&quot;made-public-methods-or-properties-private&quot;&gt;Made public methods or properties private&lt;/h3&gt;

&lt;p&gt;For the client this is, effectively, the same as deleting them, so it’s an obvious breaking change.&lt;/p&gt;

&lt;h3 id=&quot;added-authentication-requirements-where-none-existed&quot;&gt;Added authentication requirements where none existed&lt;/h3&gt;

&lt;p&gt;Up until now, all of the examples were for libraries or packages. Now we’re going to see a few examples for web APIs. The first one has to do with authentication: if a given endpoint didn’t require authentication but now does, that’s a breaking change, because existing code that used to call that will now get a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/401&quot;&gt;401 Unauthorized&lt;/a&gt; error.&lt;/p&gt;

&lt;h3 id=&quot;added-new-required-properties-to-a-payload&quot;&gt;Added new required properties to a payload&lt;/h3&gt;

&lt;p&gt;That’s akin to adding new required properties to a public method, right? If your endpoint now expects a different payload than what it did before, existing code will break, likely getting a &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/400&quot;&gt;400 Bad Request&lt;/a&gt; error.&lt;/p&gt;

&lt;h3 id=&quot;rename-or-delete-an-endpoint&quot;&gt;Rename or delete an endpoint&lt;/h3&gt;

&lt;p&gt;This one is self explanatory.&lt;/p&gt;

&lt;h2 id=&quot;what-to-do-about-breaking-changes&quot;&gt;What to do about breaking changes?&lt;/h2&gt;

&lt;p&gt;This should be obvious by now but let’s spell it out: breaking changes are A Bad Thing™. You should avoid them like the plague.&lt;/p&gt;

&lt;p&gt;If you distribute any code of software publicly and there are people who depend on it, you won’t want to keep breaking their workflows frequently, or they’ll be mad at you, rightly so.&lt;/p&gt;

&lt;p&gt;Sometimes there’s no use, though. You just need to do a breaking change, be it removing a method or class that has become obsolete, or changing the signature of a function.&lt;/p&gt;

&lt;p&gt;When you have to do something like this, a few things are advised.&lt;/p&gt;

&lt;h3 id=&quot;gradually-deprecation&quot;&gt;Gradually Deprecation&lt;/h3&gt;

&lt;p&gt;Adding a breaking change is something that you shouldn’t take lightly because it can dramatically disrupt the workflow of your users. Also, don’t do it all of a sudden, out of the blue, and in one step.&lt;/p&gt;

&lt;p&gt;Before removing obsolete classes/methods/etc, first publicly announce you’re doing so, several versions in advance. Then, you mark that artifact as deprecated somehow, but still don’t remove it. For instance, in C# you can use the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.obsoleteattribute?view=net-9.0&quot;&gt;Obsolete&lt;/a&gt; attribute.&lt;/p&gt;

&lt;p&gt;Then, after a few versions, you then finally do your breaking change.&lt;/p&gt;

&lt;h3 id=&quot;add-instructions-to-your-release-notes&quot;&gt;Add Instructions to Your Release Notes&lt;/h3&gt;

&lt;p&gt;If you’re publishing software publicly for third-party use, you probably have some sort of release notes where you communicate what were the changes in this new version. Leverage that.&lt;/p&gt;

&lt;p&gt;When it’s time to actually publish a version with a breaking change, use your release notes to describe, in detail, what the change is and how it will affect your users.&lt;/p&gt;

&lt;p&gt;Usually, when a breaking change consists of retiring a method/class/endpoint, it comes accompanied by a new way of performing the same thing. After all, you wouldn’t be retiring the old way just because.&lt;/p&gt;

&lt;p&gt;In those cases, also use your release notes to explain in detail how users can adapt their code to migrate from the old to the new way of doing the task.&lt;/p&gt;

&lt;h3 id=&quot;use-semantic-versioning&quot;&gt;Use Semantic Versioning&lt;/h3&gt;

&lt;p&gt;Finally, use &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt; and use the version number to communicate that this is a breaking change, by releasing a major version.&lt;/p&gt;

&lt;p&gt;Semantic Versioning (or SemVer for short) is a standard for versioning in which you use a version number in this format: major.minor.patch.&lt;/p&gt;

&lt;p&gt;When your new version only contains bug fixes, and they don’t add breaking changes, you increment the patch component.&lt;/p&gt;

&lt;p&gt;For instance:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.0.0 -&amp;gt; 2.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If the version contains new functionality that doesn’t break compatibility, then you increment the minor component and reset the patch component:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.0.1 -&amp;gt; 2.1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now comes the most important part. When your version contains breaking changes, either cause by new functionality, bug fixes, or both, you increment the major number and reset the other two:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2.1.0 -&amp;gt; 3.0.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That way, you clearly communicate to your users the presence or absence of breaking changes in your newest release.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this post, I explained the concept of a breaking change, why it’s usually bad, and what to do about it. Quick recap:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Breaking changes are changes that break the code of your users, in the context of software that is distributed to third-party users.&lt;/li&gt;
  &lt;li&gt;Avoid adding breaking changes to your software, because they harm the experience of your clients.&lt;/li&gt;
  &lt;li&gt;Sometimes you can’t help but add a breaking change. In those cases, use gradual deprecation, communicate clearly what changed and how to adapt, and use semantic versioning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think that’s all. Thanks for reading, I hope this has been useful and I’ll see you again in the next installment of this series, in which I’ll probably go back to letter A, because I’m just weird like that.&lt;/p&gt;
</description>
        <pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/what-are-breaking-changes</link>
        <guid isPermaLink="true">https://carlosschults.net/en/what-are-breaking-changes</guid>
        
        <category>from_a_to_z</category>
        
        <category>breaking_changes</category>
        
        
      </item>
    
      <item>
        <title>How to Improve Developer Experience: 7 Things to Change</title>
        <description>
&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTE
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;I originally wrote this post for Nimbus. You can read the &lt;a href=&quot;https://www.usenimbus.com/post/how-to-improve-developer-experience-7-things-to-change&quot;&gt;original at their site&lt;/a&gt;.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;whats-developer-experience-why-should-you-care&quot;&gt;What’s Developer Experience? Why Should You Care?&lt;/h2&gt;

&lt;p&gt;In software development, we talk a lot about user experience, and rightly so. Since it’s the end user who benefits directly from the software we write, it makes sense that they’re front and center in all our efforts. But recently, another term has started to gain traction in the context of improving software quality: developer experience.&lt;/p&gt;

&lt;p&gt;That’s what this post is all about—developer experience. We’ll open by briefly explaining what developer experience is and why all software organizations should care about it. From there, we’ll jump into the practical bit by walking you through a list of suggestions you can adopt right away to improve the developer experience for your team or company.&lt;/p&gt;

&lt;p&gt;Here’s my definition of developer experience: how comfortable, straightforward, and enjoyable the experience of software development is for a given team or organization.&lt;/p&gt;

&lt;p&gt;Why is developer experience so important? Why have people started talking about it so much recently?&lt;/p&gt;

&lt;p&gt;It’s not rocket science. Software is tremendously valuable, thus the people who create software are tremendously valuable as well. It’s in the interest of any company that creates software to keep its developers happy and productive, especially in a hot market where developers are offered opportunities left and right.&lt;/p&gt;

&lt;p&gt;If you improve the developer experience at your company, you’re more likely to attract great developers and keep the ones you already have. Productivity is likely to go up, and so is the quality of output.&lt;/p&gt;

&lt;h2 id=&quot;developer-experience-improve-it-with-these-7-tips&quot;&gt;Developer Experience: Improve It With These 7 Tips&lt;/h2&gt;

&lt;p&gt;Without further ado, let’s see seven practical suggestions you can adopt today to improve the developer experience at your organization.&lt;/p&gt;

&lt;h3 id=&quot;1-minimize-interruptions&quot;&gt;&lt;strong&gt;1. Minimize Interruptions&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Generally speaking, software developers hate interruptions. Not because we’re prima donnas who can’t be bothered with meetings or activities that can be described as “social” (though some of us certainly are.)&lt;/p&gt;

&lt;p&gt;The problem with interruption is that software development is an activity that requires long stretches of intense focus. As any professional whose craft demands such a level of focus will say, achieving that state takes time and effort. However, losing it is easy: all it takes is Bob from accounting or your manager to drop by your cubicle or ping you on Slack to make that focus disappear into thin air.&lt;/p&gt;

&lt;p&gt;To improve developer experience, minimize interruptions. In more practical terms, do the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Use asynchronous communication as much as possible.&lt;/strong&gt; Try to use an internal newsletter, wiki articles, and e-mail updates instead of meetings and calls.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Adopt a meeting-free day.&lt;/strong&gt; Pick a day of the week, or at least half a day, in which everyone’s calendar is blocked and can’t be booked. That will give everyone the chance to have dedicated time for deep concentration.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Optimize the time and duration of meetings.&lt;/strong&gt; Meetings are unavoidable sometimes. When that’s the case, pick a time and duration that makes it easy for people to focus. For instance, if your company’s work hours end at 6:00 p.m., don’t schedule a meeting that ends at 5:30. Those final thirty minutes will most likely be lost since they’re not sufficient for developers to achieve the deep focus they need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-invest-in-technical-excellence&quot;&gt;&lt;strong&gt;2. Invest in Technical Excellence&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Most developers want to know that their work matters. They want to know that they’re working for a team that creates software to the highest standards using the best possible practices available and delighting users with great features delivered at a fast pace.&lt;/p&gt;

&lt;p&gt;Thus, investing in technical excellence is a great way to improve the experience of developers. The list of what you can do includes the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Adopt automated testing and, optionally, &lt;a href=&quot;/en/csharp-unit-testing-intro-tdd/&quot;&gt;test-driven development (TDD)&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Use continuous integration (CI) and continuous delivery and deployment (CD).&lt;/li&gt;
  &lt;li&gt;Have a code review process or, alternatively, pair programming.&lt;/li&gt;
  &lt;li&gt;Use static analyzers and linters to detect common issues in the code.&lt;/li&gt;
  &lt;li&gt;Gather and track quality metrics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are just a few suggestions about what you can do to foster a culture of technical excellence in which developers feel pride in their work and feel like their work has a purpose.&lt;/p&gt;

&lt;h3 id=&quot;3-give-developers-autonomy&quot;&gt;&lt;strong&gt;3. Give Developers Autonomy&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Autonomy is a big driver of productivity and happiness at work. In order to feel fulfilled, people need to have at least some degree of autonomy over the way they do their jobs.&lt;/p&gt;

&lt;p&gt;Generally speaking, developers should be awarded a high degree of autonomy over how they do their work. Allow teams to decide the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Which branching workflow best suit their needs&lt;/li&gt;
  &lt;li&gt;Whether they estimate using points, T-shirts sizes, hours, or something else entirely&lt;/li&gt;
  &lt;li&gt;How strictly they want to adhere to the ceremonies of their preferred flavor of agile (for instance, whether or not to have a daily scrum)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On an individual level, allow developers to choose whether they want to work remotely, at the office, or in a hybrid way. Give the contributor flexibility to assemble a benefits package that makes sense for them (some people have children, others do not, so benefits that cater only to people who are married with kids are bound to alienate a sizable part of your workforce.)&lt;/p&gt;

&lt;h3 id=&quot;4-remove-the-friction-when-creating-development-environments&quot;&gt;&lt;strong&gt;4. Remove the Friction When Creating Development Environments&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;One thing that virtually every developer hates is a manual, tedious, and error-prone process when creating a new development environment. These processes cause developers to take a long time until they’re able to contribute code to the team. Worst of all, the processes are often not easily reproducible, which means differences between environments can be introduced.&lt;/p&gt;

&lt;p&gt;As a consequence, the development environment drifts away from staging and production, making bugs more likely and creating the infamous “it works on my machine” excuse.&lt;/p&gt;

&lt;p&gt;To improve developer experience, invest in ways to facilitate the creation of consistent and reproducible environments. Container solutions such as Docker are a great way to achieve that. Alternatively, you can leverage solutions that offer the creation of development environments in the cloud.&lt;/p&gt;

&lt;h3 id=&quot;5-invest-in-developer-education&quot;&gt;&lt;strong&gt;5. Invest in Developer Education&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Developers also have a great experience when they feel like they master the tools of their trade. The feeling of being in control is simply exhilarating. It doesn’t only lead to higher quality output, but it’s also more enjoyable.&lt;/p&gt;

&lt;p&gt;So, a sure way to improve developer experience is to invest in their education. There are several ways to do that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Offer developers a monthly or annual stipend that they can freely use to invest in courses, books, or certifications.&lt;/li&gt;
  &lt;li&gt;Give developers time (as in, paid company time) during which they can study and practice&lt;/li&gt;
  &lt;li&gt;Offer company-paid learning resources such as a company library or services like Udemy or Pluralsight&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;6-dont-be-cheap-when-it-comes-to-tools&quot;&gt;&lt;strong&gt;6. Don’t Be Cheap When It Comes to Tools&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;If you want your developers to do great work, you must give them the tools to do so. If your developers can’t deliver great work due to a slow computer or the lack of a software license, that’s on you.&lt;/p&gt;

&lt;p&gt;Your engineers should have great hardware, such as a company-provided laptop, monitor, keyboard, and so on (and even office supplements like a great chair).&lt;/p&gt;

&lt;p&gt;You should also provide the necessary software. That includes IDE licenses, subscriptions to services, plugins, and what have you. No matter what your developers need in order to perform their work, the company should, within reason, provide it.&lt;/p&gt;

&lt;h3 id=&quot;7-listen-to-developers-feedback-and-act-upon-it&quot;&gt;&lt;strong&gt;7. Listen to Developers’ Feedback (and Act Upon It)&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;Last but not least, here’s the final item on our list: listen to your developers!&lt;/p&gt;

&lt;p&gt;Here’s the thing: software developers are usually smart people who care about what they do. Chances are they have pretty good ideas about how to improve not only their own experience but that of their teams and organizations as a whole.&lt;/p&gt;

&lt;p&gt;Listen to your developers. When it makes sense, put their suggestions into practice. Besides the benefit created by the suggestion itself, this will have the additional benefit of improving the team’s morale. Your developers will feel valued and like an essential part of the team. Which, of course, they are.&lt;/p&gt;

&lt;h3 id=&quot;improve-developer-experience-improve-your-company&quot;&gt;&lt;strong&gt;Improve Developer Experience, Improve Your Company&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;If your organization is a tech organization, then software developers are arguably your most precious assets. So, improving developer experience, besides being a decent, human thing to do, is also a great investment. It’s in your best interest to keep your developers happy and productive, and as you’ve seen in this post, this is something you can achieve relatively easily.&lt;/p&gt;

&lt;p&gt;The suggestions in this post are simply suggestions. Your mileage can vary (for instance, if you work in a highly regulated industry, giving developers a high degree of autonomy may not apply.) As always, use your judgment. Consider the list in this post as a starting point. Tweak it as needed, trim it, and add to it. What matters is that you improve the developer experience at your company for the sake of your developers, your end users, and the company as a whole.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</description>
        <pubDate>Tue, 08 Jul 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/improve-developer-experience</link>
        <guid isPermaLink="true">https://carlosschults.net/en/improve-developer-experience</guid>
        
        <category>devex</category>
        
        <category>opinion</category>
        
        
      </item>
    
      <item>
        <title>Git Switch Branch: Everything You Need to Know</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    NOTE
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;I originally wrote this post for Cloudbees. You can read the &lt;a href=&quot;https://www.cloudbees.com/blog/git-switch-branch-everything-to-know&quot;&gt;original at their site&lt;/a&gt;.&lt;/p&gt;


  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Repositories in &lt;a href=&quot;/tag/git&quot;&gt;Git&lt;/a&gt; work in a fundamentally different way from most other tools. One of the most glaring examples of said differences is branching. In most other VCS tools, branching is this elaborate ceremony. They make a huge deal out of it, and developers just give up, preferring workflows that don’t rely on many branches.&lt;/p&gt;

&lt;p&gt;In Git, the opposite is often true: branching is so cheap that most people do it a lot. People often get confused when trying to manage their branches. This post attempts to clear up some of that confusion by offering a guide on how to successfully git switch branch in an easy and safe way. Before we get there, though, we start with some basics, explaining what branches actually are in Git, how they work and how you create them.&lt;/p&gt;

&lt;p&gt;Before wrapping up, we share a bonus tip, covering how to check out remote branches. Let’s get started!&lt;/p&gt;

&lt;h2 id=&quot;how-do-git-branches-work&quot;&gt;How Do Git Branches Work?&lt;/h2&gt;

&lt;p&gt;How do branches work in Git? The first thing you need to know is that a repository in Git is made up of &lt;strong&gt;objects&lt;/strong&gt; and &lt;strong&gt;references&lt;/strong&gt;. The main types of objects in a Git repository are commits. References point to other references or to objects. The main types of references are—you’ve guessed it—branches.&lt;/p&gt;

&lt;p&gt;Objects in Git are immutable. You can’t change a commit in any way or move its position in history. There are commands that appear to change things, but they actually create new commits. References, on the other hand, change a lot. For instance, when you create a new commit, the current branch reference is updated to point to it.&lt;/p&gt;

&lt;p&gt;When you create a new branch, all that happens is that a new reference is created pointing to a commit. That’s why it’s so cheap and fast to create branches in Git. Speaking of which…&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-create-a-new-branch&quot;&gt;How Do I Create a New Branch?&lt;/h2&gt;

&lt;p&gt;We already have a whole post explaining how &lt;a href=&quot;/en/git-create-branch/&quot;&gt;you can create a branch in Git&lt;/a&gt;, covering the four mains ways to do that.&lt;/p&gt;

&lt;p&gt;Here, we’ll just cover the easiest way to create a branch in Git, which is simply using the branch command from the current branch. Let’s see an example:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;git-switch-demo
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;git-switch-demo
git init
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file1.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create first file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file2.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create second file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file3.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create third file&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the example above, we’ve created a new repository and added three commits to it, creating a new file per commit. Here’s a visual representation of the current state of our repository:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img1.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To create a new branch from the current point, we just have to run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’ve created a branch but haven’t switched to it yet. This is how our repo looks like now:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img2.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What if we added a new commit while still in the master branch? Would that impact the example branch? The answer is no. Execute the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Another file&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file4.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create fourth file&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the next section, we’ll show how you can git switch branch, and then you’ll be able to see for yourself how that new branch doesn’t contain the fourth commit. For now, take a look at the visual representation of the current state of our repo:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img3.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;how-do-you-switch-branches&quot;&gt;How Do You Switch Branches?&lt;/h2&gt;

&lt;p&gt;For most of Git’s history, the checkout command was used for that. While you can still use it, version 2.23 of Git added the switch command (as well as the restore command) in an attempt to have more specific commands for some of the many tasks the checkout command is used for.&lt;/p&gt;

&lt;h3 id=&quot;how-do-i-use-git-checkout&quot;&gt;How Do I Use Git Checkout?&lt;/h3&gt;

&lt;p&gt;The older, more well-know way of switching branches in Git is by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; command. Following our example, if we wanted to change to the “example” branch, we’d just have to run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After executing the command, you should see a message saying that you’ve successfully switched to the example branch:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img4.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now you’re in the new branch, that means you can add how many commits you want, knowing that the master branch won’t be impacted. The checkout command, followed by a branch name, updates the working tree and the index, and it updates the HEAD reference, pointing it to the branch you’ve just checked out. What if you had uncommitted changes at the moment of switching? Those would be kept to allow you to commit them to the new branch.&lt;/p&gt;

&lt;p&gt;Git allows you to use the checkout command in different ways. For instance, an incredibly common scenario is to create a branch and immediately switch to it. In fact, I’d argue that creating a branch and &lt;em&gt;not&lt;/em&gt; changing to it on the spot is the exception rather than the rule. So, Git offers us a shortcut. Instead of creating a branch and then checking it out, you can do it in one single step using the checkout command with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-b&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;So, doing this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;is equivalent to this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch new
git checkout new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Checkout doesn’t work only with branches, though. You can also checkout commits directly. Why would you want to do so?&lt;/p&gt;

&lt;p&gt;Well, taking a look at how the project was some amount of time ago is often useful, particularly for testing purposes. But there’s more. Checking out a commit puts your repository in a state called &lt;a href=&quot;/en/git-detached-head&quot;&gt;“detached HEAD”&lt;/a&gt; which allows you to create experimental changes, adding commits that you can then choose to keep or throw away.&lt;/p&gt;

&lt;h3 id=&quot;what-is-git-switch&quot;&gt;What Is Git Switch?&lt;/h3&gt;

&lt;p&gt;For the most part of Git’s lifetime, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; command was the only one you’d use for switching branches. The problem is that this command also does other things, &lt;a href=&quot;https://redfin.engineering/two-commits-that-wrecked-the-user-experience-of-git-f0075b77eab1&quot;&gt;which can lead to confusion, especially among new users&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The 2.23.0 version of Git solves this by adding two new commands: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;restore.&lt;/code&gt; The restore command isn’t relevant for us today. The switch command, on the other hand, is a new way to switch to branches.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://git-scm.com/docs/git-switch&quot;&gt;manual page for the command&lt;/a&gt; lists all of its many options. On its most basic form, you use it the same way as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;, only swapping the command’s name:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you want to go back to the previous branch, you can use a shortcut instead of its full name:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What if you want to create a new branch and immediately switch to it? With checkout, we could use this shortcut:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; &amp;lt;branch-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The new command also offers a shortcut, but in this case, we use the letter “C”:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git switch &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &amp;lt;branch-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Is using the new command worth it? Well, I’ll probably keep using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;, as long as they don’t change it, mainly because of muscle memory. But when teaching Git to beginners? Then I’ll definitely use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; command. It has a name that’s more closely related to the task it does and, therefore, it’s more memorable.&lt;/p&gt;

&lt;h3 id=&quot;how-do-i-switch-to-a-remote-branch&quot;&gt;How Do I Switch to a Remote Branch?&lt;/h3&gt;

&lt;p&gt;Before wrapping up, we share a final tip: how to switch to remote branches?&lt;/p&gt;

&lt;p&gt;For this example, we’re going to use an open-source project called &lt;a href=&quot;https://github.com/nodatime/nodatime&quot;&gt;Noda Time,&lt;/a&gt; which is an alternative date and time API for .NET. Start by cloning the repository:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/nodatime/nodatime.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If everything worked fine, you should have a “nodatime” folder now. Enter the folder and run the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;branch&lt;/code&gt; command lists the branches in your repository. The “-a” option means you want to see all branches, not only local ones. The result should look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-switch-branch/img5.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, we have only one local branch, which is the master branch. You can see, in red, all of the remote branches. So, let’s say you want to check out the branch called “slow-test.” How would you go about that?&lt;/p&gt;

&lt;p&gt;Well, technically speaking, Git doesn’t allow you to work on other people’s branches. And that’s what remote branches are. What you actually do is to create a local “copy” of someone else’s branch to work on. So, let’s see how to do it.&lt;/p&gt;

&lt;p&gt;When you create a branch, you can pass a commit or branch name as a parameter. So, in order to create a local branch from the remote “slow-test” branch, I’d just have to do:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch slow-test origin/slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the example, I’m using “slow-test” as the name for my local branch, but I could’ve really used any other valid name.&lt;/p&gt;

&lt;p&gt;Alternatively, I could’ve used the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; command with the -b option or the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;switch&lt;/code&gt; command with the -c option. So, the two following lines are equivalent to the line above:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; slow-test origin/slow-test
git switch &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; slow-test origin/slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, there’s an even easier way. I could’ve just used:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git checkout slow-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and the result would have been the same. That works because when you try to check out a branch and Git doesn’t find a branch with that name, it tries to match it with a remote branch from one of your remotes. If it can successfully match it, things just work.&lt;/p&gt;

&lt;h2 id=&quot;git-branches-use-in-moderation&quot;&gt;Git Branches: Use in Moderation&lt;/h2&gt;

&lt;p&gt;In this post, we’ve shown you how to switch branches in Git. But we went further than that: we’ve explained what branches are and how they work. Hopefully, by now, you’re more comfortable creating and using branches in Git.&lt;/p&gt;

&lt;p&gt;Before we go, a final caveat: just because you can do something, it doesn’t mean you should. Sometimes people get so carried away with the ease of branching in Git they end up using &lt;a href=&quot;https://rollout.io/blog/pitfalls-feature-branching/&quot;&gt;workflows that rely on a number of long-lived branches&lt;/a&gt;, which makes their development process way too complex and error-prone and delays integration.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and until next time.&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/git-switch-branch</link>
        <guid isPermaLink="true">https://carlosschults.net/en/git-switch-branch</guid>
        
        <category>git</category>
        
        <category>tutorial</category>
        
        
      </item>
    
      <item>
        <title>Type-Safe C#: How GenAI Makes Tiny-Types Worth It</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1466341001/csharp-min_buiizq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s weird how our memory works, right? I can’t quite remember what I had for dinner two nights ago, or the reason why I failed to attend the gym some days last week.
But I do remember vividly a specific bug that I fixed in my first programming job after graduating from college.&lt;/p&gt;

&lt;p&gt;There was this method that wasn’t working properly, and its signature was something like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessOrder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I’ve reviewed its code and couldn’t find anything wrong with it. But when I started debugging, I realized that the calling site was passing the arguments in the wrong order—that is, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;customerId&lt;/code&gt; first and then &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;orderId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Mistakes like this are easy to make and hard to spot even in code review. Even testing might let it slip, since you might have the misfortune of supplying values that accidentally make the code work without blowing everything up.&lt;/p&gt;

&lt;p&gt;As it turns out, there’s a great way to prevent issues like the one I’ve just described. The problem? Most developers would think it’s too much work to bother.&lt;/p&gt;

&lt;h2 id=&quot;tiny-types-the-greatest-software-design-technique-that-nobody-uses&quot;&gt;Tiny Types: The Greatest Software Design Technique That Nobody Uses&lt;/h2&gt;

&lt;p&gt;I know, I know. I’ll be the first one to admit this title is overblown. “An Interesting Software Design Technique That Many People Don’t Use” just doesn’t pack the same punch, I’m sorry.&lt;/p&gt;

&lt;p&gt;So, what’s this “tiny types” thing about? It’s a radical solution to the primitive obsession code smell. Essentially, instead of using primitive types for domain concepts—for instance, using an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; to represent a unique identifier—you wrap them all using an extremely simple &lt;a href=&quot;/en/value-objects-tool/&quot;&gt;value object&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using tiny types, we could rewrite the method signature from before like this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ProcessOrder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;implementing-a-tiny-type&quot;&gt;Implementing a Tiny Type&lt;/h3&gt;
&lt;p&gt;What would the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; type look like?&lt;/p&gt;

&lt;p&gt;For starters, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; is supposed to wrap an int, it should get an int as parameter and store it somewhere. Let’s see:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;Value must be a positive integer!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I think the above is a good start, wouldn’t you agree? We get an int as parameter, validate and throw an exception in case of zero or negative values, and then assign it to a private readonly field, which is fitting, since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt;, as a value object, must be immutable.&lt;/p&gt;

&lt;p&gt;Do you know what else value objects—and, by consequence, tiny types—need? Structural equality. That is, when comparing them, we should only consider their values, not whether their references point to the same object.&lt;/p&gt;

&lt;p&gt;So, let’s start by overriding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Equals&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(For a more modern C# style, we could’ve used pattern matching, but I think the approach above is clearer.)&lt;/p&gt;

&lt;p&gt;I get now a compiler warning because my type overrides &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Equals&lt;/code&gt; but not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GetHashCode&lt;/code&gt;, so let’s fix that:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; is a simple type representing unique, immutable values, it should really be a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;struct&lt;/code&gt; instead of a class, according to &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/type&quot;&gt;Microsoft’s Type Design Guidelines&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Structs are the general case of value types and should be reserved for small, simple types, similar to language primitives.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But the design guidelines also say that all structs should implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IEquatable&amp;lt;T&amp;gt;&lt;/code&gt; interface, so let’s do that. While we’re at it, let’s also implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IComparable&amp;lt;T&amp;gt;&lt;/code&gt; and overload comparison operators:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEquatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;Value must be a positive integer!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There are more things we could add, such as implicit/explicit conversions, but our type is already functional as it is. For those using modern C#, we could achieve the same with a more concise syntax:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentOutOfRangeException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;s&quot;&gt;&quot;Value must be a positive integer!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;tiny-types-are-too-expensive&quot;&gt;Tiny Types Are Too Expensive&lt;/h3&gt;
&lt;p&gt;My tiny &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; type there takes 42 lines on my Visual Studio. Yes, there’s some stylistic choices involved—for one, I do not like when lines are over 80 characters of length—but even so, it’s quite some work.&lt;/p&gt;

&lt;p&gt;The more concise version, which leverages the record feature of modern C#, is shorter, but still requires a reasonable amount of code.&lt;/p&gt;

&lt;p&gt;Now imagine doing this for all ids in your application! And not only ids, of course. Imagine doing this for more types that required more complex validation/parsing:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Zip codes&lt;/li&gt;
  &lt;li&gt;License plates&lt;/li&gt;
  &lt;li&gt;Telephone numbers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so on.&lt;/p&gt;

&lt;p&gt;That’s the main reason why developers who know this technique don’t use it. Even when they like the idea and understand how it could be beneficial, they think doing all of that isn’t worth the trouble.&lt;/p&gt;

&lt;h2 id=&quot;llms-to-the-rescue&quot;&gt;LLMs To The Rescue&lt;/h2&gt;

&lt;p&gt;It’s been two years since OpenAI &lt;a href=&quot;https://openai.com/index/chatgpt/&quot;&gt;introduced ChatGPT to the world&lt;/a&gt;, and I’ve been experimenting with LLMs since then. My current take on them is that their value proposition for 
experienced devs is two-fold:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;They act as a replacement for Google when learning something new&lt;/li&gt;
  &lt;li&gt;They act as a code generator for mundane stuff I’d rather not do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few months ago, I’ve become a paid subscriber of &lt;a href=&quot;https://claude.ai&quot;&gt;Claude&lt;/a&gt;. I’ve been using it mainly as an aid in a hobby project I’m working on, and I must say I’m very satisfied with the results I get, since Claude
is much better than ChatGPT for programming tasks.&lt;/p&gt;

&lt;p&gt;I went to Claude with the following prompt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Generate a type called OrderId. It should be a wrapper over an int. Don’t allow zero or negative values. Implement equality, hash code, overload comparison and equality operators.&lt;/p&gt;

  &lt;p&gt;Don’t add explicit or implicit conversions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is the result I’ve got:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IEquatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Order ID must be greater than zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;!(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s a good start, but I’m not completely satisfied yet:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Can you make it a record so the implementation is more concise? Also, use expression bodied methods for the one-liners.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And now Claude gave me this:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IComparable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ArgumentException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Order ID must be greater than zero&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;operator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;CompareTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, I went to Claude and asked this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Imagine there is an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Order&lt;/code&gt; class that needs to be saved to the db. 
We use Entity Framework. How to ensure everything works since this model uses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;OrderId&lt;/code&gt; type?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And this is my response, complete with the model and the necessary EF configuration to handle our
custom type:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The Order entity&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Order&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CustomerName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;decimal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TotalAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OrderDate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Private parameterless constructor for EF&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;decimal&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;CustomerName&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;customerName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;TotalAmount&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;OrderDate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DateTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;UtcNow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Value converter for OrderId&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderIdValueConverter&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ValueConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderIdValueConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;orderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;GetHashCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Assuming this gets the underlying value&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OrderId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// DbContext configuration&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;OrderDbContext&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DbContext&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DbSet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Orders&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;OnModelCreating&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ModelBuilder&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modelBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;modelBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Entity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HasConversion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OrderIdValueConverter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ValueGeneratedOnAdd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Use database auto-increment&lt;/span&gt;
            
            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CustomerName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsRequired&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasMaxLength&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;HasPrecision&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This post had two goals. First, to present the concept of tiny types to those of you who had never heard of it. I hope you agree that, despite being a simple idea, the tiny types pattern is something that can help you write code that is more robust.&lt;/p&gt;

&lt;p&gt;Second, and more broadly, to demonstrate how LLMs can play an interesting role in fostering better software design. In the past, many software design techniques might have been dismissed as too much work to be worth it. Now, with the help of Claude, ChatGPT, or coding assistants like Copilot, we can streamline the writing of “boring” code, which makes the economics of design techniques such as the one I’ve presented in this post make more sense.&lt;/p&gt;
</description>
        <pubDate>Tue, 10 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/genai-tiny-types</link>
        <guid isPermaLink="true">https://carlosschults.net/en/genai-tiny-types</guid>
        
        <category>csharp</category>
        
        <category>ia</category>
        
        <category>boas-praticas</category>
        
        <category>modelagem-de-software</category>
        
        
      </item>
    
      <item>
        <title>Learning Mistakes to Avoid As a Software Developer</title>
        <description>&lt;p&gt;&lt;img src=&quot;/img/software-developer-learning-mistakes/cover.webp&quot; alt=&quot;&quot; /&gt;
Photo by &lt;a href=&quot;https://unsplash.com/@francisco_legarreta?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Francisco De Legarreta C.&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/a-man-with-glasses-is-looking-at-a-laptop-hHg9MC-G8_Y?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;Thanks to my friend &lt;a href=&quot;https://www.linkedin.com/in/andre-godasi/&quot;&gt;André Gonçalves da Silva&lt;/a&gt; for reading and reviewing earlier drafts of this post&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;If you work in software development, you’ve certainly heard phrases like “Never stop learning,” “You have to stay updated,” “Our field changes very quickly,” and so on.&lt;/p&gt;

&lt;p&gt;Of course, all these phrases are right, to some degree. But going around repeating “never stop learning” like a parrot isn’t the most &lt;strong&gt;useful&lt;/strong&gt; thing in terms of providing direction for your learning.&lt;/p&gt;

&lt;p&gt;What often happens in practice is that many people, having never learned how to learn properly, make many learning mistakes that compromise their professional development. These mistakes can lead to slow progress, frustration, and even career stagnation - something nobody wants to experience.&lt;/p&gt;

&lt;p&gt;That’s why, in this post, I decided to compile what I believe are the most common learning mistakes that developers generally make. This list is the result of years of personal experience, observation of fellow developers, and many conversations with people in the field. I know what I’m talking about from practical experience because many of these mistakes are things I’ve made myself.&lt;/p&gt;

&lt;p&gt;(Being honest, I still make some of them and I’m always having to check myself to stop, but don’t tell anyone. ;))&lt;/p&gt;

&lt;p&gt;Identifying and understanding these mistakes is the first step to overcoming them. By avoiding them, you can optimize your learning process, accelerate your professional growth, and stay relevant in a field that’s always evolving.&lt;/p&gt;

&lt;p&gt;So, without further ado, here’s the list of learning mistakes to avoid. For each mistake, you’ll see:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the explanation of the mistake&lt;/li&gt;
  &lt;li&gt;the problem it causes&lt;/li&gt;
  &lt;li&gt;how to fix it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go!&lt;/p&gt;

&lt;h2 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#thinking-that-content-consumption--learning&quot;&gt;Thinking That Content Consumption == Learning&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#not-applying-the-content-from-learning-resources&quot;&gt;Not Applying the Content from Learning Resources&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#lack-of-focus&quot;&gt;Lack of Focus&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#lack-of-consistency&quot;&gt;Lack of Consistency&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#underestimating-the-importance-of-fundamentals&quot;&gt;Underestimating the Importance of Fundamentals&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#living-under-a-rock-not-keeping-up-with-whats-happening&quot;&gt;Living Under a Rock (Not Keeping Up with What’s Happening)&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#conclusion&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;thinking-that-content-consumption--learning&quot;&gt;Thinking That Content Consumption == Learning&lt;/h2&gt;

&lt;p&gt;I started the list with what I believe to be the most common learning mistake currently, simply because we live in an era where content is produced in massive quantities.&lt;/p&gt;

&lt;h3 id=&quot;why-do-we-fall-into-this-trap&quot;&gt;Why Do We Fall Into This Trap?&lt;/h3&gt;

&lt;p&gt;Consuming content is &lt;strong&gt;easy, convenient, and (potentially) fun.&lt;/strong&gt; Let’s understand why:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Easy: It’s passive, you don’t have to think much or make decisions, and humans tend to seek the path of least resistance.&lt;/li&gt;
  &lt;li&gt;Convenient: You can usually consume content while doing other things:
    &lt;ul&gt;
      &lt;li&gt;Listen to a podcast while exercising or washing dishes&lt;/li&gt;
      &lt;li&gt;Watch a video while eating lunch&lt;/li&gt;
      &lt;li&gt;Read posts on Reddit while waiting in line at the bank&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Fun: Many creators realize that to engage their audience, they need to add entertainment value and transform the content into a performance that holds attention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There you have it - the trap is set. Then you go ahead and create a strategy to fill every free moment of your day with podcasts, YouTube videos, blog posts, Reddit, and whatever else.&lt;/p&gt;

&lt;h3 id=&quot;the-consequences-of-this-mistake&quot;&gt;The Consequences of This Mistake&lt;/h3&gt;

&lt;p&gt;In the end, you will have:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Consumed your time with superficial information&lt;/li&gt;
  &lt;li&gt;Retained almost nothing of what you consumed&lt;/li&gt;
  &lt;li&gt;A vague feeling that you “learned” something&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But when it comes to applying this meaningfully in your daily life? That’s where things don’t add up.&lt;/p&gt;

&lt;p&gt;Long-term, the consequences can be even more serious:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Professional stagnation, as you’re not really developing new skills&lt;/li&gt;
  &lt;li&gt;Frustration when realizing you’re not progressing as expected&lt;/li&gt;
  &lt;li&gt;Possible burnout from constantly trying to “keep up” with everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To be clear: the mistake here isn’t “consuming content.” It’s thinking that just mindlessly consuming content is enough for you to evolve as a professional.&lt;/p&gt;

&lt;h3 id=&quot;how-to-fix-this-mistake&quot;&gt;How to Fix This Mistake&lt;/h3&gt;

&lt;p&gt;The solution is simple in theory, which doesn’t necessarily mean it’s easy. Here it is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decrease the portion of your learning time spent on passive content consumption, and increase the portion spent on practical learning, especially personal projects.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here are some suggestions:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Create or contribute to an open-source project&lt;/li&gt;
  &lt;li&gt;Make a website or application for a nonprofit, charitable organization, or your church&lt;/li&gt;
  &lt;li&gt;Solve a problem that you or a family member has by creating a simple automation&lt;/li&gt;
  &lt;li&gt;Reinvent the wheel: &lt;a href=&quot;https://github.com/codecrafters-io/build-your-own-x&quot;&gt;Implement a known technology or tool&lt;/a&gt; (examples: git, Docker, an HTTP server) simply with the goal of learning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list above isn’t exhaustive but serves just to start inspiring you. Five minutes of Google or ChatGPT will yield many ideas for cool projects to do.&lt;/p&gt;

&lt;h2 id=&quot;not-applying-the-content-from-learning-resources&quot;&gt;Not Applying the Content from Learning Resources&lt;/h2&gt;

&lt;p&gt;If you buy a book and don’t read it, you’re wasting money. If you buy the book, read it, and the learning doesn’t impact how you do your work, then you’re wasting both your money and your time!&lt;/p&gt;

&lt;p&gt;The same applies to courses, tutorials, and other learning resources. Being a software developer is a practical profession; how do you expect to benefit from what you’ve learned if you don’t put it into practice?&lt;/p&gt;

&lt;p&gt;Before anyone complains: yes, of course there are books, videos, etc., whose content doesn’t have a direct practical application. Maybe you read &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Mythical_Man-Month&quot;&gt;The Mythical Man-Month&lt;/a&gt; to get some insights and learn about software development history, but that doesn’t necessarily change how you write code. And that’s fine, these cases exist – use your common sense.&lt;/p&gt;

&lt;p&gt;How does mistake #2 differ from the previous one?&lt;/p&gt;

&lt;p&gt;We can summarize the first mistake as “spending 100% of your learning time consuming content.” In other words, you don’t do anything beyond consuming things.&lt;/p&gt;

&lt;p&gt;This mistake here is along the lines of “not applying what you learn from the content watched.”&lt;/p&gt;

&lt;p&gt;In other words, it’s possible to make the second mistake without making the first one. For example, you might dedicate 60% of your learning time to creating personal projects and 40% to content consumption. But if you still don’t apply in any way the content you learned in those 40% of the time, you’ll have made mistake #2. Is that clear?&lt;/p&gt;

&lt;h3 id=&quot;reason-for-this-mistake&quot;&gt;Reason for This Mistake&lt;/h3&gt;

&lt;p&gt;Why do so many people (including yours truly) make this mistake? Probably what happens here is a certain psychological pressure that many of us feel, in terms of hitting numbers. How many people do you know who create goals like this?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Read x technical books per year&lt;/li&gt;
  &lt;li&gt;Complete y courses by the second semester&lt;/li&gt;
  &lt;li&gt;etc…&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you really feel like achieving this type of goal, there’s no way around it: you need to “spend” as little time as possible with each piece of content. Otherwise, the math doesn’t work.&lt;/p&gt;

&lt;h3 id=&quot;problems-caused-by-this-mistake&quot;&gt;Problems Caused By This Mistake&lt;/h3&gt;

&lt;p&gt;A serious consequence you might suffer from this mistake is lack of motivation. You read all the famous books in the field that were recommended to you, completed all the courses in your &lt;a href=&quot;https://www.indeed.com/hire/c/info/individual-development-plan-examples&quot;&gt;IDP&lt;/a&gt;, and it seems like nothing changed. It’s hard to stay motivated to persist in learning when it feels like none of it has real impact on how you work.&lt;/p&gt;

&lt;p&gt;That’s the frustration with lack of career evolution that we mentioned in the previous mistake. Another serious consequence of this mistake is the waste of time, money, and energy itself: learning is an investment that needs to have a return to be justified.&lt;/p&gt;

&lt;h3 id=&quot;whats-the-solution&quot;&gt;What’s the Solution?&lt;/h3&gt;

&lt;p&gt;The remedy for this mistake has two steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Prioritize quality over quantity&lt;/li&gt;
  &lt;li&gt;Constantly apply what you learned&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, here’s my practical suggestion: &lt;strong&gt;only start another course/book/etc. after you’ve applied the learning from the previous one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, let’s say you’re taking a Udemy course. After each lesson or section, stop and create a small project where you exercise what you just learned. It doesn’t need to be a big project, or even useful. Preferably, throw it away after you finish: the important thing is the practice.&lt;/p&gt;

&lt;p&gt;Here are some more examples:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;After watching a programming tutorial, dedicate time to replicate the project on your own, without looking at the video&lt;/li&gt;
  &lt;li&gt;Read an article about a new refactoring technique? Apply it to a personal project or at work&lt;/li&gt;
  &lt;li&gt;Heard a podcast about code best practices? Review an old project and see where you can apply these practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Regarding technical books, I recently created a rule for myself: when I finish a book, I can only start another one after I’ve applied the content of the book I just finished. This application can take different forms:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;do the book’s exercises, if it has any&lt;/li&gt;
  &lt;li&gt;create one or more projects to exercise that content&lt;/li&gt;
  &lt;li&gt;propose/implement a new practice at work based on what I learned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the end, that’s what matters: that you find a way to apply the learned content to improve your professional life. A stack of books whose content didn’t impact you only serves to collect dust or as a monitor stand.&lt;/p&gt;

&lt;h2 id=&quot;lack-of-focus&quot;&gt;Lack of Focus&lt;/h2&gt;

&lt;p&gt;There are many more “learnable” things than you have time or energy to learn. You’ll never know everything, and you’ll never clear your learning queue. This is a fact and you need to accept and embrace this fact, unless you’re really in the mood for burnout.&lt;/p&gt;

&lt;p&gt;Unfortunately, we feel the pressure to “always be studying,” even though that phrase itself isn’t helpful—it offers no guidance about &lt;em&gt;what&lt;/em&gt; to study, or what strategies to use.&lt;/p&gt;

&lt;p&gt;It’s common for this pressure to come from our own companies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Read book x!&lt;/li&gt;
  &lt;li&gt;Take this course!&lt;/li&gt;
  &lt;li&gt;Complete this learning path!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And these people are well-intentioned, but that doesn’t change the fact that you have a limited amount of time in your day and, more importantly, a limited amount of energy in the time you have available.&lt;/p&gt;

&lt;p&gt;But then you give in to the pressure and end up making the mistake of this item: jumping from course to course, book to book, tutorial to tutorial, without ever completing anything, or at least achieving any significant progress.&lt;/p&gt;

&lt;h3 id=&quot;a-disclaimer&quot;&gt;A Disclaimer&lt;/h3&gt;

&lt;p&gt;Look: I know that in day-to-day work, it’s very common to encounter a huge number of different problems that need to be solved, and the deadline is always yesterday. In these situations, often the right thing is indeed to learn just the surface level of a topic to be able to handle the demand and generate value for the user as quickly as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ability to distinguish when it’s time to invest in a certain item more deeply and when surface knowledge is enough&lt;/strong&gt; is something that’s extremely valuable for any professional’s career, and the only way to perfect this ability is through practice.&lt;/p&gt;

&lt;p&gt;The mistake I point out in this item is a different situation from the above scenario. More specifically, the mistake is about trying to learn many things at the same time, in depth, with dense resources.&lt;/p&gt;

&lt;h3 id=&quot;problems-caused-by-this-mistake-1&quot;&gt;Problems Caused By This Mistake&lt;/h3&gt;

&lt;p&gt;The main problem caused by lack of focus is that you never go deep into anything. You end up with a vague impression of knowledge in a million things, but when a critical situation arises where deep knowledge would be necessary, you don’t have anything to show.&lt;/p&gt;

&lt;p&gt;As I’ve said before, it’s impossible to go deep into everything. But you should, indeed, go deep into the things that matter most, those that generate the most value for your career. I’m referring to those fundamentals that many people talk about, but I’ll talk more about that in another topic.&lt;/p&gt;

&lt;h3 id=&quot;how-to-fix-it&quot;&gt;How to Fix It&lt;/h3&gt;

&lt;p&gt;This mistake might be the hardest to fix, because the solution involves a high dose of self-knowledge and a very strong sense of prioritization.&lt;/p&gt;

&lt;p&gt;In general, the tip is: &lt;strong&gt;define ONE point of evolution for your career, and focus on it for a considerable time, until you evaluate that you’ve made progress.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Some examples of improvement points:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Improve my knowledge of parallelism, concurrency, and performance&lt;/li&gt;
  &lt;li&gt;Learn the main design patterns and know how to apply them in real projects&lt;/li&gt;
  &lt;li&gt;Acquire advanced SQL skills&lt;/li&gt;
  &lt;li&gt;Learn a new language and reach a productive level&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s not easy to identify this point of improvement, but here are some tips:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ask for feedback from managers and colleagues.&lt;/li&gt;
  &lt;li&gt;Talk to a technical mentor you trust.&lt;/li&gt;
  &lt;li&gt;If you’re actively participating in job interviews and failing, analyze the points where you did poorly in the interviews to identify where to improve.&lt;/li&gt;
  &lt;li&gt;If you’re not actively looking, pretend you are. Ask a friend or mentor to do a mock interview with you, and then ask for honest feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;lack-of-consistency&quot;&gt;Lack of Consistency&lt;/h2&gt;

&lt;p&gt;What’s better, dedicating 30 minutes per day to learning, every day, or 5 hours on the weekend, once every three months? The answer is obvious.&lt;/p&gt;

&lt;p&gt;Our profession is practical, deliberate and consistent practice is necessary for you to internalize the things you learn and know how to use them when the time comes.&lt;/p&gt;

&lt;h3 id=&quot;consequences&quot;&gt;Consequences&lt;/h3&gt;

&lt;p&gt;The consequences here are pretty obvious, right? There’s simply no way to make progress if you don’t make consistent effort. This actually applies to pretty much anything in life: physical activity, language learning, playing an instrument, and so on.&lt;/p&gt;

&lt;p&gt;If you invest, for example, 1 hour per week to learn something, that gives a total of about 51 hours in the year. Now, if you learn 15 minutes every day, that gives a total of 5,475 minutes in the year, &lt;strong&gt;which is more than 91 hours&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Studying just once a week has another disadvantage. If something unexpected comes up and you need to miss it, when you return two weeks will have passed. This way, it becomes complicated to keep the momentum going; you need to remember where you stopped 14 days ago, and regaining the lost context isn’t easy at all.&lt;/p&gt;

&lt;h3 id=&quot;how-to-fix-it-1&quot;&gt;How to Fix It&lt;/h3&gt;

&lt;p&gt;Solving this mistake requires thinking about strategies to make learning become a natural part of your daily routine.&lt;/p&gt;

&lt;p&gt;To start, define &lt;strong&gt;duration&lt;/strong&gt;: that is, how much time you’ll dedicate daily, in a &lt;em&gt;realistic&lt;/em&gt; way. There’s no point in committing to 2 hours of daily learning if your routine simply doesn’t allow it.&lt;/p&gt;

&lt;p&gt;Another essential thing is choosing the &lt;strong&gt;time&lt;/strong&gt; of your learning period. To really establish the habit, ideally it would be at the same time every day. When choosing this time, take into consideration how your energy levels change throughout the day. Are you a morning person? Put your learning time in the morning. If not, at night.&lt;/p&gt;

&lt;p&gt;I’ll give an example of what works for me. I know that if I leave my learning time for after work, I’ll be too tired and probably won’t do it. So, for me, the best is to reserve about 50 minutes before work for learning.&lt;/p&gt;

&lt;p&gt;To make learning a habit, the key is to integrate it into your routine and reduce friction. You know those people who sleep in their gym clothes? Same idea for studying. Leave your PC on with VS Code open in your project, or configure the browser to open directly to the Udemy course. The easier it is to start, the better.&lt;/p&gt;

&lt;p&gt;It’s also interesting that the time to decide what to learn and the time to learn be distinct moments. If you have 50 minutes per day for learning, but spend 20 of those minutes every day deciding what to read/practice/watch, you’re wasting 40% of your time.&lt;/p&gt;

&lt;p&gt;So here’s the tip: on Saturday, define your learning routine for the following week. You can create a spreadsheet defining the days and what you’ll do, or create a board in &lt;a href=&quot;https://trello.com/&quot;&gt;Trello&lt;/a&gt;, or even use paper and pen, it doesn’t matter. What’s important is that you have this defined beforehand. Then, during the weekdays, you simply check and follow the planning made.&lt;/p&gt;

&lt;p&gt;Finally, something that works for many people is making some kind of public commitment. You declare, publicly—for example, on your LinkedIn—that you’ll study without missing for x days. The simple fact of having made this commitment often helps people maintain the routine without missing.&lt;/p&gt;

&lt;p&gt;A cool initiative in this sense is &lt;a href=&quot;https://www.100daysofcode.com/&quot;&gt;100 Days of Code&lt;/a&gt;, which encourages people to code for 100 consecutive days, without fail, interacting with other participants in the process.&lt;/p&gt;

&lt;h2 id=&quot;underestimating-the-importance-of-fundamentals&quot;&gt;Underestimating the Importance of Fundamentals&lt;/h2&gt;

&lt;p&gt;Many people underestimate the importance of learning computer science fundamentals. Yes, I’m talking about those boring things you didn’t like studying in college: algorithms and data structures, computer theory, algorithm complexity, and so on.&lt;/p&gt;

&lt;p&gt;These people argue that you don’t need to know all these things to make your code work. Yes, this might be true most of the time, but not always.&lt;/p&gt;

&lt;p&gt;We can think of computing as several layers that abstract the previous layer. When you’re working in one layer, you usually don’t need to worry about the others. This is a good thing, and it’s literally the reason why we use abstractions: to “hide” things that aren’t essential, reducing the complexity of what you need to deal with.&lt;/p&gt;

&lt;h3 id=&quot;consequences-1&quot;&gt;Consequences&lt;/h3&gt;

&lt;p&gt;Unfortunately, abstractions aren’t perfect. As Joel Spolsky warned us more than 20 years ago, &lt;a href=&quot;https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/&quot;&gt;abstractions eventually leak&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In other words: just because you use an ORM doesn’t mean you don’t have to know SQL. Even those who use a managed language like C# or Java can benefit from having an understanding of memory management: at minimum, you’ll be able to write code that uses lifetimes correctly, doesn’t create unnecessary allocations, and puts pressure on the garbage collector.&lt;/p&gt;

&lt;p&gt;Lack of understanding of algorithm complexity can bring down a system. You test your code locally with a few hundred values, but when it goes live and has to deal with millions of items, it simply can’t handle it.&lt;/p&gt;

&lt;p&gt;In summary: you can make something that “works” without knowledge of fundamentals. However, it works in some scenarios, some of the time, with unacceptable performance, and without taking edge cases into account.&lt;/p&gt;

&lt;p&gt;Beyond the problems that lack of a solid foundation can cause in the systems you work on, this mistake can bring another very serious consequence for your career.&lt;/p&gt;

&lt;p&gt;Yes, I’m talking about not being able to pass companies’ hiring processes. It’s very common for companies to use technical challenges that require good knowledge in topics like algorithms, data structures, complexity, concurrency and parallelism, the memory model of your preferred language, among others.&lt;/p&gt;

&lt;p&gt;Not having this knowledge means being summarily rejected in these processes.&lt;/p&gt;

&lt;h3 id=&quot;solution&quot;&gt;Solution&lt;/h3&gt;

&lt;p&gt;If you don’t have a college degree, I strongly recommend studying Computer Science. If you’ve already finished college but forgot all those topics, try to remember/reinforce these concepts.&lt;/p&gt;

&lt;p&gt;On the internet, you can find plenty of content about Computer Science. For example, the &lt;a href=&quot;https://github.com/Clemensss/TeachYourselfCS-PT/blob/master/TeachYourselfCS-PT.md&quot;&gt;Teach Yourself Computer Science&lt;/a&gt; project has a roadmap of topics to learn, with bibliography and video lectures from renowned universities.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://neetcode.io/roadmap&quot;&gt;NeetCode&lt;/a&gt; is a site that provides a roadmap for studying algorithms and data structures. It also offers courses and the ability to practice real questions used in job interviews.&lt;/p&gt;

&lt;h2 id=&quot;living-under-a-rock-not-keeping-up-with-whats-happening&quot;&gt;Living Under a Rock (Not Keeping Up with What’s Happening)&lt;/h2&gt;

&lt;p&gt;I thought it would be interesting if the last mistake was exactly the opposite of the first. While the error that opens the list was “just consuming content and thinking you’re learning,” this one is “never consuming any content at all.”&lt;/p&gt;

&lt;h3 id=&quot;why-is-this-a-problem&quot;&gt;Why Is This a Problem?&lt;/h3&gt;

&lt;p&gt;We work in a field that changes constantly, and increasingly quickly. Not staying updated can lead to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Obsolescence of your skills&lt;/li&gt;
  &lt;li&gt;Loss of career opportunities&lt;/li&gt;
  &lt;li&gt;Difficulty in solving problems using more efficient approaches&lt;/li&gt;
  &lt;li&gt;Lack of inspiration for innovation in your daily work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words: lack of updating hurts your performance in your current job, and at the same time reduces your chances of getting a potential new job. That’s not what you want, right?&lt;/p&gt;

&lt;h3 id=&quot;finding-the-balance&quot;&gt;Finding the Balance&lt;/h3&gt;

&lt;p&gt;On one hand, using every free second to consume every possible podcast/article/video isn’t a good strategy. It’s like eating lots of junk food: you’ll feel full, but that food won’t bring the benefits your body needs.&lt;/p&gt;

&lt;p&gt;But on the other hand, consuming &lt;em&gt;no&lt;/em&gt; content is equally bad. As a developer, it’s extremely important that you have at least a notion of what’s happening in the software development world.&lt;/p&gt;

&lt;h3 id=&quot;what-to-keep-on-your-radar&quot;&gt;What to Keep on Your Radar&lt;/h3&gt;

&lt;p&gt;Here’s a small list of things that would be interesting to keep on your radar:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Release of technical books about topics you’re interested in, or from authors you already follow&lt;/li&gt;
  &lt;li&gt;New features in the latest version of your main language or framework&lt;/li&gt;
  &lt;li&gt;Tools or techniques that can make your life easier&lt;/li&gt;
  &lt;li&gt;Emerging industry trends (for example, AI)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;where-to-find-relevant-content&quot;&gt;Where to Find Relevant Content&lt;/h3&gt;

&lt;p&gt;There are many valuable sources of information for developers. Here are some suggestions:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Reddit&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://old.reddit.com/r/programming&quot;&gt;r/programming&lt;/a&gt; for a general overview&lt;/li&gt;
      &lt;li&gt;Specific subreddits like &lt;a href=&quot;https://old.reddit.com/r/csharp&quot;&gt;r/csharp&lt;/a&gt;, &lt;a href=&quot;https://old.reddit.com/r/java&quot;&gt;r/java&lt;/a&gt;, &lt;a href=&quot;https://old.reddit.com/r/golang&quot;&gt;r/golang&lt;/a&gt;, etc.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Hacker News&lt;/strong&gt;: Excellent for news and discussions about technology in general&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;YouTube&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;Search for channels related to your specific interests&lt;/li&gt;
      &lt;li&gt;Watch technology conference talks&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Technical Blogs&lt;/strong&gt;:
    &lt;ul&gt;
      &lt;li&gt;From technology companies (for example, engineering blogs from &lt;a href=&quot;https://netflixtechblog.com/&quot;&gt;Netflix&lt;/a&gt;, &lt;a href=&quot;https://engineering.atspotify.com/&quot;&gt;Spotify&lt;/a&gt;, etc.)&lt;/li&gt;
      &lt;li&gt;From influential developers in your area&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Technology Podcasts&lt;/strong&gt;: Great for consuming information while doing other activities&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We’ve reached the end of the list. I hope this compilation of learning mistakes you just read is useful for your career. With this list I covered what not to do, but what should you do then?&lt;/p&gt;

&lt;p&gt;Maybe in the future I’ll write a post just about that: how to learn the right way, and what to focus on. Leave a comment if you’re interested in something like that.&lt;/p&gt;

&lt;p&gt;But, for now, to know what to do, just imagine a learning strategy that’s the opposite of the mistakes above:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Learn with &lt;strong&gt;consistency&lt;/strong&gt;, preferably a little every day&lt;/li&gt;
  &lt;li&gt;Have &lt;strong&gt;focus&lt;/strong&gt;: prioritize one main improvement point at a time&lt;/li&gt;
  &lt;li&gt;Prefer &lt;strong&gt;project-based learning&lt;/strong&gt;, supplemented in part by content consumption&lt;/li&gt;
  &lt;li&gt;When consuming content, always &lt;strong&gt;apply what you learned&lt;/strong&gt; in some practical way&lt;/li&gt;
  &lt;li&gt;Learning about tools is important, but having &lt;strong&gt;solid fundamentals&lt;/strong&gt; is more important&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now comes the most important tip I can leave you with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Done is better than perfect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Skipped a day of learning? No big deal, continue the next day. Dedicated 30 minutes to your project instead of the planned 50? That’s still infinitely better than having done nothing.&lt;/p&gt;

&lt;p&gt;Trends are more important than data points. Going in the right direction is more significant than arbitrary goals like “I’ll read 6 technical books in 2024.”&lt;/p&gt;

&lt;p&gt;It’s difficult to deal with the constant development pressure we feel in this field, I know that well. As much as possible, try to relax. Don’t be too hard on yourself. You’re going in the right direction.&lt;/p&gt;

&lt;p&gt;Just the fact that you’ve read to the end of a post of almost 4,000 words shows that you’re much more interested in your development than most. For that, I thank you very much. If you need help, don’t hesitate to &lt;a href=&quot;https://carlosschults.net/sobre/&quot;&gt;get in touch.&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/learning-mistakes</link>
        <guid isPermaLink="true">https://carlosschults.net/en/learning-mistakes</guid>
        
        <category>opinion</category>
        
        <category>carreer</category>
        
        
      </item>
    
      <item>
        <title>Git Detached Head: What This Means and How to Recover</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1673926044/git-beautiful-history/git-beautiful-history-cover.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;callout callout-info&quot;&gt;
  &lt;div class=&quot;callout-title&quot;&gt;
    &lt;span class=&quot;callout-icon&quot;&gt;ℹ️&lt;/span&gt;
    Info
  &lt;/div&gt;
  &lt;div class=&quot;callout-content&quot;&gt;
    
&lt;p&gt;&lt;em&gt;Editorial note: I originally wrote this post for the Cloudbees blog.  You can &lt;a href=&quot;https://www.cloudbees.com/blog/git-detached-head&quot;&gt;check out the original here, at their site&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

  &lt;/div&gt;
&lt;/div&gt;

&lt;h1 id=&quot;table-of-contents&quot;&gt;Table of Contents&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;#introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#git-detached-head-reproducing-the-problem&quot;&gt;Reproducing the “Problem”&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#what-is-a-head-in-git&quot;&gt;What Is a HEAD in Git?&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#are-you-in-detached-head-state&quot;&gt;Are you in ‘detached HEAD’ state?&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#benefits-of-a-git-detached-head&quot;&gt;Benefits of a Git Detached HEAD&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#how-do-i-fix-a-detached-head-in-git&quot;&gt;How Do I Fix a Detached HEAD in Git?&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#scenario-1-im-here-by-accident&quot;&gt;Scenario #1: I’m Here by Accident&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#scenario-2-ive-made-experimental-changes-and-i-want-to-discard-them&quot;&gt;Scenario #2: I’ve Made Experimental Changes and I Want to Discard Them&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#scenario-3-ive-made-experimental-changes-and-i-want-to-keep-them&quot;&gt;Scenario #3: I’ve Made Experimental Changes and I Want to Keep Them&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#getting-rid-of-the-git-detached-head-message&quot;&gt;Getting Rid of the “Git Detached HEAD” Message&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#git-detached-head-less-scary-than-it-sounds&quot;&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Newcomers to Git often get confused with some of the messages that the &lt;a href=&quot;https://www.atlassian.com/git/tutorials/what-is-version-control&quot;&gt;VCS tool&lt;/a&gt; throws at them. The “You are in ‘detached HEAD’ state” one is certainly one of the weirdest. After coming across this message, most people start furiously Googling “git detached HEAD,” “git detached HEAD fix,” or similar terms, looking for anything that might be of help. If that’s your case, you’ve come to the right place.&lt;/p&gt;

&lt;p&gt;Here’s the first thing you should know: &lt;em&gt;you haven’t done anything wrong&lt;/em&gt;. Your repo isn’t broken or anything like that. The expression “Detached HEAD” might sound somewhat bizarre, but it’s a perfectly valid repository state in Git. Sure, it’s not the &lt;em&gt;normal&lt;/em&gt; state, which would be—you’ve guessed it!—when HEAD is attached. The second thing you need to know is that going back to normal is super easy. If you just want to do that and get on with your day, go to the &lt;a href=&quot;#how-do-i-fix-a-detached-head-in-git&quot;&gt;“How Do I Fix a Detached Head in Git?”&lt;/a&gt; section of this post to see how it’s done.&lt;/p&gt;

&lt;p&gt;But if you want to know more—and I guess you do—stick around and we’ll help you. What does HEAD mean in Git? What does it mean for it to be attached or detached? These are the kind of questions we’ll answer in this post. By the end of it, you’ll have a better understanding of Git’s fundamentals, and detached HEADs will never trouble you again. Let’s dig in.&lt;/p&gt;

&lt;h2 id=&quot;git-detached-head-reproducing-the-problem&quot;&gt;Git Detached HEAD: Reproducing the “Problem”&lt;/h2&gt;

&lt;p&gt;Let’s start with a quick demo showing how to reach the detached HEAD state. We’ll create a repository and add some commits to it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;git-head-demo
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;git-head-demo 
git init
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;file.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello World!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file.txt
git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Add line to the file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Second file&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; file2.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create second file&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With the commands above, we’ve created a new folder with a new repository inside it. Then we created a new empty file and committed that with the message “Create file.” Next, we added a line to that file and committed the change, with the message “Add a line to the file.” Finally, we’ve created another file with one line of text and committed that as well. If you use the &lt;strong&gt;git log –oneline&lt;/strong&gt; command, you’ll see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/git-detached-head/image3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s say that, for testing purposes, we need to see how things were at the time of the second commit. How would we do that? As it turns out, we can check out a commit the same way we’d check out branches. Remember, branches are just names for commits. So, based on the example output above, we’d run &lt;strong&gt;git checkout 87ec91d&lt;/strong&gt;. Keep in mind that if you’re following along by executing these commands on your own system, the hash for your commits will be different from those in the example. Use the log command to find it.&lt;/p&gt;

&lt;p&gt;After running the command, we get the “You are in ‘detached HEAD’ state[…]” message. Before we go on, make sure you keep this in mind: you get to the detached HEAD state by checking out a commit directly.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-head-in-git&quot;&gt;What Is a HEAD in Git?&lt;/h2&gt;

&lt;p&gt;What does HEAD mean in Git? To understand that, we have to take a step back and talk fundamentals.&lt;/p&gt;

&lt;p&gt;A Git repository is a collection of &lt;strong&gt;objects&lt;/strong&gt; and &lt;strong&gt;references&lt;/strong&gt;. Objects have relationships with each other, and references point to objects and to other references. The main objects in a Git repository are commits, but other objects include &lt;a href=&quot;https://developer.github.com/v3/git/blobs/&quot;&gt;blobs&lt;/a&gt; and &lt;a href=&quot;https://developer.github.com/v3/git/trees/&quot;&gt;trees&lt;/a&gt;. The most important references in Git are &lt;a href=&quot;/en/git-create-branch&quot;&gt;branches&lt;/a&gt;, which you can think of as labels you put on a commit.&lt;/p&gt;

&lt;p&gt;HEAD is another important type of reference. The purpose of HEAD is to keep track of the current point in a Git repo. In other words, HEAD answers the question, “Where am I right now?”&lt;/p&gt;

&lt;p&gt;For instance, when you use the &lt;strong&gt;log&lt;/strong&gt; command, how does Git know which commit it should start displaying results from? HEAD provides the answer. When you create a new commit, its parent is indicated by where HEAD currently points to.&lt;/p&gt;

&lt;h3 id=&quot;are-you-in-detached-head-state&quot;&gt;Are you in ‘detached HEAD’ state?&lt;/h3&gt;

&lt;p&gt;You’ve just seen that HEAD in Git is only the name of a reference that indicates the current point in a repository. So, what does it mean for it to be attached or detached?&lt;/p&gt;

&lt;p&gt;Most of the time, HEAD points to a branch name. When you add a new commit, your branch reference is updated to point to it, but HEAD remains the same. When you change branches, HEAD is updated to point to the branch you’ve switched to. All of that means that, in these scenarios, HEAD is synonymous with “the last commit in the current branch.” This is the &lt;em&gt;normal&lt;/em&gt; state, in which HEAD is &lt;em&gt;attached&lt;/em&gt; to a branch.&lt;/p&gt;

&lt;p&gt;A visual representation of our demo repository would look like this:
&lt;img src=&quot;/img/git-detached-head/image5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, HEAD points to the master branch, which points to the last commit. Everything looks perfect. After running &lt;strong&gt;git checkout 87ec91d,&lt;/strong&gt; the repo looks like this:
&lt;img src=&quot;/img/git-detached-head/image4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is the detached HEAD state; HEAD is pointing directly to a commit instead of a branch.&lt;/p&gt;

&lt;h3 id=&quot;benefits-of-a-git-detached-head&quot;&gt;Benefits of a Git Detached HEAD&lt;/h3&gt;

&lt;p&gt;Are there good reasons for you to be in the detached HEAD state? You bet there are!&lt;/p&gt;

&lt;p&gt;As you’ve seen, you detach the HEAD by checking out a commit. That’s already useful by itself since it allows you to go to a previous point in the project’s history. Let’s say you want to check if a given bug already existed last Tuesday. You can use the &lt;strong&gt;log&lt;/strong&gt; command, filtering by date, to start the relevant commit hash. Then you can check out the commit and test the application, either by hand or by running your automated test suite.&lt;/p&gt;

&lt;p&gt;What if you could not only take a look at the past, but also change it? That’s what a detached HEAD allows you to do. Let’s review how the detached message starts:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;You are in &apos;detached HEAD&apos; state. 
You can look around, make experimental changes and commit them,
and you can discard any commits you make in this state without
impacting any branches by switching back to a branch.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this state, you can make experimental changes, effectively creating an alternate history. So, let’s create some additional commits in the detached HEAD state and see how our repo looks afterward:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Welcome to the alternate timeline, Morty!&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; new-file.txt
git add &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Create new file&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Another line&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; new-file.txt
git commit &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Add a new line to the file&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;We now have two additional commits that descend from our second commit. Let’s run &lt;strong&gt;git log –oneline&lt;/strong&gt; and see the result:
&lt;img src=&quot;/img/git-detached-head/image7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This is what the diagram looks like now:
&lt;img src=&quot;/img/git-detached-head/image6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What should you do if you want to keep those changes? And what should you do if you want to discard them? That’s what we’ll see next.&lt;/p&gt;

&lt;h2 id=&quot;how-do-i-fix-a-detached-head-in-git&quot;&gt;How Do I Fix a Detached HEAD in Git?&lt;/h2&gt;

&lt;p&gt;You can’t fix what isn’t broken. As I’ve said before, a detached HEAD is a valid state in Git. It’s not a problem. But you may still want to know how to get back to normal, and that depends on why you’re in this situation in the first place.&lt;/p&gt;

&lt;h3 id=&quot;scenario-1-im-here-by-accident&quot;&gt;Scenario #1: I’m Here by Accident&lt;/h3&gt;

&lt;p&gt;If you’ve reached the detached HEAD state by accident—that is to say, you didn’t mean to check out a commit—going back is easy. Just check out the branch you were in before:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git checkout &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you’re using Git 2.23.0 or newer, you can also use &lt;strong&gt;switch&lt;/strong&gt; instead of &lt;strong&gt;checkout&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git switch &amp;lt;branch-name&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;scenario-2-ive-made-experimental-changes-and-i-want-to-discard-them&quot;&gt;Scenario #2: I’ve Made Experimental Changes and I Want to Discard Them&lt;/h3&gt;

&lt;p&gt;You’ve entered the detached HEAD state and made a few commits. The experiment went nowhere, and you’ll no longer work on it. What do you do? You just do the same as in the previous scenario: go back to your original branch. The changes you made while in the alternate timeline won’t have any impact on your current branch.&lt;/p&gt;

&lt;h3 id=&quot;scenario-3-ive-made-experimental-changes-and-i-want-to-keep-them&quot;&gt;Scenario #3: I’ve Made Experimental Changes and I Want to Keep Them&lt;/h3&gt;

&lt;p&gt;If you want to keep changes made with a detached HEAD, just &lt;a href=&quot;https://www.cloudbees.com/blog/git-create-branch&quot;&gt;create a new branch&lt;/a&gt; and switch to it. You can create it right after arriving at a detached HEAD or after creating one or more commits. The result is the same. The only restriction is that you should do it before returning to your normal branch.&lt;/p&gt;

&lt;p&gt;Let’s do it in our demo repo:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git branch alt-history
git checkout alt-history&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Notice how the result of &lt;strong&gt;git log –oneline&lt;/strong&gt; is exactly the same as before (the only difference being the name of the branch indicated in the last commit):
&lt;img src=&quot;/img/git-detached-head/image2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We could just run &lt;strong&gt;git branch alt-history&lt;/strong&gt;, and we’d be all set. That’s the new—and final—version of our diagram:
&lt;img src=&quot;/img/git-detached-head/image1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;getting-rid-of-the-git-detached-head-message&quot;&gt;Getting Rid of the “Git Detached HEAD” Message&lt;/h2&gt;

&lt;p&gt;Before wrapping up, let’s share a final quick tip. Now that you understand everything about detached HEAD in Git and know that it’s not that big of a deal, seeing that message every time you check out a commit might become tiring. Fortunately, there’s a way to not see the warning anymore. Just run the following command:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;git config advice.detached &lt;span class=&quot;nb&quot;&gt;head false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Easy, right? You can also use the &lt;strong&gt;–global&lt;/strong&gt; modifier if you want the change to apply to every repository and not only the current one.&lt;/p&gt;

&lt;h2 id=&quot;git-detached-head-less-scary-than-it-sounds&quot;&gt;Git Detached HEAD: Less Scary Than It Sounds&lt;/h2&gt;

&lt;p&gt;A message talking about heads not being attached doesn’t sound like your routine software error message, right? Well, it’s not an error message.&lt;/p&gt;

&lt;p&gt;As you’ve seen in this post, a detached HEAD doesn’t mean something is wrong with your repo. &lt;strong&gt;Detached HEAD&lt;/strong&gt; is just a less usual state your repository can be in. Aside from not being an error, it can actually be quite useful, allowing you to run experiments that you can then choose to keep or discard.&lt;/p&gt;

&lt;p&gt;Would you like to learn more about Git? Check-out some of the following posts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/en/git-beautiful-history/&quot;&gt;Make Your Git History Look Beautiful Using Amend and Rebase&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/git-bisect-intro/&quot;&gt;Git Bisect: An Introduction To Beginners&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/en/git-create-branch&quot;&gt;Git Create Branch: 4 Ways To Do It&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</description>
        <pubDate>Mon, 16 Sep 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/git-detached-head</link>
        <guid isPermaLink="true">https://carlosschults.net/en/git-detached-head</guid>
        
        <category>git</category>
        
        <category>tutorial</category>
        
        
      </item>
    
      <item>
        <title>C# Regex: How Regular Expressions Work in C#, With Examples</title>
        <description>&lt;p&gt;&lt;img src=&quot;https://res.cloudinary.com/dz5ppacuo/image/upload/v1513817072/csharp8-1037x438_skogpz.jpg&quot; alt=&quot;&quot; /&gt;
&lt;em&gt;Editorial note: I originally wrote this post for the Stackify blog.  You can &lt;a href=&quot;https://stackify.com/c-regex-how-regular-expressions-work-in-c-with-examples/&quot;&gt;check out the original here, at their site&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Text manipulation is one of the most common tasks in programming with virtually all major programming languages usually supporting regex (regular expression) via their standard libraries. C# is no exception, so today we bring you a C# regex guide.&lt;/p&gt;

&lt;p&gt;You’ll learn what regexes are, why you’d want to use them and how to get started in a comprehensive, approachable manner. That way, you can start using regular expressions to solve real problems ASAP.&lt;/p&gt;

&lt;p&gt;Buckle up for your regex learning journey, starting now!&lt;/p&gt;

&lt;h2 id=&quot;what-is-regex&quot;&gt;What Is Regex?&lt;/h2&gt;
&lt;p&gt;A regular expression (regex) is an expression containing one or many characters that expresses a given pattern in text. If that sounds a little vague, an example will help. Consider a date in the following format:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;28-JUL-2023
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using a regex, we can express that format like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[0-9]{2}-[A-Z]{3}-[0-9]{4}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the regular expression above expresses a pattern with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;two numeric digits followed by a hyphen&lt;/li&gt;
  &lt;li&gt;three upper-case letters followed by a hyphen&lt;/li&gt;
  &lt;li&gt;four more numbers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll learn more about what each part of a regex means in a minute. For now, just bear in mind that the regex above doesn’t &lt;em&gt;know&lt;/em&gt; anything about dates. It just happens that we were able to devise a regular expression that matches the pattern or shape of the date. All of the following match with that regex, even though they’re not valid dates:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;32-ABC-7894
30-FEV-1978
00-AAA-9999
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;is-there-regex-in-c&quot;&gt;Is There Regex in C#?&lt;/h2&gt;

&lt;p&gt;Yes, of course. But that doesn’t come from the language itself. Instead, regex support comes from &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/class-library-overview&quot;&gt;.NET’s BCL (Base Class Library),&lt;/a&gt; which is essentially C#’s standard library.&lt;/p&gt;

&lt;h2 id=&quot;why-use-regex-in-c&quot;&gt;Why Use Regex In C#?&lt;/h2&gt;

&lt;p&gt;As you’ve seen, regex is something to use to express a pattern that can match a given text. &lt;/p&gt;

&lt;p&gt;In practice, all uses of regex in C# or other languages boil down to three reasons: validation, manipulation and extraction.&lt;/p&gt;

&lt;h3 id=&quot;validation&quot;&gt;Validation&lt;/h3&gt;

&lt;p&gt;An incredibly common use case for regex is data validation. For instance, let’s say you have a web form and want to ensure a certain field only accepts inputs in a specific format. How to solve that? Regex comes to the rescue.&lt;/p&gt;

&lt;h3 id=&quot;manipulation&quot;&gt;Manipulation&lt;/h3&gt;

&lt;p&gt;Sometimes you need to change information within text. Let’s go back to the previous example. Imagine for compliance reasons you need to remove all phone numbers from this body of text and replace them with the word “REDACTED.” Again, regexes would be a perfect fit for this situation.&lt;/p&gt;

&lt;p&gt;Interestingly, programming languages are not alone in using regular expressions to solve problems. Even text editors such as Notepad++ offer find-and-replace features powered by regexes.&lt;/p&gt;

&lt;h3 id=&quot;extraction&quot;&gt;Extraction&lt;/h3&gt;

&lt;p&gt;Let’s say you have considerable amounts of text. This text contains telephone numbers that you need to extract. You know the format of those numbers and the fact that they’re inside the text, but that’s the extent of your knowledge.&lt;/p&gt;

&lt;p&gt;How would you go about extracting that information? A neat C# regex would certainly come in handy in that situation.&lt;/p&gt;

&lt;h2 id=&quot;how-to-use-regex-in-c-getting-started-in-practice&quot;&gt;How to Use Regex In C#: Getting Started in Practice&lt;/h2&gt;

&lt;p&gt;C# is an &lt;a href=&quot;https://stackify.com/oop-concepts-c-sharp/&quot;&gt;OOP language&lt;/a&gt;, so it shouldn’t be a surprise that you’ll use a class for your C# regex work. More specifically, the class I’m talking about is appropriately called Regex and resides in the System.Text.RegularExpressions namespace&lt;strong&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;c-regex-a-validation-example&quot;&gt;C# Regex: A Validation Example&lt;/h3&gt;

&lt;p&gt;Let’s start with a simple validation example on how to use regex to validate whether several strings match a given pattern. The first step is to add the following &lt;strong&gt;using&lt;/strong&gt; statement to your code:&lt;/p&gt;

&lt;p&gt;using System.Text.RegularExpressions;&lt;/p&gt;

&lt;p&gt;Now, let’s create an array of strings and populate it with some values:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;candidates&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;28-JUL-2023&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;whatever&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;89-ABC-1234&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;11-JUN-2022&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;11-JUN-2022, a date plus other stuff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;This is certainly not a date&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Finally, we’ll loop through the values and use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsMatch&lt;/code&gt; static method from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex&lt;/code&gt; class to verify which of the strings matches our desired pattern:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;[0-9]{2}-[A-Z]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;candidates&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;IsMatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;$&quot;The string &apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos; matches the pattern &apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Before going further, let’s break down the pattern piece by piece:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;[0-9]{2}:&lt;/strong&gt; The first part means “Match exactly two characters, that must be digits from 0 to 9.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-:&lt;/strong&gt; This character matches exactly a hyphen.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[A-Z]{3}:&lt;/strong&gt; Here, the expression says, “Let’s match exactly three characters, which can be any of the letters from A to Z.”&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;-:&lt;/strong&gt; This matches another hyphen&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;[0-9]{4}:&lt;/strong&gt; This should be easy to understand by now, right? Exactly four numbers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, let’s run the code and see what we get:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The string &apos;28-JUL-2023&apos; matches the pattern &apos;[0-9]{2}-[A-Z]{3}-[0-9]{4}&apos;
The string &apos;89-ABC-1234&apos; matches the pattern &apos;[0-9]{2}-[A-Z]{3}-[0-9]{4}&apos;
The string &apos;11-JUN-2022&apos; matches the pattern &apos;[0-9]{2}-[A-Z]{3}-[0-9]{4}&apos;
The string &apos;11-JUN-2022, a date plus other stuff&apos; matches the pattern &apos;[0-9]{2}-[A-Z]{3}-[0-9]{4}&apos;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first three results probably didn’t surprise you. I even include something that’s not a date but matches the pattern we’re using in order to really drive home the point that regular expressions are about patterns and shapes and not about any semantics of the data we’re looking for.&lt;/p&gt;

&lt;p&gt;However, the fourth result might’ve surprised you. The text indeed starts with data that matches the pattern we’re looking for, but then it has some additional text. And even then, this string matched!&lt;/p&gt;

&lt;p&gt;The explanation for this behavior is simple, and it’s spelled out for us in the &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.ismatch?view=net-7.0#system-text-regularexpressions-regex-ismatch(system-string-system-string)&quot;&gt;summary&lt;/a&gt; for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;IsMatch&lt;/code&gt; method:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Indicates whether the specified regular expression finds a match in the specified input string.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The regular expression indeed found a match in the specified input string (“11-JUN-2022, a date plus other stuff”), and that’s why it was considered a match.&lt;/p&gt;

&lt;p&gt;But what if we wanted an exact match? In that case, you’d have to change the pattern, adding a circumflex accent (“^”) to the star of the pattern and a dollar sign (“$”) to its end. In other words, here’s how the pattern should look now:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;^[0-9]{2}-[A-Z]{3}-[0-9]{4}$&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If we run the code now, it displays only the strings that are an exact match with the pattern:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;The string &apos;28-JUL-2023&apos; matches the pattern &apos;^[0-9]{2}-[A-Z]{3}-[0-9]{4}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;c-regex-a-manipulation-example&quot;&gt;C# Regex: A Manipulation Example&lt;/h3&gt;

&lt;p&gt;Consider you have a body of text containing sensible user data. Due to privacy/compliance concerns, you want to redact those data points. Luckily for you, it’s quite easy to use a regex for that. &lt;/p&gt;

&lt;p&gt;Let’s start by creating an array containing names and phone numbers for fictitious people:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Emily Johnson,(555) 123-4567&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Benjamin Williams,(555) 987-6543&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Olivia Davis,(555) 222-3333&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Alexander Smith,(555) 444-5555&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Sophia Brown,(555) 777-8888&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;William Anderson,(555) 111-2222&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Ava Martinez,(555) 666-7777&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;James Thompson,(555) 888-9999&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Isabella Wilson,(555) 333-4444&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Michael Taylor,(555) 777-1111&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then, let’s create the pattern to match the phone numbers:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The pattern above is a bit more involved than the ones we used earlier, but it’s still simple. There are a couple of new elements, though:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;The backward slash (\):&lt;/strong&gt; We need it here in order to escape the opening and closing parenthesis, which is a character with meaning in a regular expression. In this instance, we actually do want to match a “(” character, so we need to escape it.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The \s character:&lt;/strong&gt; matches a single space.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, let’s loop through this array and, for each item, use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex.Replace&lt;/code&gt; method to generate a new string in which the phone number is replaced by all zeroes:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contact&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;(000) 000-0000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Using the Replace static method is easy. Though it has several overloads, the one we use just takes three arguments:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the input string&lt;/li&gt;
  &lt;li&gt;the pattern you want to match&lt;/li&gt;
  &lt;li&gt;the replacement string&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After running the code, here’s the output we get:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Emily Johnson,(000) 000-0000
Benjamin Williams,(000) 000-0000
Olivia Davis,(000) 000-0000
Alexander Smith,(000) 000-0000
Sophia Brown,(000) 000-0000
William Anderson,(000) 000-0000
Ava Martinez,(000) 000-0000
James Thompson,(000) 000-0000
Isabella Wilson,(000) 000-0000
Michael Taylor,(000) 000-0000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;c-regex-an-extraction-example&quot;&gt;C# Regex: An Extraction Example&lt;/h3&gt;

&lt;p&gt;For our last example, let’s extract data from a string using a regular expression. Let’s start by converting the array from the previous example into a single string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;Emily Johnson+(555) 123-4567&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nBenjamin Williams+(555) 987-6543&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nOlivia Davis+(555) 222-3333&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nAlexander Smith+(555) 444-5555&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nSophia Brown+(555) 777-8888&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nWilliam Anderson+(555) 111-2222&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nAva Martinez+(555) 666-7777&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nJames Thompson+(555) 888-9999&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nIsabella Wilson+(555) 333-4444&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;\nMichael Taylor+(555) 777-1111&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Then, we define the pattern again (same one) and use the Matches static method to get all of the matches from the string:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;kt&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;@&quot;\([0-9]{3}\)\s[0-9]{3}-[0-9]{4}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;MatchCollection&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Regex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;contacts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MatchCollection&lt;/code&gt; class holds all of the strings that matched the pattern we gave to the method. This object is enumerable, so we can loop over it with a foreach:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Here are the extracted phone numbers:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;foreach&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;matches&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;WriteLine&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;And, finally, our results: &lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c#&quot; data-lang=&quot;c#&quot;&gt;&lt;span class=&quot;n&quot;&gt;Here&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extracted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numbers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;123&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4567&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;987&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;6543&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;222&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3333&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;444&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;5555&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;777&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;8888&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;111&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2222&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;666&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;7777&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;888&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;9999&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;333&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4444&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;555&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;777&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1111&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;c-regex-an-indispensable-tool&quot;&gt;C# Regex: An Indispensable Tool&lt;/h2&gt;

&lt;p&gt;As we said in the intro, text manipulation is a staple of programming, and regular expressions make this task easier. In this C# regex guide, you’ve learned what regular expressions are, their most common usage scenarios and how to get started with regular expressions in C#.&lt;/p&gt;

&lt;p&gt;Before departing, a few tips:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Experiment more with the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regex&lt;/code&gt; class. It offers plenty of features, and the methods we’ve used today have many overloads with useful capabilities.&lt;/li&gt;
  &lt;li&gt;Learn more and practice writing regular expressions. &lt;a href=&quot;https://regexr.com/&quot;&gt;Here’s a great site&lt;/a&gt; you can use.&lt;/li&gt;
  &lt;li&gt;Educate yourself on the performance considerations of C# regex. For instance, read this &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/standard/base-types/compilation-and-reuse-in-regular-expressions?redirectedfrom=MSDN&quot;&gt;Microsoft article on the compilation and reuse of regular expressions&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, if you want to learn more about C# in general, you’re in the right place. The Stackify blog is full of useful resources. As a suggestion, take a look at &lt;a href=&quot;https://stackify.com/unit-test-frameworks-csharp/&quot;&gt;the pros and cons of the top 3 unit test frameworks for C#&lt;/a&gt;, &lt;a href=&quot;https://stackify.com/csharp-catch-all-exceptions/&quot;&gt;how to catch exceptions and find application errors in C#&lt;/a&gt;, and &lt;a href=&quot;https://stackify.com/what-is-c-reflection/&quot;&gt;how C# reflection works&lt;/a&gt; next.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</description>
        <pubDate>Tue, 07 May 2024 00:00:00 +0000</pubDate>
        <link>https://carlosschults.net/en/csharp-regex</link>
        <guid isPermaLink="true">https://carlosschults.net/en/csharp-regex</guid>
        
        <category>csharp</category>
        
        <category>regex</category>
        
        <category>regular_expressions</category>
        
        <category>tutorial</category>
        
        
      </item>
    
  </channel>
</rss>
