<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Drew De Ponte - A backstage perspective on running a company, building &amp; selling apps | drewdeponte.com</title>
    <subtitle>Backstage access as I run a consultancy (https:&#x2F;&#x2F;uptechstudio.com) and build &amp; sell apps.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://drewdeponte.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://drewdeponte.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-01-31T00:00:00+00:00</updated>
    <id>https://drewdeponte.com/atom.xml</id>
    <entry xml:lang="en">
        <title>The Git Patch Stack Methodology</title>
        <published>2026-01-31T00:00:00+00:00</published>
        <updated>2026-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/the-git-patch-stack-methodology/"/>
        <id>https://drewdeponte.com/blog/the-git-patch-stack-methodology/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/the-git-patch-stack-methodology/">&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;Modern Git workflows optimize for features, but best practices optimize for integration, review quality, and history.&lt;&#x2F;p&gt;
&lt;p&gt;The Git Patch Stack Methodology replaces feature-centric pull requests with small, architectural patches stacked directly on top of mainline. Each patch is:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Small and reviewable&lt;&#x2F;li&gt;
&lt;li&gt;Continuously rebased and integrated&lt;&#x2F;li&gt;
&lt;li&gt;Architecturally meaningful&lt;&#x2F;li&gt;
&lt;li&gt;Historically valuable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Development happens outside-in, while review and integration happen inside-out—one patch at a time. The result is better reviews, fewer conflicts, cleaner history, and faster integration without abandoning pull requests.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-note-on-tooling&quot;&gt;A Note on Tooling&lt;&#x2F;h3&gt;
&lt;p&gt;This article describes a methodology, not a tool requirement.&lt;&#x2F;p&gt;
&lt;p&gt;That said, some of the workflows described here—tracking patch identity across rebases, managing patch stacks, and opening pull requests per patch—introduce friction if done manually.&lt;&#x2F;p&gt;
&lt;p&gt;To address that, the Git Patch Stack CLI exists.&lt;&#x2F;p&gt;
&lt;p&gt;👉 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;https:&#x2F;&#x2F;git-ps.sh&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The CLI is designed to support this methodology directly on top of Git and existing platforms like GitHub and Bitbucket. It automates the mechanical work (branching, cherry-picking, tracking patch identity, updating pull requests) so developers can focus on creating high-quality patches and integrating continuously.&lt;&#x2F;p&gt;
&lt;p&gt;The rest of this article explains why the methodology works. Tooling simply makes it practical at scale.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;git-patch-stack-methodology&quot;&gt;Git Patch Stack Methodology&lt;&#x2F;h2&gt;
&lt;p&gt;To truly understand the &lt;strong&gt;Git Patch Stack Methodology&lt;&#x2F;strong&gt;, it helps to start with how software changes are typically made.&lt;&#x2F;p&gt;
&lt;p&gt;At a high level, most changes fall into one of two categories:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Large changes&lt;&#x2F;strong&gt; — new features or major system modifications&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Small changes&lt;&#x2F;strong&gt; — bug fixes, copy updates, refactors, and minor improvements&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;On the surface, this works fine if you don’t care much about peer review quality, conflict reduction, architectural clarity, or the long‑term historical value of your code. In that world, all you need is a &lt;em&gt;feature branch&lt;&#x2F;em&gt;, following the workflow popularized by platforms like GitHub and Bitbucket.&lt;&#x2F;p&gt;
&lt;p&gt;At best, a pull request created this way corresponds to a single, coherent change from the diagram above. At worst, it looks like a feature branch full of loosely related commits—snapshots of half‑finished thoughts—with little structure or narrative. The commits don’t clearly explain &lt;em&gt;what&lt;&#x2F;em&gt; changed, &lt;em&gt;why&lt;&#x2F;em&gt; it changed, or how the changes relate to one another. Unfortunately, this pattern is extremely common.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;best-practices&quot;&gt;Best Practices&lt;&#x2F;h2&gt;
&lt;p&gt;So what should we actually be aiming for?&lt;&#x2F;p&gt;
&lt;h3 id=&quot;small-pull-requests&quot;&gt;Small Pull Requests&lt;&#x2F;h3&gt;
&lt;p&gt;One widely accepted best practice is to keep pull requests small. The primary reason is to enable &lt;em&gt;high‑quality peer review&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;When a pull request is large and overwhelming, reviewers tend to skim it and respond with a quick &lt;strong&gt;LGTM&lt;&#x2F;strong&gt;. We’ve all done it. The result is a review that adds little value—often no more than what an automated linter could have caught.&lt;&#x2F;p&gt;
&lt;p&gt;Small pull requests, on the other hand, make it realistic for reviewers to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Understand the change in context&lt;&#x2F;li&gt;
&lt;li&gt;Evaluate architectural decisions&lt;&#x2F;li&gt;
&lt;li&gt;Reason carefully about correctness and edge cases&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;continuous-integration&quot;&gt;Continuous Integration&lt;&#x2F;h3&gt;
&lt;p&gt;Another best practice is &lt;em&gt;continuous integration&lt;&#x2F;em&gt;—not the tooling (GitHub Actions, CircleCI, etc.), but the behavior.&lt;&#x2F;p&gt;
&lt;p&gt;Continuous integration means integrating changes into the mainline as quickly and as frequently as possible. Doing so:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Dramatically reduces merge conflicts&lt;&#x2F;li&gt;
&lt;li&gt;Makes conflicts easier to resolve when they do occur&lt;&#x2F;li&gt;
&lt;li&gt;Narrows the scope of investigation when a bug is introduced&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Small, frequent integrations keep the system stable and make failures easier to reason about.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;architecture-historical-value&quot;&gt;Architecture &amp;amp; Historical Value&lt;&#x2F;h3&gt;
&lt;p&gt;A third set of best practices concerns the long‑term readability and usefulness of your Git history. Ideally, each change should:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Align with a specific architectural element&lt;&#x2F;li&gt;
&lt;li&gt;Clearly describe &lt;strong&gt;what&lt;&#x2F;strong&gt; changed&lt;&#x2F;li&gt;
&lt;li&gt;Explain &lt;strong&gt;why&lt;&#x2F;strong&gt; the change was necessary&lt;&#x2F;li&gt;
&lt;li&gt;Indicate &lt;strong&gt;how&lt;&#x2F;strong&gt; the change was implemented&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;When these conditions are met, your Git history becomes a form of documentation. You can understand &lt;em&gt;why&lt;&#x2F;em&gt; the system evolved the way it did, not just &lt;em&gt;what&lt;&#x2F;em&gt; the final state looks like. Each commit becomes a small, logical step toward a larger goal—similar to showing your work in a math problem. This is often described as &lt;em&gt;proof of work&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;the-conflict&quot;&gt;The Conflict&lt;&#x2F;h2&gt;
&lt;p&gt;When you try to apply these best practices while relying primarily on feature branches, tensions quickly emerge.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;feature-branches-vs-continuous-integration&quot;&gt;Feature Branches vs. Continuous Integration&lt;&#x2F;h3&gt;
&lt;p&gt;Branches exist to isolate work. Continuous integration exists to &lt;em&gt;avoid&lt;&#x2F;em&gt; isolation. By definition, the two concepts are in conflict.&lt;&#x2F;p&gt;
&lt;p&gt;Teams often try to work around this by rebasing feature branches or repeatedly merging mainline back into them. Rebasing adds cognitive and operational overhead. Merging mainline repeatedly results in tangled Git histories that are difficult to understand or reason about.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;feature-branches-vs-small-pull-requests&quot;&gt;Feature Branches vs. Small Pull Requests&lt;&#x2F;h3&gt;
&lt;p&gt;Feature branches typically bundle an entire feature into a single pull request. The result is often a massive PR that discourages careful review and encourages superficial approval.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;feature-branches-vs-historical-value&quot;&gt;Feature Branches vs. Historical Value&lt;&#x2F;h3&gt;
&lt;p&gt;Finally, feature branches encourage developers to think in terms of &lt;em&gt;features&lt;&#x2F;em&gt;, not &lt;em&gt;architectural changes&lt;&#x2F;em&gt;. As a result, commit messages often lack clarity and historical usefulness. A feature is not an architectural unit; it is composed of many smaller architectural steps.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;resolving-the-conflict&quot;&gt;Resolving the Conflict&lt;&#x2F;h2&gt;
&lt;p&gt;To better align with these best practices, we need a different mental model—one that emphasizes small, architectural changes and frequent integration.&lt;&#x2F;p&gt;
&lt;p&gt;Our goals are straightforward:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Small Pull Requests&lt;&#x2F;strong&gt; — to enable meaningful peer review&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Continuous Integration&lt;&#x2F;strong&gt; — to reduce conflicts and integration pain&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Architectural &amp;amp; Historical Value&lt;&#x2F;strong&gt; — to preserve a readable, valuable history&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;the-patch&quot;&gt;The Patch&lt;&#x2F;h3&gt;
&lt;p&gt;Let’s introduce a new unit of work: the &lt;strong&gt;patch&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;em&gt;patch&lt;&#x2F;em&gt; is a single, logical, architecturally meaningful change that provides historical value. This terminology is intentional—it echoes the original patch‑based workflows used in early open‑source development, and still used today by projects like Git and the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Conceptually, a patch maps directly to a well‑formed Git commit.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;continuous-integration-without-feature-branches&quot;&gt;Continuous Integration Without Feature Branches&lt;&#x2F;h3&gt;
&lt;p&gt;Instead of developing long‑lived feature branches, we develop directly on top of mainline.&lt;&#x2F;p&gt;
&lt;p&gt;Local commits represent patches. As mainline advances, we continuously rebase our local patch stack on top of it. Git makes this easy:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[pull]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    rebase = true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this configuration, &lt;code&gt;git pull&lt;&#x2F;code&gt; automatically rebases your local patches onto the latest mainline, surfacing conflicts early—when they’re small and easy to fix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-stack&quot;&gt;The Stack&lt;&#x2F;h3&gt;
&lt;p&gt;Rarely do we create just one patch. More often, we create a &lt;strong&gt;stack of patches&lt;&#x2F;strong&gt;, each building on the one below it.&lt;&#x2F;p&gt;
&lt;p&gt;This stack lives locally on top of &lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt;. Later patches can depend on earlier ones, which mirrors how real features are developed. Git’s interactive rebase allows us to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Reorder patches&lt;&#x2F;li&gt;
&lt;li&gt;Edit them&lt;&#x2F;li&gt;
&lt;li&gt;Split or squash them&lt;&#x2F;li&gt;
&lt;li&gt;Drop them entirely&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Work‑in‑progress commits can be marked with a &lt;code&gt;WIP:&lt;&#x2F;code&gt; prefix and refined over time until they’re ready for review.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pull-requests-as-patch-reviews&quot;&gt;Pull Requests as Patch Reviews&lt;&#x2F;h3&gt;
&lt;p&gt;Pull requests still matter—they’re how we request review. But instead of representing &lt;em&gt;features&lt;&#x2F;em&gt;, they represent &lt;em&gt;patches&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A simple workflow looks like this:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Create a branch from &lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt; named after the patch&lt;&#x2F;li&gt;
&lt;li&gt;Cherry‑pick the patch onto that branch&lt;&#x2F;li&gt;
&lt;li&gt;Push the branch and open a pull request&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;This introduces some overhead, but it’s manageable—and automatable.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;independent-vs-dependent-patches&quot;&gt;Independent vs. Dependent Patches&lt;&#x2F;h3&gt;
&lt;p&gt;Independent patches can be reviewed and merged on their own.&lt;&#x2F;p&gt;
&lt;p&gt;Dependent patches require more care. If Patch B depends on Patch A, then Patch A must be reviewed and merged first. This encourages an &lt;strong&gt;inside‑out review order&lt;&#x2F;strong&gt;, even if development happens outside‑in.&lt;&#x2F;p&gt;
&lt;p&gt;In some cases, a &lt;em&gt;patch series&lt;&#x2F;em&gt;—a pull request containing multiple dependent patches—may be appropriate. This trades faster integration for convenience and should be used selectively.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;updating-pull-requests&quot;&gt;Updating Pull Requests&lt;&#x2F;h3&gt;
&lt;p&gt;When a reviewer requests changes, we don’t add new commits—we update the patch.&lt;&#x2F;p&gt;
&lt;p&gt;Using interactive rebase, we modify the original commit and force‑push the updated branch. The pull request stays focused on a single logical change, even as it evolves.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tracking-patch-identity&quot;&gt;Tracking Patch Identity&lt;&#x2F;h3&gt;
&lt;p&gt;Because rebasing changes commit hashes, we need a stable identifier. Each patch includes a UUID in its commit message:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ps-id: &amp;lt;uuid&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows tooling to track patches across rebases, branches, and pull requests—and to detect when a patch has diverged from its reviewed version.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;development-outside-in-review-inside-out&quot;&gt;Development: Outside‑In, Review: Inside‑Out&lt;&#x2F;h2&gt;
&lt;p&gt;Patch stacks naturally reflect dependency structure: foundational changes sit at the bottom, higher‑level behavior at the top.&lt;&#x2F;p&gt;
&lt;p&gt;This pairs well with &lt;strong&gt;outside‑in development&lt;&#x2F;strong&gt;—starting from the system boundary and letting requirements drive lower‑level interfaces. Early patches may be incomplete or marked as WIP.&lt;&#x2F;p&gt;
&lt;p&gt;As inner layers solidify, outer patches are revisited and finalized. Review, however, happens &lt;strong&gt;inside‑out&lt;&#x2F;strong&gt;: dependencies first, consumers later.&lt;&#x2F;p&gt;
&lt;p&gt;This rhythm—&lt;em&gt;develop outside‑in, review inside‑out&lt;&#x2F;em&gt;—is the heart of the Git Patch Stack Methodology.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Hosting my Git Repositories</title>
        <published>2026-01-06T00:00:00+00:00</published>
        <updated>2026-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/hosting-my-git-repositories/"/>
        <id>https://drewdeponte.com/blog/hosting-my-git-repositories/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/hosting-my-git-repositories/">&lt;p&gt;For a long while now it has become more and more evident that you just can&#x27;t
trust companies to host your data. This is true even if you are paying for said
services. This has become even more obvious with the introduction of large
language models, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, the products that exist in the space of Git hosting are less than
ideal in my opinion. Instead of them focusing on making Git hosting as good as
it possibly could be. They are focused on building AI platforms that integrate
with all your Git repositories. Which I have zero interest in when I am paying
for Git hosting. Beyond that these companies are built on a software
development model that is clearly less than ideal but they have no interest in
rethinking that model.&lt;&#x2F;p&gt;
&lt;p&gt;For these reasons and more I have decided it probably makes the most sense to
simply host all my Git repositories myself.&lt;&#x2F;p&gt;
&lt;p&gt;The following are my notes around how I accomplished this so that if anyone
else wants to do the same they would hopefully be able to figure out.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-we-need&quot;&gt;What we need&lt;&#x2F;h2&gt;
&lt;p&gt;Basically, we need a server to host the repositories and run the software. You
can of course pay some VPS provider like Digital Ocean or you can run your own
server at your house or wherever you want. Note: If you run it at your house
you will likely need to figure out some sort of Dynamic DNS. I believe
Cloudflare provides this as a service. But I am sure there are others.&lt;&#x2F;p&gt;
&lt;p&gt;Then you need to have an operating system. I personally prefer Arch Linux so I
have a server running Arch Linux.&lt;&#x2F;p&gt;
&lt;p&gt;We are going to be hosting our Git repositories over the SSH protocol with the
help of a tool called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitolite.com&quot;&gt;Gitolite&lt;&#x2F;a&gt;. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitolite.com&quot;&gt;Gitolite&lt;&#x2F;a&gt; facilitates authenticating
users and managing access to the Git repositories over SSH public&#x2F;private key
pairs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;&#x2F;h2&gt;
&lt;p&gt;This portion assumes you already have an Arch Linux system setup for your server.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;get-ssh-daemeon-setup&quot;&gt;Get SSH Daemeon Setup&lt;&#x2F;h3&gt;
&lt;p&gt;First thing we need to do on that server is installed the &lt;code&gt;openssh&lt;&#x2F;code&gt; package so
that we will have the ssh daemon installed.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo pacman -Sy openssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next we want to start the ssh daemon.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl start sshd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we want to enable it so that it starts up at boot.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl enable sshd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We can then verify it is running with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;systemctl status sshd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I configured sshd by editing &lt;code&gt;&#x2F;etc&#x2F;ssh&#x2F;sshd_config&lt;&#x2F;code&gt; by updating it so that
the following are set. Explanations of what they do are in comments above them
all below. This is effectively to harden sshd as may be exposed to the internet
directly and it needs to be as secure as possible.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Enable public key authentication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PublickeyAuthentication yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Tell it where to find the file containing authorized keps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AuthorizedKeysFile .ssh&#x2F;authorized_keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Prevent password authentication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PasswordAuthentication no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Prevent challenge response auth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ChallengeResponseAuthentication no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Disable PAM authentication&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;UsePAM no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Prevent root login&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PermitRootLogin no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Prevent keyboard interactive auth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;KbdInteractiveAuthentication no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Don&amp;#39;t allow any empty passwords&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PermitEmptyPasswords no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Restrict allowed users&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AllowUsers youruser gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Disable agent &amp;amp; TCP forwarding unless you need it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AllowAgentForwarding no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;AllowTcpForwarding no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;X11Forwarding no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Disable tunneling unless needed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PermitTunnel no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Disable rhosts-style trust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IgnoreRhosts yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;HostbasedAuthentication no&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Limit auth attempts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MaxAuthTries 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Limit concurrent connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MaxSessions 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MaxStartups 10:30:60&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Drop idle connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ClientAliveInterval 300&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ClientAliveCountMax 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I restarted the sshd to have the changes take place.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl restart sshd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After this I simply scp&#x27;d my public ssh key over to the server and added it to
the &lt;code&gt;authorized_keys&lt;&#x2F;code&gt; file as follows so that I could easily ssh over to the
server and manage things.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cat ~&#x2F;.ssh&#x2F;id_ed25519.pub &amp;gt;&amp;gt; ~&#x2F;.ssh&#x2F;authorized_keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I simply made sure that the file had the correct permissions.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chmod 600 ~&#x2F;.ssh&#x2F;authorized_keys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chown -R user:user ~&#x2F;.ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;install-setup-gitolite&quot;&gt;Install &amp;amp; Setup Gitolite&lt;&#x2F;h3&gt;
&lt;p&gt;First I installed the dependencies as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo pacman -Sy base-devel git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I installed &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitolite.com&quot;&gt;Gitolite&lt;&#x2F;a&gt; as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo pacman -Sy gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above created the &lt;code&gt;gitolite&lt;&#x2F;code&gt; user on the system and setup
&lt;code&gt;&#x2F;var&#x2F;lib&#x2F;gitolite&lt;&#x2F;code&gt; as it&#x27;s home directory.&lt;&#x2F;p&gt;
&lt;p&gt;Then simply needed to initialize Gitolite. In order to do this I ran the
following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -u gitolite gitolite setup -pk path&#x2F;to&#x2F;my&#x2F;public&#x2F;ssh&#x2F;key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This setup the &lt;code&gt;gitolite-admin&lt;&#x2F;code&gt; repository as well as a &lt;code&gt;testing&lt;&#x2F;code&gt; repository.
The &lt;code&gt;gitolite-admin&lt;&#x2F;code&gt; repository is how you configure and manage Gitolite. So
you simply clone it and make changes to the configs in there and commit and
push it up. It then handles creating repositories appropriately for you with
the configured access controls.&lt;&#x2F;p&gt;
&lt;p&gt;Which supports what you need for private repositories as well as anonymous
(unauthenticated) repositories which are useful for opensource.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-about-off-site-backups&quot;&gt;What about Off-site Backups&lt;&#x2F;h2&gt;
&lt;p&gt;One side benefits I was getting from the services I was leaving was off-site
backups. So, I figured I might as well address that in my setup as well.&lt;&#x2F;p&gt;
&lt;p&gt;Turns out there is a pretty great backup tool called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;restic.net&#x2F;&quot;&gt;Restic&lt;&#x2F;a&gt; that integrates
with Backblaze B2 that allows you to configure backups to be done and stored in
a Backblaze B2 bucket pretty easily.&lt;&#x2F;p&gt;
&lt;p&gt;First I had to decide what I wanted to backup. In my case I simply wanted the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;.gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I installed &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;restic.net&#x2F;&quot;&gt;Restic&lt;&#x2F;a&gt; as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo pacman -Sy restic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I had to go and create my Backblaze B2 bucket and an Application Key,
which I captured the bucket name, key id, and key itself and did the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo mkdir -p &#x2F;etc&#x2F;restic&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo nvim &#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I then created filled &lt;code&gt;&#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;code&gt; with the following content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export RESTIC_REPOSITORY=&amp;quot;b2:BUCKET_NAME:&#x2F;gitolite&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export RESTIC_PASSWORD=&amp;quot;use-a-long-random-passphrase&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export B2_ACCOUNT_ID=&amp;quot;your-application-key-id&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;export B2_ACCOUNT_KEY=&amp;quot;your-application-key&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I set the perms on that directory and file as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo chmod 600 &#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo chown root:root &#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I initialized the restic repository.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source &#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I ran a manual backup to test things out.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic backup \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;.gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic snapshots&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I added an exclusion file to exclude unneccessary files.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvim &#x2F;etc&#x2F;restic&#x2F;gitolite.exclude&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;and gave it the following content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;**&#x2F;tmp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;**&#x2F;*.lock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;**&#x2F;lost+found&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I tested manual backup again with it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic backup \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --exclude-file &#x2F;etc&#x2F;restic&#x2F;gitolite.exclude \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;.gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I came up with a simple retention policy and tested it as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic forget \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-daily 14 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-weekly 8 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-monthly 12 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --prune&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This removes old snapshots, etc. based on the retention policy.&lt;&#x2F;p&gt;
&lt;p&gt;Then I created a backup script so that I could automate this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvim &#x2F;usr&#x2F;local&#x2F;bin&#x2F;restic-gitolite-backup.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;with the following content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set -euo pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;source &#x2F;etc&#x2F;restic&#x2F;gitolite.env&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic backup \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --exclude-file &#x2F;etc&#x2F;restic&#x2F;gitolite.exclude \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;.gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic forget \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-daily 14 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-weekly 8 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --keep-monthly 12 \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --prune&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I made it executable as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;chmod +x &#x2F;usr&#x2F;local&#x2F;bin&#x2F;restic-gitolite-backup.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I registered it as a systemd service by creating the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvim &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;restic-gitolite-backup.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;with the following content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Unit]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description=Restic backup of Gitolite repositories&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Wants=network-online.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;After=network-online.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Service]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Type=oneshot&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ExecStart=&#x2F;usr&#x2F;local&#x2F;bin&#x2F;restic-gitolite-backup.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I created a systemd timer to run it automatically.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;nvim &#x2F;etc&#x2F;systemd&#x2F;system&#x2F;restic-gitolite-backup.timer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;with the following content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Unit]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description=Daily Restic Gitolite backup&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Timer]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OnCalendar=daily&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Persistent=true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Install]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WantedBy=timers.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I simply enabled it as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;systemctl daemon-reload&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;systemctl enable --now restic-gitolite-backup.timer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And verified that it was properly registered and running with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;systemctl list-timers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally I tested the backups to make sure I could restore from them as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic snapshots&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic restore latest --target &#x2F;tmp&#x2F;restore-test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In theory you should be able to restore an individual repo as follows. But I
have not tested this yet.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;restic restore latest \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --include &#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories&#x2F;myrepo.git \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --target &#x2F;tmp&#x2F;restore-test&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;opensource-repositories&quot;&gt;OpenSource Repositories&lt;&#x2F;h2&gt;
&lt;p&gt;Setup hosting of anonymous repositories with &lt;code&gt;git:&#x2F;&#x2F;&lt;&#x2F;code&gt; protocol which doesn&#x27;t
facilitate any authentication. I do this via the &lt;code&gt;git-daemon&lt;&#x2F;code&gt; which comes with
git. It also has the benefit of playing nicely with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gitolite.com&quot;&gt;Gitolite&lt;&#x2F;a&gt; and therefore
allows sharing the same repositories store.&lt;&#x2F;p&gt;
&lt;p&gt;To do this I created a systemd service description for it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;etc&#x2F;systemd&#x2F;system&#x2F;git-daemon.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;with the content&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Unit]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Description=Git Daemon (anonymous read-only)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;After=network.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Service]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;User=gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Group=gitolite&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ExecStart=&#x2F;usr&#x2F;lib&#x2F;git-core&#x2F;git-daemon \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --reuseaddr \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --base-path=&#x2F;var&#x2F;lib&#x2F;gitolite&#x2F;repositories \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --disable=receive-pack \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --informative-errors \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --verbose&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Restart=on-failure&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Install]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WantedBy=multi-user.target&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I enabled and started the service as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl daemon-reload&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl enable git-daemon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl start git-daemon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl status git-daemon&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I simply exposed the &lt;code&gt;git-daemon&lt;&#x2F;code&gt; port &lt;code&gt;9418&lt;&#x2F;code&gt; in the firewall so that
externally people would be able to access the opensource repositories.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dynamic-dns&quot;&gt;Dynamic DNS&lt;&#x2F;h2&gt;
&lt;p&gt;I am using Cloudfare for DNS zone hosting. So I whipped up the following little
script &lt;code&gt;~&#x2F;bin&#x2F;update_dns_record_with_public_ip&lt;&#x2F;code&gt;, to dynamically set the IP
address.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;usr&#x2F;bin&#x2F;env bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set -euo pipefail&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ZONE_ID=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RECORD_ID=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CLOUDFLARE_API_TOKEN=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SUB_DOMAIN=&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;TIMESTAMP=$(date &amp;#39;+%Y-%m-%d %H:%M:%S&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LOGFILE=&amp;quot;$HOME&#x2F;logs&#x2F;cloudflare-ddns.log&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Fetch the RECORD_ID of the subdomain. This only has to be done initially to get the value for RECORD_ID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# So just uncomment this, save the file, and run the script to get the RECORD_ID. Then simply update the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# script with the RECORD_ID value, recomment these lines, and save the script and you should be good to go.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# curl -X GET &amp;quot;https:&#x2F;&#x2F;api.cloudflare.com&#x2F;client&#x2F;v4&#x2F;zones&#x2F;$ZONE_ID&#x2F;dns_records?name=$SUB_DOMAIN&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#  -H &amp;quot;Authorization: Bearer $CLOUDFLARE_API_TOKEN&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# exit 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Fetch the public IP address using ifconfig.me&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;IP_ADDRESS=$(curl -s ifconfig.me)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Get the IP address Cloudflare currently has for the subdomain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;DNS_IP=$(curl -s \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -H &amp;quot;Authorization: Bearer $CLOUDFLARE_API_TOKEN&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -H &amp;quot;Content-Type: application&#x2F;json&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;https:&#x2F;&#x2F;api.cloudflare.com&#x2F;client&#x2F;v4&#x2F;zones&#x2F;$ZONE_ID&#x2F;dns_records&#x2F;$RECORD_ID&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  | jq -r &amp;#39;.result.content&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# 3. Compare existing DNS record&amp;#39;s IP addr to the current public IP addr&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if [[ &amp;quot;$IP_ADDRESS&amp;quot; == &amp;quot;$DNS_IP&amp;quot; ]]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  echo &amp;quot;$TIMESTAMP - IP unchanged ($IP_ADDRESS). No update needed.&amp;quot; &amp;gt;&amp;gt; &amp;quot;$LOGFILE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  exit 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;RESPONSE=$(curl -X PUT &amp;quot;https:&#x2F;&#x2F;api.cloudflare.com&#x2F;client&#x2F;v4&#x2F;zones&#x2F;$ZONE_ID&#x2F;dns_records&#x2F;$RECORD_ID&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -H &amp;quot;Authorization: Bearer $CLOUDFLARE_API_TOKEN&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  -H &amp;quot;Content-Type: application&#x2F;json&amp;quot; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  --data &amp;quot;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    \&amp;quot;type\&amp;quot;: \&amp;quot;A\&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    \&amp;quot;name\&amp;quot;: \&amp;quot;$SUB_DOMAIN\&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    \&amp;quot;content\&amp;quot;: \&amp;quot;$IP_ADDRESS\&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    \&amp;quot;ttl\&amp;quot;: 120,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    \&amp;quot;proxied\&amp;quot;: false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Check success&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;SUCCESS=$(echo &amp;quot;$RESPONSE&amp;quot; | jq -r &amp;#39;.success&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if [[ &amp;quot;$SUCCESS&amp;quot; == &amp;quot;true&amp;quot; ]]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  echo &amp;quot;$TIMESTAMP - DNS update successful ($IP_ADDRESS)&amp;quot; &amp;gt;&amp;gt; &amp;quot;$LOGFILE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ERR_MSG=$(echo &amp;quot;$RESPONSE&amp;quot; | jq -r &amp;#39;.errors[]?.message&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  echo &amp;quot;$TIMESTAMP - DNS update failed: $ERR_MSG&amp;quot; &amp;gt;&amp;gt; &amp;quot;$LOGFILE&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This script expects your user&#x27;s hame directory to also have a &lt;code&gt;logs&lt;&#x2F;code&gt; directory
to be able to write it&#x27;s logs out to.&lt;&#x2F;p&gt;
&lt;p&gt;This script fetches the public IP address using ifconfig.me and then uses the
Cloudflare API to update the subdomain.&lt;&#x2F;p&gt;
&lt;p&gt;In order for this to work you need to create an API Key that is setup for Edit
zone. This can be done from the Cloudflare -&amp;gt; Avatar -&amp;gt; Profile -&amp;gt; API Keys.&lt;&#x2F;p&gt;
&lt;p&gt;Then to use this you obviously would need to fill in the variables at the
top of the script. The ZONE_ID can be obtained by selecting the zone in the
Cloudflare UI and looking in the right sidebar for the API section and grabbing
the zone id value. The RECORD_ID I believe is only available by using the API
call that is commented out near the top of the script.&lt;&#x2F;p&gt;
&lt;p&gt;Once I had the script setup I was able to test it by just running it. But, I
don&#x27;t want to manually do this. I want it to automatically be run.&lt;&#x2F;p&gt;
&lt;p&gt;So I installed &lt;code&gt;cronie&lt;&#x2F;code&gt; with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo pacman -Sy cronie vi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir -p ~&#x2F;.cache&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl enable cronie.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl start cronie.service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I edited my users crontab via &lt;code&gt;crontab -e&lt;&#x2F;code&gt; and gave it the following
content.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*&#x2F;5 * * * * &#x2F;home&#x2F;YOUR-USERNAME&#x2F;bin&#x2F;update_dns_record_with_public_ip &amp;gt;&amp;gt; &#x2F;home&#x2F;YOUR-USERNAME&#x2F;logs&#x2F;cloudflare-ddns-cron.log 2&amp;gt;&amp;amp;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;0 0 * * * truncate -s 0 &#x2F;home&#x2F;YOUR-USERNAME&#x2F;logs&#x2F;cloudflare-ddns.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above registers two cron jobs. The first one runs the script every 5 mins
to make sure that the DNS record is up to date. The second one runs once every
day and truncates the log file so it does not get out of hand.&lt;&#x2F;p&gt;
&lt;p&gt;I then waited and checked the log files to make sure everything was working as
expected.&lt;&#x2F;p&gt;
&lt;p&gt;Don&#x27;t also forget that you need to likely modify your router configuration to
forward port 22 from the outside of your network to your server&#x27;s internal IP
address. That is if you aren&#x27;t using a hosted VPS. If you are using a hosted
VPS you shouldn&#x27;t need this entire Dynamic DNS section at all as you generally
get a static IP address.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-about-prs-comments-etc&quot;&gt;What about PRs, comments, etc.&lt;&#x2F;h2&gt;
&lt;p&gt;Personally, I don&#x27;t want or need any of those things. There are plenty of tools
that can be used to facilitate those types of interactions without the need for
the Git hosting to do them. A very basic one is the concept of patches and
emails to say the least for open source repositories.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Shower Thoughts 2026-01-01</title>
        <published>2026-01-01T00:00:00+00:00</published>
        <updated>2026-01-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/shower-thoughts-2026-01-01/"/>
        <id>https://drewdeponte.com/blog/shower-thoughts-2026-01-01/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/shower-thoughts-2026-01-01/">&lt;p&gt;Welcome to my first Shower Thoughts arcticle. This is a series that I came up
with while taking a shower this morning. I am not planning on writing an
article every day or anything. As I don&#x27;t necessarily have significant shower
thoughts every day. But when I do this is an outlet for me to get them out and
share them with my future self and the world.&lt;&#x2F;p&gt;
&lt;p&gt;Of course they will primarily be business, product and engineering focused as
that is where my career is spent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;coming-back-to-sharing-things&quot;&gt;Coming back to Sharing Things&lt;&#x2F;h2&gt;
&lt;p&gt;For about a year now I have taken a step back from sharing things that I am
working on or sharing things that I have been thinking about. This was
partially because of various things going on in my life, e.g. switch to
Principal Engineer at OnDiem, etc. But probably most significantly it was
because it takes a decent amount of time and effort to share things and I just
wasn&#x27;t sure the value in terms of what it brings to other people, how much
it helps my standing within the community, etc. was there.&lt;&#x2F;p&gt;
&lt;p&gt;Now that it has been about a year and I am looking back. I believe I have been
looking at the &quot;value&quot; all wrong. I now believe there is something innate to it
that helps me stay happy. I am not sure exactly what it is or why. Maybe it is
some deep need within me to connect with people in terms of the things that I
am working on and thinking about. But I do know at this point it is definitely
a significant component that impacts my emotional state.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that if there is one thing I have found to be true over the years. It is
that taking the extra few minutes to write something down generally ends up
saving me more time in the future.&lt;&#x2F;p&gt;
&lt;p&gt;So with those two points in mind I am going to be coming back to sharing things
more often.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;righting-the-wrongs-of-software-development&quot;&gt;Righting the Wrongs of Software Development&lt;&#x2F;h2&gt;
&lt;p&gt;Another topic that came to mind while in the shower this morning is this deep
seeded need to right what I see as wrongs within the Software Development
world. I have tried to let go of this mental stance over the past year or so as
I haven&#x27;t necessarily seen a direct &amp;amp; clear path to profit from it.&lt;&#x2F;p&gt;
&lt;p&gt;I have failed in terms of letting go of this and have decided that for my own
sanity, happiness, etc. I really need to double down on this instead of letting
go of it. And not worry about the money and the profitability as much. At least
right now.&lt;&#x2F;p&gt;
&lt;p&gt;So what is this mentality of &quot;Righting the Wrongs of Software Development&quot; you
may ask?&lt;&#x2F;p&gt;
&lt;p&gt;Well, it is hard to fully articulate. So, I will simply try to call out some
wrongs that I see and that I think about, some of which I may be actively
exploring addressing.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Why is it we can have video games that can perform well above 244 hz while
doing tons of computation but we can&#x27;t have desktop apps that can scroll some
basic content smoothly?&lt;&#x2F;li&gt;
&lt;li&gt;Why do there have to be so many layers to things in general? It makes
everything slower, harder to debug, and much harder to make performant.&lt;&#x2F;li&gt;
&lt;li&gt;Why are we trying to build local state based applications in browsers via
Javascript? Or maybe even in WebASM if you are really on the bleading edge.
It is just more layers of what was already possible in native development in
a much better fashion.&lt;&#x2F;li&gt;
&lt;li&gt;Why does everyone think the only way to build cross-platform applications is
to do so through a browser? Making everything with much more layers and much
less performance.&lt;&#x2F;li&gt;
&lt;li&gt;Why is it people are so attached to social networks when they generally don&#x27;t
breed true conversation? People would be better offer writing blog posts and
simply having people email them if someone wants to comment on a post. Or maybe
email a mailing list for that post so that other people interested in that
topic could follow along. It would probably be better to facilitate more real
meaning conversations. A mailing list could be at the author level or maybe at
a per article level. And guess what mailto: links allow you to specify a
subject line, body, etc. to start the email with.&lt;&#x2F;li&gt;
&lt;li&gt;Why is it every product feels like it has to do a million things. I want the
products I use to do less things but do them better. Example I want a simple
service to exist that lets people subscribe to mailing lists and that is it. I
want another tool that can interact with said service to get emails from that
list. Why does everything have to be so needlessly coupled. In Mailchimp for
example why can&#x27;t I send my own custom made raw emails without paying more
money?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The list goes on and on and on an on. With tools, services, products in general
that I interact with on a daily basis. The hard part is focusing and
prioritizing which if any to actual focus effort and energy into. Beyond that,
identifying where people went wrong with things and making sure that those
things don&#x27;t happen within my products.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;simple-mailing-lists-flexible-mail-pipeline&quot;&gt;Simple Mailing Lists &amp;amp; Flexible Mail Pipeline&lt;&#x2F;h2&gt;
&lt;p&gt;This is an idea that I had a while back and I even spent some time working on
at one point. But in today&#x27;s shower thoughts it came back up and makes me think
that maybe I should finish out the work to get it at least to an initial phase
of completion. Making it fully usable.&lt;&#x2F;p&gt;
&lt;p&gt;The core idea here is to split out the service that allows people to subcribe
to a mailing list. Making it extremely focused, light weight, performant,
cross-platform, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Then have another tool that can take Markdown files and produce HTML email content.&lt;&#x2F;p&gt;
&lt;p&gt;Then have another tool that can take HTML email content and send it to a
collection of users.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;shower-thoughts-2026-01-01&#x2F;modular_mailing_list_system.png&quot; alt=&quot;Modular Mailing List System&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The idea being that all these components that be simple, focused, performant,
and modular. So that they can do their one thing and do it well. This will give
me the flexibility. And who knows maybe it will give me some thoughts on how to
package things up as a service or a product.&lt;&#x2F;p&gt;
&lt;p&gt;But irrespective it will give me the baseline tools to run my mailing list the
way I want and give me the flexibility to evolve in the ways that I want.&lt;&#x2F;p&gt;
&lt;p&gt;You are probably going. Well, what out click tracking, and open tracking, and
all that other stuff that everyone wants their email marketing tools to do. I
am not doing any of it. I don&#x27;t value it. What I am sharing with the world I am
going to share if there is 1 person listening or 1 million people listing. That
metric isn&#x27;t useful to me and there are much more valuable and meaningful
metrics to pay attention to.&lt;&#x2F;p&gt;
&lt;p&gt;This really boils down to simply architecting things in a better way. But this
was actually driven out of my frustration with marketing automation tools like
Mailchimp, etc.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Install multiple PostgreSQL versions from src on Arch</title>
        <published>2025-12-12T00:00:00+00:00</published>
        <updated>2025-12-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/install-multiple-postgresql-versions-from-src-on-arch/"/>
        <id>https://drewdeponte.com/blog/install-multiple-postgresql-versions-from-src-on-arch/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/install-multiple-postgresql-versions-from-src-on-arch/">&lt;p&gt;On Arch Linux if you need multiple versions of PostgreSQL installed at the same
time. Say because you are working on a software product that is currently
locked into an older PostgreSQL version while also working on another product
that is using a new PostgreSQL version. You are kinda screwed, at least in
terms of being able to do it from the packagement management system.&lt;&#x2F;p&gt;
&lt;p&gt;They effectively provide the latest version and then also provided through the
user packages you can get a previous version to facilitate the upgrade process
that PostgreSQL requires.&lt;&#x2F;p&gt;
&lt;p&gt;So we have to look for a solution outside of the normal package management
system. I tried looking for solutions like a PostgreSQL Version Manager similar
in concept to NVM (Node Version Manager) or RVM (Ruby Version Manager), etc.
There were a couple that seemed not fully baked and just seemed like a bunch of
unnecessary layers of crap.&lt;&#x2F;p&gt;
&lt;p&gt;The only alternative I could find was to use Docker which I also didn&#x27;t want to
do as it is a bunch more layers of crap that I didn&#x27;t want to deal with.&lt;&#x2F;p&gt;
&lt;p&gt;We should totally be able to install multiple versions of PostgreSQL side by
side on Arch Linux and it shouldn&#x27;t be a problem. And guess what. I was
correct. The following are my notes from when I set this up.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;&#x2F;h2&gt;
&lt;p&gt;In the below I specify a custom prefix of &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13&lt;&#x2F;code&gt; instead of
the default of &lt;code&gt;&#x2F;usr&#x2F;local&#x2F;pgsql&lt;&#x2F;code&gt; because I want to be able to have multiple
postgresql versions installed at the same time.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, I specified the &lt;code&gt;openssl-1.1&lt;&#x2F;code&gt; which is an additional package you
can install on Arch linux beside the normal openssl 3.6.0, because the
&lt;code&gt;pgcrypto&lt;&#x2F;code&gt; extension depends on things that were provided by openssl 1.1 but
were removed in openssl 3.x.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that I specified &lt;code&gt;--with-uuid=e2fs&lt;&#x2F;code&gt; because on Arch linux the &lt;code&gt;libuuid&lt;&#x2F;code&gt;
is provided and not the &lt;code&gt;ossp-uuid&lt;&#x2F;code&gt; library. I needed to specify this so that
when I built the &lt;code&gt;uuid-ossp&lt;&#x2F;code&gt; extension in contrib it could properly build.&lt;&#x2F;p&gt;
&lt;p&gt;Out side of that I simply followed the directions in the PostgreSQL
documentation with the following configure command to take the above into
account.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;.&#x2F;configure --prefix=&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13 --with-openssl --with-includes=&#x2F;usr&#x2F;include&#x2F;openssl-1.1 --with-libraries=&#x2F;usr&#x2F;lib&#x2F;openssl-1.1 --with-uuid=e2fs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: During the process the build would fail. And I would look at why it was
failing and it was always simply a dependency that was not installed. I would
install the package from the package system and then re-run the build. I did
this a handfull of times to get the build to fully succeed. I also followed the
same process for the extensions that I installed as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;start-stop-versions&quot;&gt;Start&#x2F;Stop Versions&lt;&#x2F;h2&gt;
&lt;p&gt;You don&#x27;t really have two versions running at the same time in this setup. So
the key becomes how do you start and stop the different versions of PostgreSQL
that you have installed. The way I addressed this was simply to whip up some
quick shell scripts to start and stop it. For example I created a
&lt;code&gt;~&#x2F;bin&#x2F;pgsql_start_15.13&lt;&#x2F;code&gt; and &lt;code&gt;~&#x2F;bin&#x2F;pgsql_stop_15.13&lt;&#x2F;code&gt; to facilitate starting
and stopping that specific version of PostgreSQL.&lt;&#x2F;p&gt;
&lt;p&gt;The following is the content from &lt;code&gt;~&#x2F;bin&#x2F;pgsql_start_15.13&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;usr&#x2F;bin&#x2F;env sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PGDATA=&amp;quot;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13&#x2F;data&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PGCTL=&amp;quot;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13&#x2F;bin&#x2F;pg_ctl&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;LOGFILE=&amp;quot;$PGDATA&#x2F;logfile&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# go to directory pg_ctl has perms to so that when&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# pg_ctl tries to return to the directory it doesn&amp;#39;t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# error.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd &#x2F;tmp || exit 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Check if PostgreSQL is already running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if sudo -u postgres $PGCTL -D &amp;quot;$PGDATA&amp;quot; status &amp;gt; &#x2F;dev&#x2F;null 2&amp;gt;&amp;amp;1; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;PostgreSQL is already running.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;Starting PostgreSQL...&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sudo -u postgres $PGCTL -D &amp;quot;$PGDATA&amp;quot; -l &amp;quot;$LOGFILE&amp;quot; start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;PostgreSQL started.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The following is the content from the &lt;code&gt;~&#x2F;bin&#x2F;pgsql_stop_15.13&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#!&#x2F;usr&#x2F;bin&#x2F;env sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Variables&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PGDATA=&amp;quot;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13&#x2F;data&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;PGCTL=&amp;quot;&#x2F;usr&#x2F;local&#x2F;pgsql&#x2F;15.13&#x2F;bin&#x2F;pg_ctl&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# go to directory pg_ctl has perms to so that when&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# pg_ctl tries to return to the directory it doesn&amp;#39;t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# error.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cd &#x2F;tmp || exit 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Check if PostgreSQL is running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;if sudo -u postgres $PGCTL -D &amp;quot;$PGDATA&amp;quot; status &amp;gt; &#x2F;dev&#x2F;null 2&amp;gt;&amp;amp;1; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;Stopping PostgreSQL...&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    sudo -u postgres $PGCTL -D &amp;quot;$PGDATA&amp;quot; stop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;PostgreSQL stopped.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    echo &amp;quot;PostgreSQL is not running.&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Fix PostgreSQL Collation version miss-match</title>
        <published>2025-11-25T00:00:00+00:00</published>
        <updated>2025-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/fix-postgresql-collation-version-miss-match/"/>
        <id>https://drewdeponte.com/blog/fix-postgresql-collation-version-miss-match/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/fix-postgresql-collation-version-miss-match/">&lt;p&gt;The following is an example of what you need to do to fix PostgreSQL Collation
version miss-match issues on Arch Linux.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;REINDEX DATABASE dummy;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;ALTER DATABASE dummy REFRESH COLLATION VERSION;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Basically my understanding is that PostgreSQL depends on certain libraries and
the version of those libraries are effectively snapshotted when the indexing is
done. Hence the COLLATION VERSION. So when libraries are upgraded on the system
and PostgreSQL is now linking to a different version of the library. There is
no guarantee that it behaves 100% the same as it did with the previous.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, you need to reindex things and then update the COLLATION VERSION.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Install Ruby on Arch Linux</title>
        <published>2025-11-25T00:00:00+00:00</published>
        <updated>2025-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/install-ruby-on-arch-linux/"/>
        <id>https://drewdeponte.com/blog/install-ruby-on-arch-linux/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/install-ruby-on-arch-linux/">&lt;p&gt;I had to frum install Buby with the following so that it was setup to find the
proper system libs, etc.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;CFLAGS=&amp;quot;-std=c99 -I&#x2F;usr&#x2F;include -L&#x2F;usr&#x2F;lib -D_GNU_SOURCE&amp;quot; frum install 3.2.2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Upgrade PostgreSQL on Arch Linux</title>
        <published>2025-11-25T00:00:00+00:00</published>
        <updated>2025-11-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/upgrade-postgresql-on-arch-linux/"/>
        <id>https://drewdeponte.com/blog/upgrade-postgresql-on-arch-linux/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/upgrade-postgresql-on-arch-linux/">&lt;p&gt;The following are my notes for upgrading PostgreSQL on Arch Linux when I have installed PostgreSQL through the official package management system.&lt;&#x2F;p&gt;
&lt;p&gt;Stop the service with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl stop postgresql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The PostgreSQL upgrade process which is done with &lt;code&gt;pg_upgrade&lt;&#x2F;code&gt; requires having the previous version of postgres that created the &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;postgres&#x2F;data&lt;&#x2F;code&gt; directory as the format is locked to major versions. For example you might be upgrading from PostgreSQL 17 to 18. The &lt;code&gt;&#x2F;var&#x2F;lib&#x2F;postgres&#x2F;data&lt;&#x2F;code&gt; directory was originally setup with 17.&lt;&#x2F;p&gt;
&lt;p&gt;On Arch Linux the way that pacman works with upgrades is that it upgrades to the latest. So when you upgrade postgresql it will have only the latest version installed. But in order to facilitate upgrade with postgresql you have to have the previous version installed already.&lt;&#x2F;p&gt;
&lt;p&gt;To facilitate this Arch User Package&#x27;s available through &lt;code&gt;yay&lt;&#x2F;code&gt; provide a package for the previous version to be installed beside the current. The following facilitates installing these packages.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;yay -Sy postgresql-old-upgrade&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;yay -Sy postgis-old-upgrade # if you were using postgis with postgresql in the previous version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once these are installed we need to move the old data dir to a backup. This can be done as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -iu postgres&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -u postgres mv data data.old17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we need to create new initialized data directory for the new version of the database. Note: The &lt;code&gt;--no-data-checksums&lt;&#x2F;code&gt; option is something I added because the 17 data was done without data checksums and the &lt;code&gt;pg_upgrade&lt;&#x2F;code&gt; process doesn&#x27;t allow upgrading from a non-checksum on to checksum one.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -iu postgres&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;mkdir data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;initdb --no-data-checksums -D &#x2F;var&#x2F;lib&#x2F;postgres&#x2F;data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once you have the new data directory initialized then you can run the upgrade with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -iu postgres&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pg_upgrade -b &#x2F;opt&#x2F;pgsql-17&#x2F;bin -B &#x2F;usr&#x2F;bin -d data.backup -D data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you can start the service up again.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo systemctl start postgresql&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Some statistics are not transferred by pg_upgrade. Once we have started the new
server we should be able to do the following to handle this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo -iu postgres&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;usr&#x2F;bin&#x2F;vacuumdb --all --analyze-in-stages --missing-stats-only&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;usr&#x2F;bin&#x2F;vacuumdb --all --analyze-only&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pull Request Alternative Design Doc</title>
        <published>2025-02-07T00:00:00+00:00</published>
        <updated>2025-02-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pull-request-alternative-design-doc/"/>
        <id>https://drewdeponte.com/blog/pull-request-alternative-design-doc/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pull-request-alternative-design-doc/">&lt;p&gt;The following is a Design Doc for an idealized alternative to what is currently
the pull request work flow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;The feature branch&#x2F;pull request process is fundamentally broken a bunch of
different ways. This can be improved significantly with a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Patch
Stack&lt;&#x2F;a&gt; based workflow and tooling. But this is still far
from ideal as when you have dependent patches you can&#x27;t open a review for the
higher level patch until the dependent patch is integrated into mainline. A
stacked branch approach can elevate this but introduces other problems. Like,
having to manage branch names up front as well as manage the DAG (directed
acyclic graph) of the relationships between the branches. Also, it requires a
completely different service that companies have to pay for to extend the peer
review process, see &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;graphite.dev&quot;&gt;Graphite&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;idealized-goals&quot;&gt;Idealized Goals&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;open patch review requests as soon as completed, even if they are patches
that depend on another patch that has &lt;strong&gt;not&lt;&#x2F;strong&gt; been integrated into mainline
yet.&lt;&#x2F;li&gt;
&lt;li&gt;open patch review requests for a patch series communicating the dependence
and order of dependence.&lt;&#x2F;li&gt;
&lt;li&gt;don&#x27;t require an additional service&lt;&#x2F;li&gt;
&lt;li&gt;promote better reviews by actually having people use their own tools to review&lt;&#x2F;li&gt;
&lt;li&gt;support reviewing commits after they are integrated into mainline as well as
before they are integrated into mainline&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-thinking&quot;&gt;The Thinking&lt;&#x2F;h2&gt;
&lt;p&gt;The initial high level thought is, that if we were to use &lt;code&gt;git format-patch&lt;&#x2F;code&gt; or
similar to facilitate the review process. Then the review would be free
floating, or independent, even if it actually depended on another patch.&lt;&#x2F;p&gt;
&lt;p&gt;This can could be seen as a drawback. But in reality it is a benefit as it
effectively lifts the requirement of that dependency from the point of
requesting the review and moves it to the application of the patches.&lt;&#x2F;p&gt;
&lt;p&gt;This would allow the developer who wrote the patches to effectively request
review for each of them independently even if they had dependence of another
patch that has yet to be integrated into mainline.&lt;&#x2F;p&gt;
&lt;p&gt;This might not eliminate the concept of a patch series all together. But it
gives you flexibility and optionality in terms of workflow.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pr.pico.sh&quot;&gt;pr.pico.sh&lt;&#x2F;a&gt; is the closest thing to this that I have come
across. Though, it is a separate service that you would need to host.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Commit Creation</title>
        <published>2024-10-16T00:00:00+00:00</published>
        <updated>2024-10-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-commit-creation/"/>
        <id>https://drewdeponte.com/blog/git-commit-creation/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-commit-creation/">&lt;p&gt;When people are first learning Git they seem to learn something along the lines
of the following.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can create a commit by doing the following.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;staging a change with &lt;code&gt;git add &amp;lt;path&#x2F;to&#x2F;file&amp;gt;&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;create the commit with &lt;code&gt;git commit&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Or maybe something like.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can stage and commit in one shot with &lt;code&gt;git commit -a&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It seems that for the majority of people, once they learn the above about
creating commits, they just move on and never look back. In my opinion this
moving on and never looking back has massively delayed individual growth as
well as hindered the development of maintainable systems.&lt;&#x2F;p&gt;
&lt;p&gt;So with this article I am attempting to provide the ultimate guide to Git
commit creation. In the hopes that it will help newer developers understand
everything that they should be taking into consideration when creating a
commit. And who knows, maybe we will be lucky and a couple of those devs that
haven&#x27;t looked back, will slow down for a minute and think about creating Git
commits again.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-pressures&quot;&gt;The Pressures&lt;&#x2F;h2&gt;
&lt;p&gt;To really start to understand how we should be creating commits, and the
reasons why. We need to explore the pressures imparted on Git commit creation
from Git itself, the needs of our team members, both right now and in the
future, as well as the needs of our selves, both right now and in the future.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;anatomy-of-a-commit&quot;&gt;Anatomy of a Commit&lt;&#x2F;h3&gt;
&lt;p&gt;To start we really need to understand what commits are in Git. Technically from
a Git perspective a commit is a snapshot of a project&#x27;s contents, files &amp;amp;
folders, at a moment in time combined with a message.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;snapshots-diffs&quot;&gt;Snapshots &amp;amp; Diffs&lt;&#x2F;h4&gt;
&lt;p&gt;In the Git repository these snapshots are related to one another through the
concept of ancestry. Meaning that generally each commit has one or more parent
commits. These parent commits are the ancestors of the commit.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Side Note:&lt;&#x2F;em&gt; There is technically a special case of commit that doesn&#x27;t have
any parents. Commonly you will see this with the first commit in a repository.
However, you can actually create multiple of these within a repository if you
like. If you are curious this is generally referred to as an &quot;orphan&quot; branch
and can be done with &lt;code&gt;git checkout --orphan&lt;&#x2F;code&gt;. See the git-checkout man page
for more details if you are interested.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;So we have snapshots with messages, and they have ancestors. What is the big
deal?&lt;&#x2F;p&gt;
&lt;p&gt;Well, the natural thing that falls out of a snapshot having an ancestor is that
there is a difference (a.k.a. diff) that exists between two snapshots. In fact
this is such a prominent mental model that when you do a &lt;code&gt;git show &amp;lt;sha&amp;gt;&lt;&#x2F;code&gt; it
shows you the difference between the ancestor commit&#x27;s snapshot and the
snapshot of the commit identified by the given &lt;code&gt;&amp;lt;sha&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A lot of people choose to simply think about commits as diffs even though they
are actually storing full snapshots of the project in the Git repository.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;commit-message&quot;&gt;Commit Message&lt;&#x2F;h4&gt;
&lt;p&gt;The message portion of the commit is an extremely important and valuable piece
of information, that if used properly, facilitates code reviews, as well as
short-term and long-term maintenance and understanding of a code base.&lt;&#x2F;p&gt;
&lt;p&gt;Git actually has an official format for Git commit messages, which is as
follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Short summary of change (&amp;lt;= 50 chars in len)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One or more paragraphs of text.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you are working with any editor worth its salt. It will have support
specifically for the Git commit message format and help you abide by the
constraints of this format.&lt;&#x2F;p&gt;
&lt;p&gt;Abiding by this format is important as it will make sure that our commit
messages work within Git as a tool and it&#x27;s expectations.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;commit-characteristics&quot;&gt;Commit Characteristics&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to understanding the anatomy of a commit, their associated
requirements and implications, it is also important to understand the expected
characteristics of a commit within Git.&lt;&#x2F;p&gt;
&lt;p&gt;When you are making a commit. Two characteristics that are important to make
sure you take into consideration are that the commit is &lt;strong&gt;buildable&lt;&#x2F;strong&gt; and
&lt;strong&gt;testable&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Buildable&lt;&#x2F;strong&gt; simply means that the snapshot that will be captured by the
commit, is able to build without failure, using the build system of the
project. This is applicable not only to compiled languages but also can be
conceptually extended to include other tooling like linting and formatting.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Testable&lt;&#x2F;strong&gt; simply means that the snapshot that will be captured by the
commit, is able to successfully run the automated tests without failure.&lt;&#x2F;p&gt;
&lt;p&gt;These are crucial for a number of reasons. For one, Git provides tools that
depend on these characteristics being met. For example &lt;code&gt;git bisect&lt;&#x2F;code&gt;, an
extremely valuable tool that aids in automating finding a commit that
introduced a particular issue. If your commits aren&#x27;t &lt;strong&gt;buildable&lt;&#x2F;strong&gt; and
&lt;strong&gt;testable&lt;&#x2F;strong&gt; &lt;code&gt;git bisect&lt;&#x2F;code&gt; doesn&#x27;t work in an automated fashion.&lt;&#x2F;p&gt;
&lt;p&gt;When your commits are &lt;strong&gt;not&lt;&#x2F;strong&gt; testable your team will quickly lose faith in the
value that the test suite is providing, which will generally result in people&#x27;s
testing practices waning, likely due to the Broken Windows Theory.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that if your commits are &lt;strong&gt;not&lt;&#x2F;strong&gt; buildable your teammates will quickly
become irritated with you because your commits will be impeding them from
making progress on the things they are trying to push forward.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;scope-intent&quot;&gt;Scope &amp;amp; Intent&lt;&#x2F;h3&gt;
&lt;p&gt;At this point we know that that commits have a snapshot of the project and an
associated message that should abide by the official format, and that the
commit should be &lt;strong&gt;Buildable&lt;&#x2F;strong&gt; and &lt;strong&gt;Testable&lt;&#x2F;strong&gt;. However, we don&#x27;t have any
real guidance in terms of what should be included in the snapshot and the
commit message.&lt;&#x2F;p&gt;
&lt;p&gt;This is where scope and intent come into play. Scope and intent are the key to
one of the most important software engineering practices of today,
understanding and properly defining commits.&lt;&#x2F;p&gt;
&lt;p&gt;When we are making changes to software it is crucial to think about the
&lt;strong&gt;intent&lt;&#x2F;strong&gt; behind the change. This can also be thought of as simply answering
the question, &quot;Why was this change made?&quot; However, thinking about the
&lt;strong&gt;intent&lt;&#x2F;strong&gt; alone is not enough. We also need to think about the &lt;strong&gt;scope&lt;&#x2F;strong&gt; in
terms of the various irreducible (a.k.a. atomic) components of the proposed
change. This is due to the fact that the &lt;strong&gt;intents&lt;&#x2F;strong&gt; of a change are the
combination of the individual &lt;strong&gt;intent&lt;&#x2F;strong&gt; of each irreducible component.&lt;&#x2F;p&gt;
&lt;p&gt;This sounds a bit theoretical at this point. But it is actually something that
is quite concrete and is very easy to see when simply looking at a pull
request&#x27;s changes. All we have to do is ask ourselves the question, &quot;Why was
this change made?&quot;, and then as we are looking at the code, validate whether
that specific code change aligns with that intent.&lt;&#x2F;p&gt;
&lt;p&gt;I recently reviewed a pull request that was created to tackle a particular bug.
However, when looking at the pull request there were a lot more changes than I
expected to see. I wasn&#x27;t sure why those changes were there, but they didn&#x27;t
seem to be required to fix the bug.&lt;&#x2F;p&gt;
&lt;p&gt;At this point there is no way anyone should sign off on this pull request as we
really have no idea what it is doing, let alone, why these changes were made.&lt;&#x2F;p&gt;
&lt;p&gt;So I talked to the developer that made the pull request and through
conversation we determined that the changes that weren&#x27;t specifically fixing
the bug were made for a handful of different reasons, to eliminate duplication,
to fix linting errors&#x2F;warnings, and to clean up a toggle.&lt;&#x2F;p&gt;
&lt;p&gt;It looks like we have a bit of a miss alignment here in terms of &lt;strong&gt;intent&lt;&#x2F;strong&gt;
because we have code that exists with intents other than &lt;strong&gt;fix the bug&lt;&#x2F;strong&gt;. More
accurately, we have a bit of &lt;strong&gt;scope creep&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we look at the pull request visually in terms of &lt;strong&gt;intents&lt;&#x2F;strong&gt; and &lt;strong&gt;scope&lt;&#x2F;strong&gt;
it would currently look something like the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-commit-creation&#x2F;scope-and-intent-001.png&quot; alt=&quot;Visual of commit with individual intents but one scope&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the above we can visually see that in this case the current scope of the
commit involves the following intents.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Commit A
&lt;ul&gt;
&lt;li&gt;literal bug fix&lt;&#x2F;li&gt;
&lt;li&gt;clean up toggle&lt;&#x2F;li&gt;
&lt;li&gt;fix lints&lt;&#x2F;li&gt;
&lt;li&gt;correct duplication&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;But, it is a single commit and that commit only has one scope. You could
theoretically argue that you can include in the commit message details
describing that the commit addresses all these intents. But that would not
address the issue that when looking at the code you wouldn&#x27;t be able to
distinguish if a line of code was changed to fix a linting rule or changed to
address the duplication, etc.&lt;&#x2F;p&gt;
&lt;p&gt;So a much better approach is to create separate commits, one for each of the
intents. This binding between an intent and a commit, which has a singular
scope, is a crucial underpinning to building maintainable software systems
efficiently.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-commit-creation&#x2F;scope-and-intent-002.png&quot; alt=&quot;Visual of commits with paired individual intents and scopes&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The above visually represents each scope as a different commit paired with each
respective intent. So we would effectively have the following commits.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Commit A: literal bug fix&lt;&#x2F;li&gt;
&lt;li&gt;Commit B: clean up toggle&lt;&#x2F;li&gt;
&lt;li&gt;Commit C: fix lints&lt;&#x2F;li&gt;
&lt;li&gt;Commit D: correct duplication&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This fundamentally makes the peer review process go much quicker as the commits
are focused on a singular narrowed intent, and provide the critical context in
the commit message.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;intent-architecture&quot;&gt;Intent &amp;amp; Architecture&lt;&#x2F;h4&gt;
&lt;p&gt;As the old adage says, &quot;There&#x27;s more than one way to skin a cat.&quot; That
statement is true in the context of defining intents as well. However, that
doesn&#x27;t mean that all the ways of defining intents are equal.&lt;&#x2F;p&gt;
&lt;p&gt;For example. We could take and break out our commits for a project as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;initial set up of listing action v2&lt;&#x2F;li&gt;
&lt;li&gt;added api calls, and computed variables to allow for checking which CTA to display&lt;&#x2F;li&gt;
&lt;li&gt;finished functionality for all of the child components&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If we look at the summaries we can maybe draw the following diagram based on
understanding.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-commit-creation&#x2F;intent-and-architecture-non-arch-bound.png&quot; alt=&quot;Visual of architecture diagram derived from intent summaries not bound to arch concepts&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we just look at the summaries and diagram above we can gather the following.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;That there is some initial setup. Though we are not sure what that is
exactly without looking deeper.&lt;&#x2F;li&gt;
&lt;li&gt;That some API calls and computed variables were added to facilitate checking
which CTA to display. But we don&#x27;t have any information about what
component(s) are responsible for&#x2F;involved in this.&lt;&#x2F;li&gt;
&lt;li&gt;We know some sort of work has been done to finish the functionality for all
the child components. But we don&#x27;t know what that is without looking
deeper.&lt;&#x2F;li&gt;
&lt;li&gt;And we know that there is some concept of listing action v2 but don&#x27;t really
understand how it relates to anything else.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;The above is technically broken out into intentions. The first intention was,
&quot;setup listing action v2&quot;, the second was &quot;add api calls &amp;amp; computed variables to
allow for checking which CTA to display&quot;, and the third was &quot;finishing up some
functionality&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;It is worth noting that the second intention has a smell as it has the keyword,
&lt;strong&gt;and&lt;&#x2F;strong&gt;, in the description. Hinting there are probably multiple intents within
the scope of that commit.&lt;&#x2F;p&gt;
&lt;p&gt;Despite multiple intents in that scope, this is definitely a step in the right
direction as the commits are broken out into intentions.&lt;&#x2F;p&gt;
&lt;p&gt;But we can do much better with a slight shift in our thinking about intents.&lt;&#x2F;p&gt;
&lt;p&gt;If we add the constraint that our intents should generally be related to
application architecture concepts. Things like modules, classes, methods,
functions, services, etc. We would have likely defined the intents and commits
as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;add can apply, reason props &lt;code&gt;ProfessionalViewListing&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;mod &lt;code&gt;ProfessionalListing&lt;&#x2F;code&gt; API client to map props&lt;&#x2F;li&gt;
&lt;li&gt;add listing actions components (e.g. &lt;code&gt;AcceptShift&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;add &lt;code&gt;ListingActionV2&lt;&#x2F;code&gt; to show proper action component&lt;&#x2F;li&gt;
&lt;li&gt;register the &lt;code&gt;listing_action_v2_fe&lt;&#x2F;code&gt; toggle&lt;&#x2F;li&gt;
&lt;li&gt;mod the &lt;code&gt;Listing&lt;&#x2F;code&gt; view to show &lt;code&gt;ActionV2&lt;&#x2F;code&gt; or &lt;code&gt;ActionV1&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is fantastic as now we have lots of information just from the summaries of
these commits. In fact, it gives us enough information to draw the following
diagram of the architecture involved.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-commit-creation&#x2F;intent-and-architecture-arch-bound.png&quot; alt=&quot;Visual of architecture diagram derived from intent summaries bound to arch concepts&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So from the above diagram we can see that the commit summaries containing
intent around different architectural concepts, as an approach, has provided us
with a lot more value in terms of understanding changes as well as the code
base itself.&lt;&#x2F;p&gt;
&lt;p&gt;In particular, we know that there is some sort of collection of Listing Action
components and that the &lt;code&gt;ListingActionV2&lt;&#x2F;code&gt; component is responsible for choosing
which one to render based on some criteria. We also know that the &lt;code&gt;Listing View&lt;&#x2F;code&gt; exists and that it conditionally chooses to render either the
&lt;code&gt;ListingActionV1&lt;&#x2F;code&gt; component or the &lt;code&gt;ListingActionV2&lt;&#x2F;code&gt; component based on the
registered &lt;code&gt;listing_action_v2_fe&lt;&#x2F;code&gt; toggle most likely. We also know that there
is a &lt;code&gt;ProfessionalViewListing&lt;&#x2F;code&gt; that received the &lt;code&gt;can_apply&lt;&#x2F;code&gt; and &lt;code&gt;reason&lt;&#x2F;code&gt;
properties. As well as that there was a &lt;code&gt;ProfessionalListingApiClient&lt;&#x2F;code&gt; which
was modified to map properties, which are most likely the properties that were
just added in the previous commit.&lt;&#x2F;p&gt;
&lt;p&gt;We were almost able to build a complete architectural diagram expressing the
relationships between the various components involved just from the commit
summaries. The one thing we are missing is just how the API client relates
to the rest of the architectural concepts.&lt;&#x2F;p&gt;
&lt;p&gt;It is amazing how valuable this is and how much it facilitates rapidly gaining
context around an area of effort. So, I hope this makes it clear that even
though we can define intents in a bunch of different ways. We generally should
define them based on architectural concepts due to the massive gains that we
get.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;fallback-on-scope-intent&quot;&gt;Fallback on Scope &amp;amp; Intent&lt;&#x2F;h4&gt;
&lt;p&gt;Now, you may have noticed that I said aligning your intent is generally the
right thing to do. That is because there are scenarios where it may not be
fitting. An example, where you would likely want to fall back to simply using
Scope &amp;amp; Intent to define your commit, is when you are switching from not having
automated formatting in a project to having automated formatting.&lt;&#x2F;p&gt;
&lt;p&gt;In this case you could try and argue that you could format sections of the code
based on architectural concepts. Though, generally this isn&#x27;t practical due to
the fact that the tooling doesn&#x27;t make it easy to apply auto formatting only to
an architectural concept within the code, and secondly because most of the time
people don&#x27;t have a solid well organized architecture to help with this.&lt;&#x2F;p&gt;
&lt;p&gt;So instead you create a commit that formats all the files in the code base. It
could be thousands of files, but you get it done in one fell swoop. And you
make the summary of the commit clearly communicate the scope &amp;amp; intent of
formatting all the files.&lt;&#x2F;p&gt;
&lt;p&gt;A similar scenario would be enabling linting across a project that didn&#x27;t have
linting before.&lt;&#x2F;p&gt;
&lt;p&gt;In my experience scenarios that are incompatible with architectural alignment
are pretty rare. So we should always make sure we are putting effort in to
strive for architectural alignment and only fall back to solely scope and
intent after exhausting all the ways to facilitate architectural alignment.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;more-than-a-summary&quot;&gt;More than a summary&lt;&#x2F;h3&gt;
&lt;p&gt;At this point we have great guidance in terms using scope &amp;amp; intent to define
our commits and their commit summaries. And we have learned how valuable a
commit&#x27;s summary can be when the commit is defined with a singular intent
around architectural components. However, the commit summaries are limited to
50 characters, or less. Which makes it difficult to fully communicate the
intention of a change. Let alone provide any additional information about the
approach that was taken and why.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, the Git commit message format supports providing any number of
paragraphs of detail as long as they have blank lines separating them, and they
are hard wrapped to 72 characters. This allows us to define our own Git commit
format based on the official Git commit format plus our learnings from above.&lt;&#x2F;p&gt;
&lt;p&gt;The following is a Git commit message format I have refined over the past 24+
years of development experience.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Short summary of change (&amp;lt;= 50 chars in len)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One or more paragraphs explaining the INTENTION &amp;amp; REASON&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;for the change. (hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One or more paragraphs explaining the APPROACH taken to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;attempt to achieve the above described INTENTION or a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;portion of the INTENTION. (hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Associated Ticket Identifiers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The short summary should describe the change. I like to think of this as the
&lt;strong&gt;what&lt;&#x2F;strong&gt; of the commit. It is valuable to give a high level understanding of
what change the commit represents.&lt;&#x2F;p&gt;
&lt;p&gt;The intention &amp;amp; reason paragraph on the other hand is by far the most valuable
part of the commit message as it is something that is &lt;strong&gt;impossible&lt;&#x2F;strong&gt; to get
from simply reading the code. I like to think of this as the &lt;strong&gt;why&lt;&#x2F;strong&gt; of the
commit.&lt;&#x2F;p&gt;
&lt;p&gt;Following that is the paragraph covering the approach. This is something we can
kind of get from reading the code, but not entirely. So we include this as
additional context in the commit message. You can think of this as the &lt;strong&gt;how&lt;&#x2F;strong&gt;
of the commit.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly, we provide any associated ticket references. This facilitates ticketing
systems tracking commits and their association to tickets in the ticketing
systems. This is an extremely beneficial thing to include as it facilitates
going back and finding even more context about a change.&lt;&#x2F;p&gt;
&lt;p&gt;So for every commit we provide the &lt;strong&gt;what&lt;&#x2F;strong&gt;, &lt;strong&gt;why&lt;&#x2F;strong&gt;, &lt;strong&gt;how&lt;&#x2F;strong&gt;, and &lt;strong&gt;associated
tickets&lt;&#x2F;strong&gt; so that peers reviewing the changes have all the associated context
and so that in the future if we, or another dev, need to understand the intent
and context of a change we can easily get it from the commit message.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;proof-of-work&quot;&gt;Proof of Work&lt;&#x2F;h3&gt;
&lt;p&gt;When you create your commits taking the above into consideration another
natural benefit appears. It is something that prominent development teams, like
the Linux Kernel and Git development teams, talk about in respect to their Git
commit requirements. It is this concept of Proof of Work.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that when you submit a series of commits in a particular order, the
commits and the order should communicate the steps you are taking to accomplish
the higher level goal &amp;amp; intent of the pull request or patch series.&lt;&#x2F;p&gt;
&lt;p&gt;Think of the commits being the equivalent of writing out the steps you
performed when solving a math problem as a kid. In fact, it carries the same
benefits. It helps you and others see how you got to the resulting answer. And
if that answer isn&#x27;t 100% correct, it helps you or others see the various steps
you took and be able to investigate or validate each one of them.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, if we are following the practice above of binding scope and
intent to architecture, then it also provides an understanding of how the
greater intent was accomplished in the terms of the application architecture.
This is extremely valuable from both a peer review standpoint, and from the
standpoint of trying to understand changes at a later point in time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tactics&quot;&gt;Tactics&lt;&#x2F;h2&gt;
&lt;p&gt;We have covered some of the details about what commits are, what their contents
and message should contain, and the arguments backing them. However, we haven&#x27;t
really started covering how you actually go about creating commits like this.
So let&#x27;s shift more into the mental hurdles and the tactical skills needed to
actually create better commits.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;commit-permanence&quot;&gt;Commit Permanence&lt;&#x2F;h3&gt;
&lt;p&gt;One of the biggest hurdles people seem to have when shifting from making
horrible commits to making great commits, is breaking this misconception that
commits are permanent the moment you create them.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t know where this misconception comes from. But in my experience it is
quite prevalent. But it is clear that it doesn&#x27;t come from Git proper. You can
see this fairly quickly just by looking at some of the operations that Git
facilitates you performing on commits.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git commit --amend&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit --fixup reword&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit --fixup amend&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit --squash&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit --reset-author&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit --author&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The above is all just in the &lt;code&gt;git commit&lt;&#x2F;code&gt; command. There is even more once we
look into &lt;code&gt;git rebase&lt;&#x2F;code&gt; and other commands.&lt;&#x2F;p&gt;
&lt;p&gt;From looking at the above set of commands alone, it is clear from a Git
perspective, that commits are made to be modified &amp;amp; mutated at least up until
some point in time. It is also clear that, that point in time is &lt;strong&gt;not&lt;&#x2F;strong&gt; at the
moment of creation of the commit.&lt;&#x2F;p&gt;
&lt;p&gt;So what is that moment of time when a commit should become permanent?&lt;&#x2F;p&gt;
&lt;p&gt;I would argue that it is the moment that a commit is integrated into the
mainline branch. Prior to that moment the commits should be free to be refined
and reworked.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;isn-t-rewriting-history-bad&quot;&gt;Isn&#x27;t Rewriting History Bad&lt;&#x2F;h4&gt;
&lt;p&gt;If we take that stance though then we have to be ok rewriting history, even
once it has been shared. And isn&#x27;t rewriting shared history a big no no?&lt;&#x2F;p&gt;
&lt;p&gt;Yes and no. Let me explain.&lt;&#x2F;p&gt;
&lt;p&gt;There are cases where it is giant pain in the butt and can be extremely
disruptive to other developers if you rewrite shared history. One such scenario
is if you were to rewrite the history in the published mainline of a
repository. In general, it is bad form to rewrite the history of mainline
of a repository. Although, sometimes it is necessary and worth the disruption,
e.g. to strip accidentally shared credentials, etc.&lt;&#x2F;p&gt;
&lt;p&gt;So just like everything else in engineering. There are pros and cons. We just
need to make sure we understand the pros and cons and choose the path that fits
our needs the best.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;rewrite-pull-request-history&quot;&gt;Rewrite Pull Request History&lt;&#x2F;h5&gt;
&lt;p&gt;If we look at the scenario of rewriting history in a shared pull-request
branch.&lt;&#x2F;p&gt;
&lt;p&gt;It enables us to have commits that can communicate a ton of context and
value in terms of architecture. Additionally, it facilitates reverting specific
targeted changes if necessary. As well as answering questions about the intent
of changes over time in relation to architectural concepts. And bisecting to
identify a specific change that introduced an issue and what the intention of
that change was. Just to name a few.&lt;&#x2F;p&gt;
&lt;p&gt;At the same time it has the drawback that it can break direct code
collaboration if there isn&#x27;t communication between the parties. Generally
though, there isn&#x27;t much direct code collaboration on pull requests as the
author is usually the one making the changes. And if the reviewer wants to make
a change and push it up to the pull request branch. All they really need to do
is let the pull request author know that they have pushed up a change, so they
can manage integrating it into the final commit.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;squash-merge&quot;&gt;Squash &amp;amp; Merge&lt;&#x2F;h5&gt;
&lt;p&gt;Another approach is to take a hard-lined stance about not rewriting any shared
history, including pull requests. This means that the only way we can bring in
changes from mainline is to back merge mainline into our branch. It also means
that we can&#x27;t refine our commits once they are pushed up to a pull request. In
turn requiring us to add additional commits to the pull request that are not
logically structured and are not representative of the application architecture
or the intents at all.&lt;&#x2F;p&gt;
&lt;p&gt;This in turn results in a bunch of commits, that are meaningless to the Git
history existing within the pull request branch. And given that these commits
are generally &lt;strong&gt;not buildable&lt;&#x2F;strong&gt; &amp;amp; &lt;strong&gt;not testable&lt;&#x2F;strong&gt; they result in breaking &lt;code&gt;git bisect&lt;&#x2F;code&gt; and other functionality.&lt;&#x2F;p&gt;
&lt;p&gt;To help mitigate this people will do a &quot;Squash &amp;amp; Merge&quot; in which all the
commits within the pull request branch are squashed together into a singular
commit. This helps resolve the &lt;strong&gt;buildable&lt;&#x2F;strong&gt; &amp;amp; &lt;strong&gt;testable&lt;&#x2F;strong&gt; characteristics in
the majority of cases. However, we have completely lost the ability to revert
targeted changes and the ability to even understand the intention of the
changes from an architectural perspective.&lt;&#x2F;p&gt;
&lt;p&gt;The only thing we have gained from this is &quot;smoother direct code
collaboration&quot;. Meaning that in the more rare scenarios when you are reviewing
a pull request, and you want to push a change up to it. You don&#x27;t need to let
the author know that you are pushing a change up to their branch. Although you
generally do anyway.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;the-choice&quot;&gt;The Choice&lt;&#x2F;h5&gt;
&lt;p&gt;The choice is pretty clear to me as the overhead of pinging the author via
messaging is trivial, as a cost for rewriting pull-request history. And it
unlocks a wealth of benefits. Enabling our commit&#x27;s moment of permanence to be
when the commit is integrated into the upstream mainline.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to get a deeper understanding of this in relation to the Git tree.
Check out my article, &lt;a href=&quot;&#x2F;blog&#x2F;when-to-rewrite-git-history&#x2F;&quot;&gt;When to rewrite Git
history&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;but-how-do-we-do-this&quot;&gt;But How do we do this?&lt;&#x2F;h3&gt;
&lt;p&gt;You might be thinking. How do I actually accomplish this?&lt;&#x2F;p&gt;
&lt;h4 id=&quot;learn-git&quot;&gt;Learn Git&lt;&#x2F;h4&gt;
&lt;p&gt;Well the extremely short answer is simply, learn more about Git.&lt;&#x2F;p&gt;
&lt;p&gt;It really boils down to learning a few commands, &lt;code&gt;git add -p&lt;&#x2F;code&gt;, &lt;code&gt;git commit --amend&lt;&#x2F;code&gt;, and &lt;code&gt;git rebase -i&lt;&#x2F;code&gt;. It is worth noting that it is crucial that you
have a solid understanding of Git commits and the Git commit tree in general
when truly understanding these commands.&lt;&#x2F;p&gt;
&lt;p&gt;The following is an outline of the related
operations you would perform with each of those commands and links to
respective documentation or guides.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; I included links to guides for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt;, a
Git extension that facilitates a patch stack workflow with Git, because it
documents the main commit mutation operations with &lt;code&gt;gps rebase&lt;&#x2F;code&gt; which is really
just a convenience mechanism for &lt;code&gt;git rebase -i&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;creating multiple commits from uncommitted changes
&lt;ul&gt;
&lt;li&gt;Add hunks instead of entire file &lt;code&gt;git add -p &amp;lt;patch&#x2F;to&#x2F;file&amp;gt;&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-add#Documentation&#x2F;git-add.txt---patch&quot;&gt;git add -p manpage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Use a Git GUI to stage individual lines or selections
&lt;ul&gt;
&lt;li&gt;My article on &lt;a href=&quot;&#x2F;blog&#x2F;git-add-patch-wont-split&#x2F;&quot;&gt;git add -p won&#x27;t split&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;amending a commit &lt;code&gt;git commit --amend&lt;&#x2F;code&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-commit#Documentation&#x2F;git-commit.txt---amend&quot;&gt;git commit --amend manpage&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git rebase -i&lt;&#x2F;code&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-Branching-Rebasing&quot;&gt;ProGit Book - 3.6 Branching - Rebasing&lt;&#x2F;a&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-rebase#Documentation&#x2F;git-rebase.txt--i&quot;&gt;git rebase -i manpage&lt;&#x2F;a&gt;
&lt;ul&gt;
&lt;li&gt;edit a commit &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;edit-a-patch&quot;&gt;Git Patch Stack: Docs - Edit a patch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;reword a commit message
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git rebase -i&lt;&#x2F;code&gt; and mark for &lt;code&gt;reword&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;reorder commits &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;reorder-patches&quot;&gt;Git Patch Stack: Docs - Reorder patches&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;drop a commit &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;drop-a-patch&quot;&gt;Git Patch Stack: Docs - Drop a patch&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;add a commit in the middle &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;add-patch-in-the-middle&quot;&gt;Git Patch Stack: Docs - Add a patch in the middle&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;fix a commit up into another commit &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;combine-multiple-patches&quot;&gt;Git Patch Stack: Docs - Combine multiple patches&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;squash commits together &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;combine-multiple-patches&quot;&gt;Git Patch Stack: Docs - Combine multiple patches&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;split a commit up into multiple commits
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-rebase#_splitting_commits&quot;&gt;git rebase manpage splitting commits&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;My article on &lt;a href=&quot;&#x2F;blog&#x2F;git-splitting-commits&#x2F;&quot;&gt;Git - Splitting Commits&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;guides&#x2F;split-a-patch-up&quot;&gt;Git Patch Stack: Docs - Split a patch up&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;wip-commits&quot;&gt;WIP Commits&lt;&#x2F;h4&gt;
&lt;p&gt;In addition to learning Git. There is another concept that is extremely
valuable now that you are living in this world of commits that you evolve over
time. And that is the WIP (Work in Progress) commit.&lt;&#x2F;p&gt;
&lt;p&gt;This is simply a convention of prefixing the commit summary with &lt;code&gt;WIP:&lt;&#x2F;code&gt; to let
ourselves know that the commit still needs further refinement before we submit
it in a pull request or integrate it into mainline.&lt;&#x2F;p&gt;
&lt;p&gt;Once we have refined it to the point that we are happy we simply update the
commit summary, removing the &lt;code&gt;WIP:&lt;&#x2F;code&gt; prefix. In turn finalizing our commit
conceptually.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;commit-message-template&quot;&gt;Commit Message Template&lt;&#x2F;h4&gt;
&lt;p&gt;Beyond that. There are things that are just hard to remember. The
various parts of the commit message can be one of those things. Luckily Git
helps us out by providing support for commit message templates via the
&lt;code&gt;commit.template&lt;&#x2F;code&gt; configuration setting.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to set this up you can do so by running the following command.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git config --global commit.template ~&#x2F;.gitmessage.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above configures Git to look for the commit message at &lt;code&gt;~&#x2F;.gitmessage.txt&lt;&#x2F;code&gt;.
This template file is simply a text file that is loaded up into the editor when
you go to create a commit.&lt;&#x2F;p&gt;
&lt;p&gt;The contents of my &lt;code&gt;~&#x2F;.gitmessage.txt&lt;&#x2F;code&gt; are as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Short summary of change (the what) ( &amp;lt;= 50 chars )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# INTENTION of the change &amp;amp; REASON for change&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# (Hard wrapped at 72 chars) &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# APPROACH taken &amp;amp; WHY in relation to attempting to achieve INTENTION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# (Hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Associated Ticket Identifers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The layout I provided is based on making it efficient to enter. Starting out
when it loads it in the editor it drops you into the top left corner ready to
start writing your 50 character or less summary.&lt;&#x2F;p&gt;
&lt;p&gt;It is important to realize that any line in the Git commit message starting
with a &lt;code&gt;#&lt;&#x2F;code&gt; is considered a comment and will &lt;strong&gt;not&lt;&#x2F;strong&gt; be included in the final
commit message. This means that I don&#x27;t actually need to replace any of these
comments. Instead, I just add the respective content below each comment.
The one exception to this is the short summary which is added above the comment
instead of below. It is also worth mentioning that you will want to keep a
blank line between each of these sections.&lt;&#x2F;p&gt;
&lt;p&gt;There are many more things you can include in your commit messages and the
template to help you. Some people add explicit change log entries to their
commit messages that are targeted at the consumers of the product rather than
the developers. Others manage sign-off from peer developers through commit
message standards they have defined, etc.&lt;&#x2F;p&gt;
&lt;p&gt;In my opinion, all these things can be valuable, and should be considered, but
the above template really outlines the core that should always be present.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;buildable-testable-enforcement&quot;&gt;Buildable &amp;amp; Testable Enforcement&lt;&#x2F;h4&gt;
&lt;p&gt;The &lt;strong&gt;buildable&lt;&#x2F;strong&gt; and &lt;strong&gt;testable&lt;&#x2F;strong&gt; characteristics are another thing that are
easy to let slip by if we are just manually verifying them.&lt;&#x2F;p&gt;
&lt;p&gt;To help us hold to these requirements some people set up a Git pre-commit hook
to make sure that each commit is buildable &amp;amp; testable prior to commit creation.&lt;&#x2F;p&gt;
&lt;p&gt;In my experience this isn&#x27;t the ideal enforcement mechanism because it assumes
that commits are final and that you aren&#x27;t going to iterate on them or evolve
them. Which we have seen above is pretty damn important.&lt;&#x2F;p&gt;
&lt;p&gt;A more appropriate hook would be a hook that is triggered when you want to
either request that someone review a commit or integrate a commit. In turn
helping make sure that any commit you are going to share either via integration
into mainline or via pull request&#x2F;patch is buildable and testable. Git doesn&#x27;t
natively have such a hook. But if you use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; it easily
supports this via it&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;tool&#x2F;hooks&quot;&gt;isolate_post_checkout
hook&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You might be thinking. I don&#x27;t need to worry about this. We have a CI
(Continuous Integration) service that makes sure my pull requests are both
buildable and testable. But in general this isn&#x27;t a valid enforcement mechanism
as most teams don&#x27;t strictly only create pull requests consisting of a single
commit.&lt;&#x2F;p&gt;
&lt;p&gt;So if we make sure that our commits are buildable and testable it in turn
guarantees that our pull requests are buildable and testable. However, if we
only make sure that our pull request is buildable and testable it is quite
possible, if not likely, that one of the commits in the pull request in &lt;strong&gt;not&lt;&#x2F;strong&gt;
buildable or testable.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;outside-in&quot;&gt;Outside-In&lt;&#x2F;h4&gt;
&lt;p&gt;Outside-In is an engineering practice in which you drive changes from the
outermost thing first and work your way inward. Generally, the outermost thing
is the UI layer.&lt;&#x2F;p&gt;
&lt;p&gt;The massive benefit of this is that you always end up building only what you
need to build as it is driven by the need of the layer above. This is in
opposition to inside-out or middle-out development in which you try and guess
the needs of the outer layers and build the inner&#x2F;middle layers first.
Generally this results in your guesses being not quite right and having to do
rework or even worse including additional complexity and functionality that
isn&#x27;t needed by the layers above.&lt;&#x2F;p&gt;
&lt;p&gt;Outside-In is extremely useful in helping you think about the architecture
concepts. As you are effectively working from the outermost architectural
concepts, to the innermost architectural concepts, and then working your way
back up from the inside-out, connecting each of the layers.&lt;&#x2F;p&gt;
&lt;p&gt;Using &lt;code&gt;WIP&lt;&#x2F;code&gt; commits can aid this process as your outer layers can start as
&lt;code&gt;WIP&lt;&#x2F;code&gt; commits until you reach that innermost layer which ends up being a
complete logical chunk. Then as you work your way back up the layers connecting
them to the layer below you are effectively finalizing them and getting rid of
the &lt;code&gt;WIP&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To get a better understanding of Outside-In with an example you can check out
my article, &lt;a href=&quot;&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using Git&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;At this point you should hopefully have enough knowledge and context to be able
to start creating meaningful, logically chunked, buildable and testable commits
that are bound to scope, intent and architecture. Resulting in a valuable Git
repository history that will aid you through the short-term and long-term
maintenance and development of the project.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>When to rewrite Git history?</title>
        <published>2024-06-13T00:00:00+00:00</published>
        <updated>2024-06-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/when-to-rewrite-git-history/"/>
        <id>https://drewdeponte.com/blog/when-to-rewrite-git-history/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/when-to-rewrite-git-history/">&lt;p&gt;Ok, so let&#x27;s talk about Git and this &quot;rule&quot; that people often get attached to,
&quot;Don&#x27;t rewrite history once it is shared!&quot;&lt;&#x2F;p&gt;
&lt;p&gt;There is definitely some wisdom in this &quot;rule&quot;. However, following this &quot;rule&quot;
religiously also has some side effects. And it is worth understanding those in
more depth, as well as understanding any alternatives and what their pros &amp;amp;
cons might be.&lt;&#x2F;p&gt;
&lt;p&gt;When you follow this rule we have to ask, how do the branches we are working on
get updated with changes other developers have already integrated into &lt;code&gt;main&lt;&#x2F;code&gt;?
Well, there are a couple of approaches we can use depending on our situation.
To explore these, let&#x27;s assume we start with a Git tree that looks as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 9cabcd2 - (HEAD -&amp;gt; main, origin&#x2F;main) commit C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 6327c81 - commit B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* b68a192 - commit A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now let&#x27;s assume we have created some changes in a branch locally that we
&lt;strong&gt;have not&lt;&#x2F;strong&gt; pushed up to the remote yet. And that someone else has integrated
another change into &lt;code&gt;main&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* a0aca6f - (main, origin&#x2F;main) commit G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * fe06e90 - (HEAD -&amp;gt; feature&#x2F;x) commit F&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * 81312b5 - commit E&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * f09acea - commit D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&#x2F; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 9cabcd2 - commit C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 6327c81 - commit B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* b68a192 - commit A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;One option we have to include the new change in &lt;code&gt;main&lt;&#x2F;code&gt; as part of our
&lt;code&gt;feature&#x2F;x&lt;&#x2F;code&gt; branch is to use &lt;code&gt;git rebase&lt;&#x2F;code&gt;. This can effectively take the
commits from our branch and replay them on top of the commit that was added to
&lt;code&gt;main&lt;&#x2F;code&gt;. Our tree would look as follows after doing this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* ae46190 - (HEAD -&amp;gt; feature&#x2F;x) commit F&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 512b2ba - commit E&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* d09efea - commit D&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* a0aca6f - (main, origin&#x2F;main) commit G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 9cabcd2 - commit C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 6327c81 - commit B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* b68a192 - commit A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This works great! It keeps our tree clean, simple, linear, and easy to
understand. However, &lt;code&gt;commit D&lt;&#x2F;code&gt;, &lt;code&gt;commit E&lt;&#x2F;code&gt;, and &lt;code&gt;commit F&lt;&#x2F;code&gt; all have different
SHAs now, and are effectively &lt;code&gt;commit D&#x27;&lt;&#x2F;code&gt;, &lt;code&gt;commit E&#x27;&lt;&#x2F;code&gt;, and &lt;code&gt;commit F&#x27;&lt;&#x2F;code&gt;. This
is totally fine right now because we hadn&#x27;t shared &lt;code&gt;commit D&lt;&#x2F;code&gt;, &lt;code&gt;commit E&lt;&#x2F;code&gt; and
&lt;code&gt;commit F&lt;&#x2F;code&gt; with anyone yet.&lt;&#x2F;p&gt;
&lt;p&gt;However, if we had shared commits &lt;code&gt;D&lt;&#x2F;code&gt;, &lt;code&gt;E&lt;&#x2F;code&gt;, and &lt;code&gt;F&lt;&#x2F;code&gt; already by pushing our
branch up to the remote. We would have technically shared that history. And our
Git tree would look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* a0aca6f - (main, origin&#x2F;main) commit G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * fe06e90 - (HEAD -&amp;gt; feature&#x2F;x, origin&#x2F;feature&#x2F;x) commit F&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * 81312b5 - commit E&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * f09acea - commit D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&#x2F; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 9cabcd2 - commit C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 6327c81 - commit B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* b68a192 - commit A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Therefore, when following this rule we can no longer use &lt;code&gt;git rebase&lt;&#x2F;code&gt; to base
our branch on top of the latest &lt;code&gt;main&lt;&#x2F;code&gt; because it would accomplish that by
rewriting the commits in the branch. Rewriting the commits could create
complications for other developers who happen to be working on the previous
state of the commits as the new commits have now diverged.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, we need to bring the new commits in &lt;code&gt;main&lt;&#x2F;code&gt; into our &lt;code&gt;feature&#x2F;x&lt;&#x2F;code&gt; branch
in a way that doesn&#x27;t rewrite history. &lt;code&gt;git merge&lt;&#x2F;code&gt; is exactly the command we
are looking for. As it creates a new merge commit that has multiple parent
commits. If we ran &lt;code&gt;git merge main&lt;&#x2F;code&gt; it would look something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* f1cca4d - N - (HEAD -&amp;gt; feature&#x2F;x) commit H&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|\&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * fe06e90 - N - (origin&#x2F;feature&#x2F;x) commit F&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * 81312b5 - N - commit E&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;| * f09acea - N - commit D&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* a0aca6f - N - (main, origin&#x2F;main) commit G&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;|&#x2F; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 9cabcd2 - G - commit C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* 6327c81 - N - commit B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* b68a192 - N - commit A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above Git tree we can see that &lt;code&gt;feature&#x2F;x&lt;&#x2F;code&gt; contains the same commits
with the same SHAs as before, but also contains a new commit that merges &lt;code&gt;main&lt;&#x2F;code&gt;
into &lt;code&gt;feature&#x2F;x&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This is great as it makes it so that you can easily collaborate with one or
more developers on the &lt;code&gt;feature&#x2F;x&lt;&#x2F;code&gt; branch. However, it also made the Git tree
more complex and complicated to understand. It might not be too bad with
one branch. But we haven&#x27;t gotten to the step of merging our branch back into
&lt;code&gt;main&lt;&#x2F;code&gt; at some point in the future. Or, the reality that often you need to
merge main into your feature branch multiple times as new changes are
introduced. Or, the reality of dealing with multiple branches doing the same
thing at the same time. Generally, you will end up with a very complicated tree
that looks something like the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;when-to-rewrite-git-history&#x2F;.&#x2F;complicated-git-tree.png&quot; alt=&quot;image of extremely complicated git tree&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Having these forward &amp;amp; backward merges happening also ends up eventually
confusing Git when it comes to its ability to find merge bases correctly, in
turn limiting the functionality of Git.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-the-alternative&quot;&gt;What is the Alternative?&lt;&#x2F;h2&gt;
&lt;p&gt;The alternative is to simply use &lt;code&gt;git rebase&lt;&#x2F;code&gt; on your feature branches.
However, we know that this can create problems for those collaborating on a
feature branch.&lt;&#x2F;p&gt;
&lt;p&gt;So we simply have an understanding of how we are going to treat feature
branches by default. For example, we can say that by default feature branches
are owned and controlled by their author. Anyone pulling down that branch and
testing it out or reviewing it should understand that the history is owned by
the author, and they will likely change it. Generally, the reviewing developer
uses something like &lt;code&gt;git reset --hard origin&#x2F;feature&#x2F;x&lt;&#x2F;code&gt; to update their local
state to match that of the remote state.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if you communicate out of band with the developer that owns the feature
branch and let them know that you are going to push up a commit, they can
integrate it into their feature branch in their local git repo and still use
rebase. It just requires some out of band coordination. But this is actually a
relatively rare situation for this to occur and therefore isn&#x27;t a big deal.&lt;&#x2F;p&gt;
&lt;p&gt;It is also worth noting that taking this approach allows you to use the &quot;Rebase
&amp;amp; Merge&quot; strategy in GitHub which will result in a linear Git history. Making
it much easier to understand and manage over time.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;I have used both these strategies and many others throughout my career. But the
ease of understanding &amp;amp; management of a linear Git tree is far more valuable
than simply not needing to worry about a tiny bit of out of band communication
in the rare scenario that you need to directly contribute to someone else
feature branch.&lt;&#x2F;p&gt;
&lt;p&gt;The key with this alternative is that you don&#x27;t rewrite history for &lt;code&gt;main&lt;&#x2F;code&gt; as
it is a central point of collaboration where you don&#x27;t want to have deal with
the overhead of the out of bound communication and coordination. But due to the
rareness of the need to directly contribute to other peoples feature branches
the overhead of the out-of-band communication is more than an acceptable trade.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Reasonable Code Organization</title>
        <published>2024-03-27T00:00:00+00:00</published>
        <updated>2024-03-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/reasonable-code-organization/"/>
        <id>https://drewdeponte.com/blog/reasonable-code-organization/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/reasonable-code-organization/">&lt;p&gt;The following are some excerpts related to code organization from a code review
I did recently.&lt;&#x2F;p&gt;
&lt;p&gt;I started reviewing this PR and wasn&#x27;t quite sure exactly what the separation
of concerns were with the boundaries you had drawn. So I drew a diagram to try
and help myself understand better. It ended up looking as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;reasonable-code-organization&#x2F;diagram-at-beginning.png&quot; alt=&quot;original diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From looking at the code in far more depth I started to get a better
understanding but still wasn&#x27;t sure about things. Largely, what component was
responsible exactly for what concerns.&lt;&#x2F;p&gt;
&lt;p&gt;I figured out through reading a bunch of the code that
&lt;code&gt;EventStreamQueryService&lt;&#x2F;code&gt; was for querying Athena for Events. Which roughly
lines up with the diagram above. Part of what threw me on that was the naming
having Stream in there. The following questions were flowing through my head.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;what does &lt;code&gt;Stream&lt;&#x2F;code&gt; have to do with querying?&lt;&#x2F;li&gt;
&lt;li&gt;is it integrated with a stream somehow?&lt;&#x2F;li&gt;
&lt;li&gt;why is Athena a peer?&lt;&#x2F;li&gt;
&lt;li&gt;is something else using it?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Beyond that even when I looked at the code of the Athena service it
has knowledge of &lt;code&gt;Events&lt;&#x2F;code&gt; which isn&#x27;t an Athena thing at all.&lt;&#x2F;p&gt;
&lt;p&gt;So, I figured I would throw a quick diagram together to show how I would think
about this problem architecturally and how I would draw the lines. That looks
as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;reasonable-code-organization&#x2F;ideal-diagram-dependencies.png&quot; alt=&quot;ideal diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I tried to explain the responsibilities of each of the concepts in the text
next to it. The arrows represent their relationship in terms of dependence
(what things depend on what things). This generally helps in terms of making
decisions about encapsulation of dependencies (a.k.a. are you going to hide a
dependency away or are you going to expose it intentionally for other things to
use it).&lt;&#x2F;p&gt;
&lt;p&gt;This naturally leads to the question. &quot;How do you organize this code so that it
is far more consumable and easy to understand coming into the project?&quot;&lt;&#x2F;p&gt;
&lt;p&gt;That is where modules come into play as they facilitate encapsulation of
dependencies as well help to formalize interfaces. It is worth noting that I am
not talking about Nest.JS modules, though they can also facilitate
encapsulation. I am simply talking about standard Typescript modules. If we
take the example above you could create a directory structure as such.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;reasonable-code-organization&#x2F;better-directory-structure.png&quot; alt=&quot;better directory structure&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Having a directory structure like this is extremely valuable because of the
encapsulation. It tells me that as a consumer and developer of the &lt;code&gt;Event Stream Module&lt;&#x2F;code&gt;, that the &lt;code&gt;Event&lt;&#x2F;code&gt; and &lt;code&gt;EventStreamReplayService&lt;&#x2F;code&gt; are the public interface and
entry point for the module. I know this very quickly just from looking at the
directory structure.  Everything else is encapsulated and hidden away with in
their respective modules. This is also extremely useful to know as a developer
because I can understand for example that &lt;code&gt;EventStreamService&lt;&#x2F;code&gt; depends on
&lt;code&gt;KinesisService&lt;&#x2F;code&gt; but that nothing else should because it is encapsulated within
the &lt;code&gt;EventStreamService&lt;&#x2F;code&gt; module.&lt;&#x2F;p&gt;
&lt;p&gt;The same goes for &lt;code&gt;EventQueryService&lt;&#x2F;code&gt; module. It encapsulates the &lt;code&gt;Athena Service&lt;&#x2F;code&gt; telling me as a developer nothing else should be using that &lt;code&gt;Athena Service&lt;&#x2F;code&gt;. Instead, they should be going through the &lt;code&gt;EventQueryService&lt;&#x2F;code&gt; or if
some functionality doesn&#x27;t make sense being added to &lt;code&gt;EventQueryService&lt;&#x2F;code&gt; then
the &lt;code&gt;AthenaService&lt;&#x2F;code&gt; should be elevated up to a higher level shared dependency.&lt;&#x2F;p&gt;
&lt;p&gt;All of this, aids massively in communicating the boundaries and their actual
association to the architecture itself.&lt;&#x2F;p&gt;
&lt;p&gt;Something like what we originally had doesn&#x27;t tell us much.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;reasonable-code-organization&#x2F;diagram-at-beginning.png&quot; alt=&quot;original diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It tells me that a &lt;code&gt;StreamEvent&lt;&#x2F;code&gt; exists that a &lt;code&gt;EventStreamQueryService&lt;&#x2F;code&gt;
exists, that a &lt;code&gt;EventStreamService&lt;&#x2F;code&gt; exists, and that a &lt;code&gt;AthenaService&lt;&#x2F;code&gt; exists,
but it doesn&#x27;t tell me much of anything about their relationships or what their
responsibilities are intended to be.&lt;&#x2F;p&gt;
&lt;p&gt;Not having clear boundaries allows you to easily fall into traps that make your
code far less maintainable and reusable. For example if we look at the
&lt;code&gt;AthenaService.fetchQuery()&lt;&#x2F;code&gt; method.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  async&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fetchQuery&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;    queryExecutionId&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;    nextToken&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ): &lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;Promise&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;EventStreamQuery&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; AthenaServiceError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    try {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = await this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;client&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;send&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;        new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; GetQueryResultsCommand&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          QueryExecutionId:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; queryExecutionId&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          NextToken:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; nextToken&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;      const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; events&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; EventStreamEvent&lt;&#x2F;span&gt;&lt;span&gt;[]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;      data&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;ResultSet&lt;&#x2F;span&gt;&lt;span&gt;?.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Rows&lt;&#x2F;span&gt;&lt;span&gt;?.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;forEach&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;row&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;        events&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          eventSource:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; row&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;VarCharValue&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          projectId:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; row&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;VarCharValue&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          occurredAt:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Date&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;row&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;VarCharValue&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;          payload:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; JSON&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;parse&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;row&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Data&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;VarCharValue&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Ok&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        queryExecutionId:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; queryExecutionId&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        state:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; EventStreamQueryState&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;SUCCEEDED&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        nextToken:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; data&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;NextToken&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        events:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; events&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      })&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    } catch (error) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      return &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;Err&lt;&#x2F;span&gt;&lt;span&gt;(this.mapError(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;error&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is building a &lt;code&gt;EventStreamQuery&lt;&#x2F;code&gt; object as well as building an array of
&lt;code&gt;EventStreamEvents&lt;&#x2F;code&gt;. This is a mixing of two concerns here. One is the work
necessary to deal with Athena client and the other is work that is structuring
data to be &lt;code&gt;Event&lt;&#x2F;code&gt; data.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s say we decided to use &lt;code&gt;Athena&lt;&#x2F;code&gt; for something else in the future in this
project, or who knows maybe in another project. Because these two concerns are
mixed here it would require much more work to rebuild all the context around
this problem space and safely do the extraction of just the &lt;code&gt;Athena&lt;&#x2F;code&gt; specific
piece that could be reused. Keeping those boundaries clean now doesn&#x27;t
cost very much at all as the context is already present.&lt;&#x2F;p&gt;
&lt;p&gt;If you aren&#x27;t clear on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.typescriptlang.org&#x2F;docs&#x2F;handbook&#x2F;2&#x2F;modules.html&quot;&gt;TypeScript
Modules&lt;&#x2F;a&gt; it is a
standard language feature that is worth understanding. The pattern of having a
directory represent your module with a &lt;code&gt;index.ts&lt;&#x2F;code&gt; file in it can be very
useful.&lt;&#x2F;p&gt;
&lt;p&gt;To complete the exercise with the same type of diagram I started with, but
in this proposed new world order. It would look like this.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;reasonable-code-organization&#x2F;side-by-side-comparison.png&quot; alt=&quot;side by side comparison&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is of course possible to do with Nest.JS modules. However, it doesn&#x27;t
really give you any advantage and adds more boilerplate code and complexity
than is necessary.&lt;&#x2F;p&gt;
&lt;p&gt;I hope this has been useful and am always open to discuss further.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My Keyboard</title>
        <published>2024-01-18T00:00:00+00:00</published>
        <updated>2024-01-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/projects/keyboard/"/>
        <id>https://drewdeponte.com/projects/keyboard/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/projects/keyboard/">&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;&#x2F;h2&gt;
&lt;p&gt;The following is a deep dive into my current keyboard which is outlined below.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;4x5 Dactyl Manuform (with a few small tweaks)&lt;&#x2F;li&gt;
&lt;li&gt;Printed on my 3D printer&lt;&#x2F;li&gt;
&lt;li&gt;Custom-built&lt;&#x2F;li&gt;
&lt;li&gt;Hand Wired&lt;&#x2F;li&gt;
&lt;li&gt;Cherry MX Blue switches (Cherry MX Silver in my secondary keyboard)&lt;&#x2F;li&gt;
&lt;li&gt;Firmware: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.qmk.fm&#x2F;#&#x2F;&quot;&gt;QMK&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;My fork of QMK firmware (repo: &lt;code&gt;git:&#x2F;&#x2F;git.drewdeponte.com&#x2F;qmk_firmware.git&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Dvorak&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;dactyl_manuform_keyboard_layout_print_on_letter.pdf&quot;&gt;Pretty Layout for Printing&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5079.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-a-dactyl-manuform&quot;&gt;Why a Dactyl Manuform?&lt;&#x2F;h2&gt;
&lt;p&gt;Well, the short answer is because I have historically had wrist pain from
typing. But not with the 4x5 Dactyl Manuform. I believe at this point with all
my experimentation with a ton of other custom keyboards I have built that the
key to my success with this build is due to two things.&lt;&#x2F;p&gt;
&lt;p&gt;First, I determined that my wrist pain was caused largely by repetitive
stretching of my fingers to reach keys at the outer boundaries of keyboards.
The only way I could figure to reduce that was to reduce the number of keys I
have on the keyboard. Hence, the 4x5 size. However, this meant that I would
have to have layers and a comfortable thumb cluster I could use all the keys
from.&lt;&#x2F;p&gt;
&lt;p&gt;The Dactyl Manuform 4x5 meets all these requirements and still maintains all my
other ergonomic requirements. Also thanks to QMK it is customizable enough to
support a layered layout in a way that I can still be efficient at programming.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-problem-no-more&quot;&gt;A Problem, No More&lt;&#x2F;h2&gt;
&lt;p&gt;I love my Dactyl Manuform keyboard. It is by far the best keyboard I have every
used and my wrists haven&#x27;t felt any pain since I started using it. However, it
has had one problem. It is too light-weight. Because of this even when I have
rubber on the bottom of it, it still slides around on my desk.&lt;&#x2F;p&gt;
&lt;p&gt;The other day I decided it was time to address this annoyance. So I took them
apart and first tried to see if I could figure out a good mechanism for adding
weight to them. Didn&#x27;t have much luck with that. And then I thought my other
issue is having my trackpad positioned appropriately relative to the keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;This got me thinking if I could create some sort of thin thing that would hold
the keyboards in the appropriate positions to be ergonomic, as well as hold my
trackpad.&lt;&#x2F;p&gt;
&lt;p&gt;So I laid out the components on my desk in the correct positions and then took
a rough measurement to figure out how large something would need to be. I then
took those measurements to find some scrap Masonite board in my wood shop and
cut it down to that size. Then I laid the components on it the correct
positions and then used some CA glue to glue down tiny blocks to hold the
components in the correct positions &amp;amp; orientations.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_6976.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This actually worked extremely well. It kept the keyboards and trackpad in the
correct positions. It also increased the surface area in contact with the
rubber as well as the weight. Causing it to prevent the devices from sliding
around on my desk.&lt;&#x2F;p&gt;
&lt;p&gt;However, the next problem that I had was that it was ugly and that it bothered
my wrist when I would relax my hand on the desk. Beyond that it was just ugly.
So I free hand drew a more organic looking outline around the components,
visible in the photo above, and then cut it out with a band saw.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_6997.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This made it not only look nicer. But also eliminated the discomfort that I had
when I would wrest my hinds on the desk every so often. In fact, you can see what
it looks like in use in the following photo.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_7001.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is still a bit ugly and could use some love. So my plan is to cover up the
blocks and the visible wood by sculpting clay to make in organic looking alien
blob that is absorbing my keyboards and touchpad. And then I will paint it.
Hopefully, at that point it will look much nicer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-build&quot;&gt;The Build&lt;&#x2F;h2&gt;
&lt;p&gt;The following are a bunch of photos I took throughout the build. I won&#x27;t go
into all the details about them. But figured I would share.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5041.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5042.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5045.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5046.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5047.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5050.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5051.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5053.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5054.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5057.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5071.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5072.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5073.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5074.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5075.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5079.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5080.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_5080.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;IMG_6220.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;66026839065__7E6872AC-DD8D-4329-81E0-F5292F1B9E52.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;
&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;projects&#x2F;keyboard&#x2F;66026840819__51271F4A-6E5C-4396-8174-D3A194DC613F.jpeg&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;p&gt;The following are really more notes for me about things. But it might be useful
to you if you are trying to get a Dactyl Manuform setup with QMK Firmware.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abstracthat&#x2F;dactyl-manuform&quot;&gt;abstracthat&#x2F;dactyl-manuform&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;parts&quot;&gt;Parts&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mcmaster.com&#x2F;#94180a331&#x2F;=16yfrx1&quot;&gt;Tapered Heat-Set Inserts for Plastic&lt;&#x2F;a&gt; (Brass, M3 x 0.50 mm Thread Size, 3.800 mm Installed Length) - use for attaching a base to the bottom of the housing&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.metricscrews.us&#x2F;index.php?main_page=product_info&amp;amp;cPath=155_185&amp;amp;products_id=455&quot;&gt;M3 wafer-head screws, 5mm&lt;&#x2F;a&gt; - used to attach the base to the inserts in the housing&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;gp&#x2F;product&#x2F;B00LQPY0Y0&quot;&gt;1N4148 diodes&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;gp&#x2F;product&#x2F;B00GWFECWO&quot;&gt;#30 wire&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;2 &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sparkfun.com&#x2F;products&#x2F;12640&quot;&gt;Arduino Pro Micros&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;gp&#x2F;product&#x2F;B008CPVMMU&quot;&gt;Veroboard stripboard&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aliexpress.com&#x2F;item&#x2F;32949546651.html?spm=a2g0o.cart.0.0.2e4b3c00twBcLt&amp;amp;mp=1&quot;&gt;4pin Telephone Cord&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.amazon.com&#x2F;gp&#x2F;product&#x2F;B01HU7BVDU&#x2F;&quot;&gt;Female RJ-9 connectors&lt;&#x2F;a&gt; - &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.aliexpress.com&#x2F;item&#x2F;32763781713.html?spm=a2g0o.cart.0.0.2e4b3c00twBcLt&amp;amp;mp=1&quot;&gt;4pin RJ-9 Female Connectors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;keyboard-layout&quot;&gt;Keyboard Layout&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ePL2Xbq6mO0&quot;&gt;teej sets up QMK Layout for Dactyl Manuform 5x7&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;qmk&quot;&gt;QMK&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.qmk.fm&#x2F;#&#x2F;newbs_building_firmware&quot;&gt;QMK - Building Firmware&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;possible-parts&quot;&gt;Possible Parts&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;keeb.io&#x2F;collections&#x2F;diy-parts&#x2F;products&#x2F;pro-micro-5v-16mhz-arduino-compatible-atmega32u4&quot;&gt;Pro Micro&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;build-videos&quot;&gt;Build Videos&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;kevin-eckert-keyboard-build-stream-dactyl-manuform&quot;&gt;Kevin Eckert - Keyboard Build Stream - Dactyl Manuform&lt;&#x2F;h4&gt;
&lt;p&gt;This is great in depth series on the build which matches the types of connectors used in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abstracthat&#x2F;dactyl-manuform&quot;&gt;abstracthat&#x2F;dactyl-manuform&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=dWC_8BOArzc&quot;&gt;Keyboard Build Stream - Dactyl Manuform - Part 1&lt;&#x2F;a&gt; - assume already printed, put switches in the case, wire the switches&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=fDc6rjZGYiI&quot;&gt;Keyboard build Stream - Dactyl Manuform - Part 2&lt;&#x2F;a&gt; - continue wiring switches with diodes on the rows&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=r-CKnaoSmCk&quot;&gt;Keyboard build Stream - Dactyl Manuform - Part 3&lt;&#x2F;a&gt; - wire up the Pro Micro to the switches&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Oloh3Yabu6I&quot;&gt;Keyboard Build Stream - Dactyl Manuform - Part 4&lt;&#x2F;a&gt; - Wiring RJ-9, USB-C to micro USB extension, programming mode button&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;cmd-dactyl-manuform-build&quot;&gt;CMD - Dactyl Manuform Build&lt;&#x2F;h4&gt;
&lt;p&gt;This build video is great for understanding the background of the Dactyl and seeing someone paint it. However, it is using a slightly different case from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;abstracthat&#x2F;dactyl-manuform&quot;&gt;abstracthat&#x2F;dactyl-manuform&lt;&#x2F;a&gt;. It uses a different type of connector to connect the two halves of the keyboard, etc.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=CxNKWNKBLMs&amp;amp;t=1127s&quot;&gt;CMD - Dactyl Manuform Build&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;i-built-a-ridiculous-keyboard-by-hand&quot;&gt;I built a Ridiculous Keyboard by Hand&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=VlHgEqLVYqA&quot;&gt;I built a Ridiculous Keyboard by Hand&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Wes8jtxbBdo&amp;amp;t=336s&quot;&gt;What I Learned From Building a Ridiculous Keyboard by Hand&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;keyboard-layout-1&quot;&gt;Keyboard Layout&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;i.imgur.com&#x2F;N8zCFBp.png&quot;&gt;Developer&#x27;s 40% Plank layout&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dactyl-qmk&quot;&gt;Dactyl QMK&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;balatero.com&#x2F;writings&#x2F;qmk&#x2F;getting-started-with-dactyl-manuform-and-qmk&#x2F;&quot;&gt;Getting Started with Dactyl Manuform QMK&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;wiring-flashing&quot;&gt;Wiring &#x2F; Flashing&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qmk&#x2F;qmk_firmware&#x2F;tree&#x2F;master&#x2F;keyboards&#x2F;handwired&#x2F;dactyl_manuform&quot;&gt;QMK Wiring for connect two halves&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;golem.hu&#x2F;article&#x2F;pro-micro-pinout&#x2F;&quot;&gt;Firmware Pin Mapping&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;split-not-working&quot;&gt;Split Not Working&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;qmk&#x2F;qmk_firmware&#x2F;issues&#x2F;9697&quot;&gt;Dactyl Manuform Split Not Working&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.qmk.fm&#x2F;#&#x2F;feature_split_keyboard?id=handedness-by-pin&quot;&gt;QMK Split Keyboards Feature&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.reddit.com&#x2F;r&#x2F;olkb&#x2F;comments&#x2F;c0006h&#x2F;dactylmanuform_wlets_split_firmware_slave_side&#x2F;erb2y5l&#x2F;&quot;&gt;QMK Split Keyboard Not Working&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;qmk-firmware&quot;&gt;QMK Firmware&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;compile&quot;&gt;Compile&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qmk compile -kb handwired&#x2F;dactyl_manuform&#x2F;4x5 -km drewdeponte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;flash&quot;&gt;Flash&lt;&#x2F;h4&gt;
&lt;ol&gt;
&lt;li&gt;Connect the keyboard directly to the laptop via straight USB-C cable with
the left half plugged into the computer. The right half can stay connected
to the left half via the telephone wire.&lt;&#x2F;li&gt;
&lt;li&gt;Run the following command, it will get to a point where it starts waiting
for the device. When it does, you double tap the button on the back of the
left half of the keyboard, and it will switch the controller into flash mode.
The app will detect it and flash the device.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;qmk flash -kb handwired&#x2F;dactyl_manuform&#x2F;4x5 -km drewdeponte&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After it is done you should be able to disconnect it, reconnect the keyboard
and everything should be good to go.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;edit&quot;&gt;Edit&lt;&#x2F;h4&gt;
&lt;p&gt;Edit the following file to make changes to the layout.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;~&#x2F;code&#x2F;personal&#x2F;qmk_firmware&#x2F;keyboards&#x2F;handwired&#x2F;dactyl_manuform&#x2F;4x5&#x2F;keymaps&#x2F;drewdeponte&#x2F;keymap.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h4 id=&quot;notes-1&quot;&gt;Notes&lt;&#x2F;h4&gt;
&lt;p&gt;To get this split to work I had to set up my &lt;code&gt;config.h&lt;&#x2F;code&gt; as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#define USE_SERIAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#define SPLIT_USB_DETECT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This only really works when the left side is plugged into the computer. If the
right side is plugged in the keys translate differently.&lt;&#x2F;p&gt;
&lt;p&gt;I tried the &lt;code&gt;EEPROM&lt;&#x2F;code&gt; detection but even after flashing the &lt;code&gt;EEPROM&lt;&#x2F;code&gt;s it didn&#x27;t
seem to work with the &lt;code&gt;EE_HAND&lt;&#x2F;code&gt;. So after trying things out this is what I
found to work.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;past-keyboards&quot;&gt;Past Keyboards&lt;&#x2F;h2&gt;
&lt;p&gt;I have had many past keyboards. The following is a list of just a few.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kinesis-ergo.com&#x2F;shop&#x2F;advantage2-signature-series&#x2F;&quot;&gt;Kinesis Advantage2 Signature Series&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ergodox.io&quot;&gt;ErgoDox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;kono.store&#x2F;products&#x2F;infinity-ergodox-keyboard&quot;&gt;Infinity ErgoDox&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.zsa.io&#x2F;moonlander&#x2F;&quot;&gt;Moonlander&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;olkb.com&#x2F;collections&#x2F;planck&quot;&gt;Planck&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.moergo.com&#x2F;collections&#x2F;glove80-keyboards&quot;&gt;Glove80&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Patch Stack 7.0.0</title>
        <published>2024-01-09T00:00:00+00:00</published>
        <updated>2024-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-patch-stack-7-0-0/"/>
        <id>https://drewdeponte.com/blog/git-patch-stack-7-0-0/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-patch-stack-7-0-0/">&lt;p&gt;The &lt;code&gt;7.0.0&lt;&#x2F;code&gt; release of Git Patch Stack is an extremely significant release. It
marks the beginning of a few major mental &amp;amp; strategic shifts in terms of Git
Patch Stack.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state&quot;&gt;State&lt;&#x2F;h2&gt;
&lt;p&gt;Historically we have tracked state in all versions of Git Patch Stack before
&lt;code&gt;7.0.0&lt;&#x2F;code&gt;. We stored this state in &lt;code&gt;.git&#x2F;GIT-PATCH-STACK-PATCH-STATES-V3.json&lt;&#x2F;code&gt;,
and a state entry in it generally would look something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;5543c1e7-b77b-41af-8653-c721b2e9db9d&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;patch_id&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;5543c1e7-b77b-41af-8653-c721b2e9db9d&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;state&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Integrated&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;ps&#x2F;rr&#x2F;fix_grammar___spelling_in_making_code_reusable&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;4c4b3b720b92957b21f11a9b6a331190b55535b1&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;      ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can conceptually think of it as hash map keyed off of the &lt;code&gt;ps-id&lt;&#x2F;code&gt;
(&lt;code&gt;patch_id&lt;&#x2F;code&gt;). The &lt;code&gt;state&lt;&#x2F;code&gt; property is simply an object that kept track of
the current state of a given patch.&lt;&#x2F;p&gt;
&lt;p&gt;This &lt;code&gt;state&lt;&#x2F;code&gt; property could conceptually be in any of the following cases,
each with their own associated data.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#[derive(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Serialize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Deserialize&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Debug&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Clone&lt;&#x2F;span&gt;&lt;span&gt;)]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;pub&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; enum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PatchState&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    BranchCreated&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; branch_name, patch_stack_diff_hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    PushedToRemote&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; remote, branch_name, patch_stack_diff_hash, remote_diff_hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    RequestedReview&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; remote, branch_name, patch_stack_diff_hash, remote_diff_hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    Integrated&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;              &#x2F;&#x2F; remote, branch_name, patch_stack_diff_hash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This was a simple straightforward way of getting started with Git Patch Stack
and representing the state that we believed we needed. However, over time we
began to see flaws &amp;amp; drawbacks with this approach.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;flaws&quot;&gt;Flaws&lt;&#x2F;h3&gt;
&lt;p&gt;For one, we got numerous reports of the state tracking becoming out of
alignment with Git proper because users were going outside of Git Patch Stack
and doing things.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, Git Patch Stack was tracking state that was fabricated. Meaning
it was state that we had made up and wasn&#x27;t actually possible to represent
within Git. This is largely because we were caching this fabricated state from
remote systems such as GitHub. Creating another point&#x2F;opportunity to be out of
sync in terms of state.&lt;&#x2F;p&gt;
&lt;p&gt;Third, people were trying to use Git Patch Stack across multiple remotes of a
repository and our state tracking had no mechanism of being synchronized across
the remotes.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-decision&quot;&gt;The Decision&lt;&#x2F;h3&gt;
&lt;p&gt;With the &lt;code&gt;7.0.0&lt;&#x2F;code&gt; release we decided to resolve these issues by making a very
important decision. Firstly, we would &lt;strong&gt;no longer track state&lt;&#x2F;strong&gt;. Instead, we
would &lt;strong&gt;compute the state&lt;&#x2F;strong&gt; for Git Patch Stack from the natural state of Git.&lt;&#x2F;p&gt;
&lt;p&gt;This has the benefit that it makes it impossible for a users Git state to be out of
sync with a users Git Patch Stack state.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, it facilitates the sharing of Git Patch Stack state across remotes
as the Git state is already synchronized over the network.&lt;&#x2F;p&gt;
&lt;p&gt;In addition, it has the massive benefit of now enabling users to use only the
portions of Git Patch Stack that they find valuable for their workflow without
getting out of sync. This same characteristic also enables Git Patch Stack to
be combined with other Git extensions &amp;amp; tools (e.g.
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;tummychow&#x2F;git-absorb&quot;&gt;git-absorb&lt;&#x2F;a&gt;) without worrying about
getting out of sync.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;beneficial-side-effects&quot;&gt;Beneficial Side Effects&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to all the natural benefits we have gained from the decision to
compute state instead of track state, we indirectly gained a massive side
effect. The side effect of creating better alignment between Git Patch Stack
and Git proper. This modeling alignment ended up enabling us to add a long
requested feature of Git Patch Stack, Patch Series support.&lt;&#x2F;p&gt;
&lt;p&gt;A Patch Series within a Patch Stack workflow is a defined consecutive sequence
of patches. Often times they are dependent on one another and have to be
sequenced in a specific order. This is useful when you want to simply organize
related patches or when you want to request review of a series of patches.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_with_patch_series_no_alt_colors@2x.png&quot; alt=&quot;gps list output with a patch series but no alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Even though we have introduced the concept of a patch series, it is important
to realize that they still exist within your Patch Stack. In fact, they can
exist alongside other solo patches or other patch series within your stack.
Their relationship to each other is simply controlled by which order you place
them in your stack. The same way that you manage patch relationships.&lt;&#x2F;p&gt;
&lt;p&gt;To understand how we define or refine a patch series lets look at the example above. Prior to having the &quot;login&quot; patch series defined our &lt;code&gt;gps ls&lt;&#x2F;code&gt; output would look as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_no_patch_series_no_alt_colors@2x.png&quot; alt=&quot;gps list output no patch series no alternating patch series colers&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Simply a stack of patches. To define or refine a patch series we simply use our new patch index range syntax (e.g. &lt;code&gt;2-5&lt;&#x2F;code&gt;), which works generally across the commands. For example if we want to create the patch series locally like we did in this example we would use &lt;code&gt;gps branch -n login 2-5&lt;&#x2F;code&gt;. Leaving us with a &lt;code&gt;gps ls&lt;&#x2F;code&gt; output that again looks as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_with_patch_series_no_alt_colors@2x.png&quot; alt=&quot;gps list output with a patch series but no alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However, if we wanted to refine the definition of that patch series. We would
simply rerun that same command while either increasing or decreasing the patch
index range to respectively include or exclude patches from the patch series.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;alternating-patch-series-coloring&quot;&gt;Alternating Patch Series Coloring&lt;&#x2F;h4&gt;
&lt;p&gt;After using Patch Series support for a while within the Git Patch Stack core
team, we decided that to really make it easy to use we would need to be able to
visually see a patch series within the stack without having to track from the
right side of a patch, seeing the branch, all the way over to the left side of
the patch to see the index. Our solution for this problem was relatively
simple. We introduced alternating patch series colors in the &lt;code&gt;gps list&lt;&#x2F;code&gt; output.&lt;&#x2F;p&gt;
&lt;p&gt;This allows you to clearly see which patches are part of which patch series.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_with_patch_series_with_alt_colors@2x.png&quot; alt=&quot;gps list output with a patch series with alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In fact from the screenshot above you can see that &lt;code&gt;gps list&lt;&#x2F;code&gt; sees individual
patches that are not part of a formal patch series as implicit patch series of
one patch. This is why the colors are alternating between the &lt;code&gt;Add Mortgage Calculator&lt;&#x2F;code&gt; patch and the &lt;code&gt;Add Loan Calculator&lt;&#x2F;code&gt; patch, as well as the &lt;code&gt;Add Savings Calculator&lt;&#x2F;code&gt; patch.&lt;&#x2F;p&gt;
&lt;p&gt;In fact if we had the same set of patches but hadn&#x27;t defined the patch series
we would see the following, as the alternate patch series coloring feature is
enabled by default.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_no_patch_series_with_alt_colors@2x.png&quot; alt=&quot;gps list output no patch series with alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can also clearly see the every patch in the list has alternate coloring.
This is a side effect of the fact that we don&#x27;t have any formal patch series
defined and again that &lt;code&gt;gps list&lt;&#x2F;code&gt; sees solo patches as a patch series of one
patch.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;colors-and-their-problems&quot;&gt;Colors and their Problems&lt;&#x2F;h5&gt;
&lt;p&gt;Colors especially within the terminal have a number of different problems. For
one the contrast needed for different people is different. Two, the colors
within my terminal are almost always different from the colors in your
terminal. Not to mention how your monitor is configured and presents the colors
to you is likely different. Or even, how your eyes interpret the colors and
the variance there. Who knows maybe you are color-blind and therefore need
specific colors.&lt;&#x2F;p&gt;
&lt;p&gt;To address these issues we have shifted to 24-bit color mode and set the
default colors based on my personal color choices. This way the colors are
hopefully pretty close to the colors I use on my machine.&lt;&#x2F;p&gt;
&lt;p&gt;We have also opted to support customization of the colors so that if you need
or just want different colors you can configure the colors that are used in the
&lt;code&gt;gps list&lt;&#x2F;code&gt; output. For details check out the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;tool&#x2F;configuration&quot;&gt;Configuration&lt;&#x2F;a&gt; documentation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;composition-over-opinion&quot;&gt;Composition over Opinion&lt;&#x2F;h2&gt;
&lt;p&gt;Another characteristic that Git Patch Stack has had historically up until
&lt;code&gt;7.0.0&lt;&#x2F;code&gt; is that it was more opinionated. It expected users to follow a specific
workflow and focused primarily on that.&lt;&#x2F;p&gt;
&lt;p&gt;This original decision was largely due to the fact that we were tracking state
and therefore users had to use our commands &amp;amp; workflow for the tool to
consistently work.&lt;&#x2F;p&gt;
&lt;p&gt;As part of the original approach we implemented a decent number of commands
either for convenience, as an alias, or to try and create a complete
abstraction to facilitate having a workflow completely within Git Patch Stack.
A lot of these commands actually did nothing other than proxy down to a Git
command. This has its maintenance problems as we would then have to maintain
and proxy all the various options for that Git command.&lt;&#x2F;p&gt;
&lt;p&gt;Git commands change over time and therefore this creates a large maintenance
problem. Beyond that it turns out that there are a ton of different variations
of workflows that users have with Git. Having a hard lined view of the workflow
that Git Patch Stack is targeted to support and not supporting any other
workflows significantly limits its ability to be valuable.&lt;&#x2F;p&gt;
&lt;p&gt;However, now that we are computing state we no longer need to be so opinionated
in terms of workflow as our users can now use the pieces of Git Patch Stack
they prefer and ignore the rest. They can also use Git Patch Stack in
combination with other Git commands or even other Git extensions.&lt;&#x2F;p&gt;
&lt;p&gt;So we decided to change the focus of Git Patch Stack from enforcing a
particular workflow, to instead be a general tool allowing users to have their
own custom workflows utilizing Git Patch Stack.&lt;&#x2F;p&gt;
&lt;p&gt;Making this decision then made it clear that to truly support this mindset we
should remove all the &quot;proxy commands&quot;. This will ease our maintenance effort
significantly, and it will make the intention of Git Patch Stack and its stance
clearer. So we removed the &lt;code&gt;sync&lt;&#x2F;code&gt;, &lt;code&gt;log&lt;&#x2F;code&gt;, &lt;code&gt;create-patch&lt;&#x2F;code&gt;, &lt;code&gt;amend-patch&lt;&#x2F;code&gt;,
&lt;code&gt;status&lt;&#x2F;code&gt;, &lt;code&gt;unstage&lt;&#x2F;code&gt;, &lt;code&gt;upstream-patches&lt;&#x2F;code&gt;, and the &lt;code&gt;add&lt;&#x2F;code&gt; commands to simplify the
command surface area.&lt;&#x2F;p&gt;
&lt;p&gt;To continue this effort to simplify the command surface area we removed the
&lt;code&gt;batch-request-review&lt;&#x2F;code&gt; command and added proper first class support for
batching to the &lt;code&gt;request-review&lt;&#x2F;code&gt; command. When doing so, we added it in a way
that would be easy to add to other commands. However, we were hesitant to just
add it to all the commands as we weren&#x27;t sure that it made sense. Additionally,
we removed the old &lt;code&gt;branch&lt;&#x2F;code&gt; command and renamed the &lt;code&gt;request-review-branch&lt;&#x2F;code&gt;
command to &lt;code&gt;branch&lt;&#x2F;code&gt; as well as retrofitted it to be a first class citizen.&lt;&#x2F;p&gt;
&lt;p&gt;We also realized, based on proxy command feature requests, that we needed to
somehow support all these custom local Git workflows people have. We decided
that the best way to do this was to additionally focus Git Patch Stack on the
concept of facilitating composition of its concepts with that of Git proper or
any other command line tool for that matter.&lt;&#x2F;p&gt;
&lt;p&gt;To begin to facilitate this we have provided the &lt;code&gt;gps sha &amp;lt;patch-index&amp;gt;&lt;&#x2F;code&gt;
command. It simply takes a &lt;code&gt;patch-index&lt;&#x2F;code&gt; as the argument and outputs the
corresponding Git commit SHA. Having this basic command now allows people to
build new commands that deal with a patch index instead of a Git commit SHA.&lt;&#x2F;p&gt;
&lt;p&gt;Maybe you are a fan of using &lt;code&gt;git commit --fixup&lt;&#x2F;code&gt; and you want to use it with a
patch index instead of having to have the SHA for a patch and type it in. No
problem with &lt;code&gt;gps sha&lt;&#x2F;code&gt; you can simply do &lt;code&gt;git commit --fixup=amend:$(gps sha 4)&lt;&#x2F;code&gt; to flag patch indexed by 4 for amend. If it is a command you use all the
time in your workflow simply make an alias that does it.&lt;&#x2F;p&gt;
&lt;p&gt;This flexibility provided by the composition is key to support the vast variety
of personalized workflows that people have.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;platform-agnostic&quot;&gt;Platform Agnostic&lt;&#x2F;h2&gt;
&lt;p&gt;Another choice that we made was that we should be as platform-agnostic as
possible in our choices and our design so that we can support as many platforms
as possible. Support for macOS &amp;amp; Linux variants was something we had at a basic
level. However, Windows was a platform that we didn&#x27;t support primarily because
of choices of libraries we used.&lt;&#x2F;p&gt;
&lt;p&gt;So part of the effort of the &lt;code&gt;7.0.0&lt;&#x2F;code&gt; release was to move toward being able to
support the Windows platform. As I mentioned before the primary issue we had
was libraries we were using that weren&#x27;t cross-platform. So we swapped those
out for libraries that were cross-platform.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gpg-signing&quot;&gt;GPG Signing&lt;&#x2F;h3&gt;
&lt;p&gt;The other major issue we had was GPG signing support. Prior to &lt;code&gt;7.0.0&lt;&#x2F;code&gt; we were
integrating directly with GPG via C library that we couldn&#x27;t easily get to
build on Windows. So we decided to follow suite with what Git proper was doing
in terms of GPG Signing support and have Git Patch Stack simply shell out to
the GPG command on that system by utilizing Git propers configuration.&lt;&#x2F;p&gt;
&lt;p&gt;For details on configuring GPG signing please checkout &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;tool&#x2F;commit-signing&quot;&gt;Commit Signing&lt;&#x2F;a&gt; docs.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ssh-signing&quot;&gt;SSH Signing&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to switching GPG Signing away from the C library. We also had
numerous requests to support SSH Signing as GPG was losing in popularity. So
while we were reworking the GPG Signing we also added support for SSH
Signing in a cross-platform manner.&lt;&#x2F;p&gt;
&lt;p&gt;All of these platform-agnostic choices have also resulted in a far simpler
build process which helps not only in the distribution of the application but
also in the maintenance and even developer onboarding.&lt;&#x2F;p&gt;
&lt;p&gt;For details on configuring SSH signing please checkout &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;tool&#x2F;commit-signing&quot;&gt;Commit Signing&lt;&#x2F;a&gt; docs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quality-of-life&quot;&gt;Quality of Life&lt;&#x2F;h2&gt;
&lt;p&gt;Beyond these major decisions and the improvements that have fallen out of them
we also have a lot of improvements that we have made simply for Quality of
Life.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;integrate-verify-hook&quot;&gt;Integrate Verify Hook&lt;&#x2F;h3&gt;
&lt;p&gt;As part of &lt;code&gt;7.0.0&lt;&#x2F;code&gt; we now have the &lt;code&gt;integrate_verify&lt;&#x2F;code&gt; hook. This is a hook that
gets executed as part of the &lt;code&gt;gps integrate&lt;&#x2F;code&gt; commands lifecycle. Enabling you
to verify external state, maybe on an SCM hosting provider, is correct prior to
integrating.&lt;&#x2F;p&gt;
&lt;p&gt;We have provided an example in the repository,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&#x2F;blob&#x2F;main&#x2F;example_hooks&#x2F;integrate_verify.sample.github-cli&quot;&gt;example_hooks&#x2F;integrate_verify.sample.github-cli&lt;&#x2F;a&gt;.
This example is written to integrate with GitHub to check to make sure that all
the CI checks have passed prior to letting someone integrate their patch.&lt;&#x2F;p&gt;
&lt;p&gt;For further details on this hook check out the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&#x2F;tool&#x2F;hooks&quot;&gt;Hooks&lt;&#x2F;a&gt; documentation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;in-rebase-support&quot;&gt;In Rebase Support&lt;&#x2F;h3&gt;
&lt;p&gt;For quite some time we have had requests to make &lt;code&gt;gps list&lt;&#x2F;code&gt; function when in
the middle of a rebase. Well &lt;code&gt;7.0.0&lt;&#x2F;code&gt; is the release where we finally add
support for this. To see how this works let&#x27;s get started by setting the state
to what you see in the screenshot below.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_no_patch_series_with_alt_colors@2x.png&quot; alt=&quot;gps list output no patch series with alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now let&#x27;s say that we want to edit the &lt;code&gt;Add Login client&lt;&#x2F;code&gt; patch identified by
patch index &lt;code&gt;3&lt;&#x2F;code&gt;. One approch to doing that is to run a &lt;code&gt;gps rebase&lt;&#x2F;code&gt; and simply
mark that patch for &lt;code&gt;edit&lt;&#x2F;code&gt;. This will leave us looking like the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;in_rebase_support_edit_patch_3@2x.png&quot; alt=&quot;gps rebase marking patch 3 for editing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Git simply outputs the short SHA and summary of the commit it stopped at for
editing. However, if we now run &lt;code&gt;gps list&lt;&#x2F;code&gt; we see the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;in_rebase_support_gps_list_in_rebase@2x.png&quot; alt=&quot;gps list after stopping in the middle of a rebase&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;From the above we can see that it shows us a lot more useful information here.
It shows us that we are in the middle of a rebase of &lt;code&gt;main&lt;&#x2F;code&gt; and the SHA of the
commit we are rebasing it onto.&lt;&#x2F;p&gt;
&lt;p&gt;It also shows us in the bottom section the current state of the patch stack. At
this point in time it only consists of the patches that the rebase has already
played. From this we can tell that if we were to run a &lt;code&gt;git commit --amend&lt;&#x2F;code&gt; it
would be amending the &lt;code&gt;Add Login client&lt;&#x2F;code&gt; patch as it is the patch currently at
the top of the stack.&lt;&#x2F;p&gt;
&lt;p&gt;Lastly the section above that shows the patches that are still in the rebase
to-do list and have yet to be replayed. In fact if you squint a little you
might have noticed that if you slammed the top section and bottom section
together it would look just like your patch stack. This is by design so that
you can quickly and easily figure out what state you are in with respect to
your patch stack, even when you are in the middle of a rebase &lt;code&gt;gps list&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ahead-behind-counts&quot;&gt;Ahead &amp;amp; Behind Counts&lt;&#x2F;h3&gt;
&lt;p&gt;In addition to all these other great improvements we also improved &lt;code&gt;gps list&lt;&#x2F;code&gt;
by adding &lt;strong&gt;ahead&lt;&#x2F;strong&gt; and &lt;strong&gt;behind&lt;&#x2F;strong&gt; counts to its output. In fact we can see
these on the top line of the &lt;code&gt;gps list&lt;&#x2F;code&gt; output in the screenshot below.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-7-0-0&#x2F;gps_list_no_patch_series_with_alt_colors@2x.png&quot; alt=&quot;gps list output no patch series with alternating patch series colors&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In the screenshot above we can see that it says that we are currently in a
state where our patch stack is &lt;code&gt;ahead 7&lt;&#x2F;code&gt; and &lt;code&gt;behind 0&lt;&#x2F;code&gt;. What does this mean
exactly?&lt;&#x2F;p&gt;
&lt;p&gt;Well, &lt;code&gt;ahead X&lt;&#x2F;code&gt; is telling you how many patches stack has ahead of it&#x27;s base.
In the screenshot above it is &lt;code&gt;7&lt;&#x2F;code&gt; because there are &lt;code&gt;7&lt;&#x2F;code&gt; patches.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;behind Y&lt;&#x2F;code&gt; is telling you how many commits your stack is behind it&#x27;s
associated upstream tracking branch. You generally want it to be &lt;code&gt;0&lt;&#x2F;code&gt; as that
indicates that your patch stack is up-to-date with what Git sees as the current
state of your patch stacks upstream tracking branch. You will notice becoming
behind if others are adding commits to the remote of your patch stack, and you
are using &lt;code&gt;git fetch&lt;&#x2F;code&gt; to update your repositories&#x27; knowledge, but you aren&#x27;t
actively rebasing your patch stack onto the latest.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;others&quot;&gt;Others&lt;&#x2F;h3&gt;
&lt;p&gt;Beyond all the above-mentioned features &amp;amp; changes. We have also included a
handful of other changes that are less crucial and less visible in terms of
presentation. The summary of these can be seen below.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;added&quot;&gt;Added&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;conflict &amp;amp; merge commit detection errors to isolate command&lt;&#x2F;li&gt;
&lt;li&gt;conflict &amp;amp; merge commit detection errors to branch command&lt;&#x2F;li&gt;
&lt;li&gt;conflict &amp;amp; merge commit detection errors to request-review command&lt;&#x2F;li&gt;
&lt;li&gt;conflict &amp;amp; merge commit detection errors to integrate command&lt;&#x2F;li&gt;
&lt;li&gt;global color option support to the branch command&lt;&#x2F;li&gt;
&lt;li&gt;the command alias &quot;b&quot; to the new branch command&lt;&#x2F;li&gt;
&lt;li&gt;build time generation of man pages&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;changed&quot;&gt;Changed&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;unhandled error output for the list command&lt;&#x2F;li&gt;
&lt;li&gt;unhandled error printing to print the chain of errors&lt;&#x2F;li&gt;
&lt;li&gt;gps --help docs to describe core vs. ancillary cmds&lt;&#x2F;li&gt;
&lt;li&gt;improved CLI help interface&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;fixed&quot;&gt;Fixed&lt;&#x2F;h4&gt;
&lt;ul&gt;
&lt;li&gt;crash in list command when tracking branch is configured but remote branch doesn&#x27;t exist&lt;&#x2F;li&gt;
&lt;li&gt;bug where commit without diff id in stack would cause list to fail&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;where-to-go-from-here&quot;&gt;Where to Go from here?&lt;&#x2F;h2&gt;
&lt;p&gt;The future is somewhat an unknown as we haven&#x27;t planned a next major release
yet, let alone a theme for one. To keep tabs on what we are planning or
specific issues you can check out our public &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;orgs&#x2F;uptech&#x2F;projects&#x2F;3&quot;&gt;GitHub
Project&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you are interested in chatting about Git Patch Stack or just different Git
workflows, providing feedback, or contributing. Don&#x27;t hesitate to reach out via
our public &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;join.slack.com&#x2F;t&#x2F;gitpatchstack&#x2F;shared_invite&#x2F;zt-1bubjt6wg-QrvG9aBGniyZ0aPH9BcB4g&quot;&gt;Slack
Group&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you are completely new to Git Patch Stack, a good place to start would be
the main &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack site&lt;&#x2F;a&gt; as well as the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;book.git-ps.sh&quot;&gt;documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As always we hope that you find the decisions, changes and features we added
valuable.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a StoryBrand: Chapter 4</title>
        <published>2023-12-28T00:00:00+00:00</published>
        <updated>2023-12-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/building-a-storybrand-chapter-4/"/>
        <id>https://drewdeponte.com/blog/building-a-storybrand-chapter-4/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/building-a-storybrand-chapter-4/">&lt;p&gt;The content goes here.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;context&quot;&gt;Context&lt;&#x2F;h2&gt;
&lt;p&gt;Principle One: The customer is the hero not your brand.&lt;&#x2F;p&gt;
&lt;p&gt;Define characters ambition. What they want. So that we open the question, Will
the hero get what she wants? This is called a Story Question or story gap.&lt;&#x2F;p&gt;
&lt;p&gt;When we define something our customers want, we posit a story question in the
mind of the customer: &lt;em&gt;Can this brand really help me get what I want?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;define something your customers want&lt;&#x2F;li&gt;
&lt;li&gt;must be have a singular focus, be one thing&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;example-1&quot;&gt;Example 1&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;High-end resort originally had marketing content that was images of their
front desk, staff, etc. Wasn&#x27;t really inviting a customer into a story. What
their customers really wanted most was a luxurious, restful experience.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;After StoryBranding they changed their website from long stories about
themselves (which positioned them as the hero) to images of a warm bath,
plush towels and robes, someone getting a massage in the spa, and a looping
clip of a back-porch rocking chair against the backdrop of trees blowing in
the wind along a golf course.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;They replaced the text on their main page with the short and powerful copy:
&quot;Find the luxury and rest you&#x27;ve been looking for.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Excerpt From
Building a StoryBrand
Donald Miller
https:&#x2F;&#x2F;books.apple.com&#x2F;us&#x2F;book&#x2F;building-a-storybrand&#x2F;id1212150000
This material may be protected by copyright.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-2&quot;&gt;Example 2&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;One university we worked with defined their customer&#x27;s desire as “a
hassle-free MBA you can complete after work.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Excerpt From
Building a StoryBrand
Donald Miller
https:&#x2F;&#x2F;books.apple.com&#x2F;us&#x2F;book&#x2F;building-a-storybrand&#x2F;id1212150000
This material may be protected by copyright.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-3&quot;&gt;Example 3&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;A landscaping company humorously defined their customer’s ambition as “a yard that looks better than your neighbor&#x27;s.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Excerpt From
Building a StoryBrand
Donald Miller
https:&#x2F;&#x2F;books.apple.com&#x2F;us&#x2F;book&#x2F;building-a-storybrand&#x2F;id1212150000
This material may be protected by copyright.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example-4&quot;&gt;Example 4&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;A caterer we worked with in Los Angeles defined his customer&#x27;s desire as “a mobile fine-dining experience in the environment of your choice.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Excerpt From
Building a StoryBrand
Donald Miller
https:&#x2F;&#x2F;books.apple.com&#x2F;us&#x2F;book&#x2F;building-a-storybrand&#x2F;id1212150000
This material may be protected by copyright.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;examples-5-10&quot;&gt;Examples 5-10&lt;&#x2F;h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Financial Advisor: &quot;A Plan for Your Retirement&quot;
College Alumni Association: &quot;Leave a Meaningful Legacy&quot;
Fine-Dining Restaurant: &quot;A Meal Everybody Will Remember&quot;
Real Estate Agent: &quot;The Home You’ve Dreamed About&quot;
Bookstore: &quot;A Story to Get Lost In&quot;
Breakfast Bars: &quot;A Healthy Start to Your Day&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Excerpt From
Building a StoryBrand
Donald Miller
https:&#x2F;&#x2F;books.apple.com&#x2F;us&#x2F;book&#x2F;building-a-storybrand&#x2F;id1212150000
This material may be protected by copyright.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;actions&quot;&gt;Actions&lt;&#x2F;h2&gt;
&lt;h2 id=&quot;application&quot;&gt;Application&lt;&#x2F;h2&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Getting Started with StoryBranding</title>
        <published>2023-12-28T00:00:00+00:00</published>
        <updated>2023-12-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/storybranding-beginning/"/>
        <id>https://drewdeponte.com/blog/storybranding-beginning/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/storybranding-beginning/">&lt;p&gt;If I am honest with myself. One of the areas that I lack strength &amp;amp;
skills, is marketing. I try and focus on areas I am weaker to hopefully improve
over time. But it is hard to do this when you are running a business, doing
client work, and have a family.&lt;&#x2F;p&gt;
&lt;p&gt;A while back a friend of mine introduced me to the book, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;buildingastorybrand.com&quot;&gt;Building a
StoryBrand&lt;&#x2F;a&gt; by Donald Miller. I read it
through, and it resonated pretty strongly with me. But it was non-trivial for
me to apply. So I let other things get in the way.&lt;&#x2F;p&gt;
&lt;p&gt;I feel like if I had better marketing skills it would seriously impact my
ability to help push my business to the next level. So being that I have some
time during Christmas vacation I have decided to give it another go. This time
pushing myself through the discomfort in hopes to grow my skills &amp;amp; abilities.&lt;&#x2F;p&gt;
&lt;p&gt;I figure if I can at least start it during Christmas break and keep a journal
as I go through then I will be able to actually push through and finish with
something to show for it.&lt;&#x2F;p&gt;
&lt;p&gt;So jumping right in, Chapters 1, 2, and 3 are really an outline and sales pitch
for the concept of StoryBranding and the framework to create a StoryBrand.
&lt;strong&gt;StoryBranding is basically the idea of taking the same fundamental structures
that make stories so impactful to people and applying them to your branding.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The later chapters get into specific details about the framework and what each
step is. I will cover those in detail in future posts as I reread them and
attempt to apply them.&lt;&#x2F;p&gt;
&lt;p&gt;Right now I am planning on using a rough template consisting of two main sections.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;context&lt;&#x2F;li&gt;
&lt;li&gt;actions&lt;&#x2F;li&gt;
&lt;li&gt;application&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The thinking behind this is that I am focusing on details of how to apply this
concept which I will outline in the &lt;strong&gt;actions&lt;&#x2F;strong&gt; section. While the &lt;strong&gt;context&lt;&#x2F;strong&gt;
section will house all my notes from reading the chapter that I believe are
necessary context while doing the &lt;strong&gt;actions&lt;&#x2F;strong&gt;. The &lt;strong&gt;application&lt;&#x2F;strong&gt; section will
house an explanation of how I have attempted to execute the actions.&lt;&#x2F;p&gt;
&lt;p&gt;I have a number of different projects, services, etc. that I could apply this
concept to that I may use some of in the &lt;strong&gt;application&lt;&#x2F;strong&gt; section just to try
and get a better handle of things.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pullwalla&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Uptech Studio as a Productized Service&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pullwalla - More Workflows</title>
        <published>2023-11-28T00:00:00+00:00</published>
        <updated>2023-11-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pullwalla-more-workflows/"/>
        <id>https://drewdeponte.com/blog/pullwalla-more-workflows/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pullwalla-more-workflows/">&lt;p&gt;Hello!&lt;&#x2F;p&gt;
&lt;p&gt;We just released v3.7.0 (51) of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pullwalla&lt;&#x2F;a&gt; to both macOS and iOS platforms.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-filters&quot;&gt;Quick Filters&lt;&#x2F;h2&gt;
&lt;p&gt;One of Pullwalla&#x27;s primary goals has been to help people quickly &lt;strong&gt;discover&lt;&#x2F;strong&gt; the pull requests they are interested in. Quick Filters continue to be a key mechanism supporting this.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;more-workflows&quot;&gt;More Workflows&lt;&#x2F;h3&gt;
&lt;p&gt;One of the things we have done in this release is support additional workflows.&lt;&#x2F;p&gt;
&lt;p&gt;The workflow we supported historically is a workflow where developers take a step back from code every so often, looked at the previously &lt;em&gt;Unclaimed&lt;&#x2F;em&gt;, pull requests to find a pull request review, and then &quot;claim&quot; it by assigning themselves to it.&lt;&#x2F;p&gt;
&lt;p&gt;This workflow is fine and works for some. But it doesn&#x27;t work for everyone. Some people instead take the approach of requiring that every pull request when created has to have explicit requests for review, or requires that assignees be used to mean something different. Others have a workflow that is some sort of hybrid between the two approaches.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, we introduced two new Quick Filters.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Undecided&lt;&#x2F;strong&gt; - shows pull requests that have not been approved or had changes requested yet.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Needs my Decision&lt;&#x2F;strong&gt; - shows pull requests that either you are an assignee of or that have a request for your review and have not been approved or had changes requested by you.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The &lt;strong&gt;Needs my Decision&lt;&#x2F;strong&gt; quick filter facilitates workflows where PRs are created and given an assignee or a request for review is explicitly made. While the &lt;strong&gt;Undecided&lt;&#x2F;strong&gt; quick filter supports workflows where developers pick their own pull requests to review. You can see this in the screenshot below.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;files.pullwalla.com&#x2F;v3.7.0-51-quick-filters-transparent-wallpaper@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;clarification&quot;&gt;Clarification&lt;&#x2F;h3&gt;
&lt;p&gt;Beyond the addition of the &lt;strong&gt;Undecided&lt;&#x2F;strong&gt; and &lt;strong&gt;Needs my Decision&lt;&#x2F;strong&gt; quick filters. We also renamed the other quick filters to try and make them more accurate and clear. Previously Pullwalla&#x27;s Quick Filters looked as follows.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;files.pullwalla.com&#x2F;v3.6.2-50-quick-filters-transparent-wallpaper@2x.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The mapping of the name changes are as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Created&lt;&#x2F;strong&gt; is now &lt;strong&gt;My PRs&lt;&#x2F;strong&gt; as it shows pull requests that you have created.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Assigned&lt;&#x2F;strong&gt; is now &lt;strong&gt;My Assignments&lt;&#x2F;strong&gt; as it shows pull requests that you are an assignee of.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Mentioned&lt;&#x2F;strong&gt; is now &lt;strong&gt;My Mentions&lt;&#x2F;strong&gt; as it shows pull requests that you are mentioned in.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Review Requests&lt;&#x2F;strong&gt; is now &lt;strong&gt;Request for my Review&lt;&#x2F;strong&gt; as it shows pull requests where someone has requested your review.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Participated&lt;&#x2F;strong&gt; is now &lt;strong&gt;Participated In&lt;&#x2F;strong&gt; as it shows pull requests that you have participated in.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Unclaimed&lt;&#x2F;strong&gt; is now &lt;strong&gt;Unassigned&lt;&#x2F;strong&gt; as it shows you pull requests that have no assignees.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Claimed&lt;&#x2F;strong&gt; is now &lt;strong&gt;Assigned&lt;&#x2F;strong&gt; as it shows you pull requests that have one or more assignees.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We hope these improvements to Quick Filters will have a big impact on peoples day to day interactions with Pullwalla. If you think we are missing something or have any feedback in general please don&#x27;t hesitate to reach out at &lt;a href=&quot;mailto:pullwalla@uptechstudio.com&quot;&gt;pullwalla@uptechstudio.com&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thoughts-or-suggestions&quot;&gt;Thoughts or suggestions?&lt;&#x2F;h3&gt;
&lt;p&gt;As always, we’d love to hear from you.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Need help with an App (mobile, web, desktop, etc.)?&lt;&#x2F;strong&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;, the creators of Pullwalla, are here to help. Just reach out to &lt;a href=&quot;mailto:info@uptechstudio.com&quot;&gt;info@upechstudio.com&lt;&#x2F;a&gt;, and we are happy to explore how we might work together.&lt;&#x2F;p&gt;
&lt;p&gt;Cheers,
The Pullwalla Team&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Patch Stack Goals</title>
        <published>2023-11-03T00:00:00+00:00</published>
        <updated>2023-11-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-patch-stack-goals/"/>
        <id>https://drewdeponte.com/blog/git-patch-stack-goals/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-patch-stack-goals/">&lt;p&gt;&lt;em&gt;The following is a transcript of an audio recording I made exploring the goals
and intent behind the Git Patch Stack project. I have also included the audio
below if you would prefer to listen.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;audio controls&gt;
	&lt;source src=&quot;git-patch-stack-goals.mp3&quot; type=&quot;audio&#x2F;mpeg&quot;&gt;
Your browser does not support the audio element.
&lt;&#x2F;audio&gt;
&lt;h2 id=&quot;transcript&quot;&gt;Transcript&lt;&#x2F;h2&gt;
&lt;p&gt;Hi I am Drew De Ponte, Partner at Uptech Studio &amp;amp; creator of Git Patch Stack.&lt;&#x2F;p&gt;
&lt;p&gt;Today I wanted to talk about Git Patch Stack and the driving forces and purpose
behind it. Largely in my mind, the goal was and still is to find alignment
between Git itself as a tool, its characteristics, best practices and the
development process and tooling that we all generally use at mass today.&lt;&#x2F;p&gt;
&lt;p&gt;In my mind that is using Bitbucket, GitHub, GitLab and the pull requests or
merge requests peer review workflow that the mass is still using today. The
reason I was looking for alignment between these things was because I felt like
there was a dichotomy between the pull request feature branch workflow and Git
best practices.&lt;&#x2F;p&gt;
&lt;p&gt;How people were using feature branches in the feature branch workflow
at large was very much against the best practices of Git. One great example
of this is the atomic or logical commit being a best practice of Git. This is
because people would focus largely on feature branches as the primary concept
and they would ignore the value of commits.&lt;&#x2F;p&gt;
&lt;p&gt;They would ignore the benefits you gain longer term by having well structured
logical commits, and they would ignore the benefits you get in terms of all the
features of Git being available to you.&lt;&#x2F;p&gt;
&lt;p&gt;So Git Patch Stack has always been an exploration on my part to try and find
the best alignment between those two worlds. Most of our values have fallen out
of this exploration for this alignment. For example one of our values is that
we support the Continuous Integration Methodology as closely as possible.&lt;&#x2F;p&gt;
&lt;p&gt;We want to eliminate the negative side effects of branch isolation. So, We
always lean towards Continous Integration in terms of decision making. Having
the user confront conflicts and bring integration to the forefront so that it
happens at a much quicker iterative pace, and so that the surface area of the
conflicts are much smaller when they occur. Rather than waiting until a giant
feature branch is finally ready to be merged and having to deal with a
nightmare in terms of integration.&lt;&#x2F;p&gt;
&lt;p&gt;We are also big on aligning with Git. Hence why we focus on atomic or logical
commits and the tooling is designed around it. Not that you can&#x27;t use branches,
because you can if you really want. Branches are fine. But you have to be a
very cognizant and aware of the consequences of those branches when you are
makeing those decisions. I think that&#x27;s largely one of the downfalls that
occurred when Git came out.&lt;&#x2F;p&gt;
&lt;p&gt;Git itself is fantastic as a tool. It gives you all this flexibility and power.
However, when GitHub came out as a tool it created this next level of focus on
the concepts of the feature branch &amp;amp; pull request. Which only perpetuated heavy
use branches and drove developers to not think about the concept of logical
commits. Or even the fundamentals of Git anymore.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a higher level abstraction that they created &amp;amp; popularized. And most
developers nowadays come into Git through these higher level abstractions. I
can&#x27;t tell you how many developers I&#x27;ve met that don&#x27;t even know that there is
a tree of commits.&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s a side effect of them learning from this higher level abstraction
and not learning the fundamental underlying abstractions. There&#x27;s downsides to
that. Which is, without diving deeper and learning those underlying
abstractions, those developers just believe that, that&#x27;s the truth.&lt;&#x2F;p&gt;
&lt;p&gt;They believe that, that is the only way. Or, that in actuality, they believe
that, that is the way it was designed and intended to be used, which is not
necessarily true. That&#x27;s one person or one group of people&#x27;s take on how they
think it should be used. And none of those people were the creator of Git.&lt;&#x2F;p&gt;
&lt;p&gt;They built that and put it out into the world and it resonated with people.
This makes sense because it&#x27;s a simplification. Instead of thinking about
commits and how they relate to each other &amp;amp; all the complexities of the
mechanics of managing them in Git. You don&#x27;t have to think about any of that.
You just think about this much grander, larger scale thing called a feature.
But that has its downsides as well.&lt;&#x2F;p&gt;
&lt;p&gt;So again, we as Git Patch Stack are focused on trying to find &amp;amp; and refine that
alignment between these worlds, where we can focus on the right things for Git
as a tool itself. But also play in a world with these higher level concepts
like feature branches &amp;amp; pull requsets, when we want or need to.&lt;&#x2F;p&gt;
&lt;p&gt;And also allow the user to, jump out and use a branch or any other normal Git
commads when it is appropriate. But the focus of the tooling is all on these
logical commits.&lt;&#x2F;p&gt;
&lt;p&gt;So we have this core value of, &lt;strong&gt;abide by Git best practices&lt;&#x2F;strong&gt;. That way we are
in alignment with what Git expects. &lt;strong&gt;Support as much as possible the concept
of continuous integration&lt;&#x2F;strong&gt;. So that we can reduce the surface area and
complexity of conflicts.&lt;&#x2F;p&gt;
&lt;p&gt;Third we have, &lt;strong&gt;finding alignment with this concept of feature branches and
pull requests and peer reviews&lt;&#x2F;strong&gt;. But implementing it in such a way, that you
aren&#x27;t forced into the feature branch, pull request, or peer review concepts.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, Git Patch Stack allows you from a workflow standpoint to plug into
those concepts, or it would allow you to, plug into an email based workflow
instead. When you conceptually request review in Git Patch Stack, there&#x27;s a
hook system.&lt;&#x2F;p&gt;
&lt;p&gt;And that hook system allows you to plug in a hook to, go create a pull request
in GitHub, or go create a patch and email that patch to a particular mailing
list, or do anything you want. It&#x27;s completely up to you.&lt;&#x2F;p&gt;
&lt;p&gt;But the goal of Git Patch Stack is to provide that core structure to think in
terms of the right concepts so that you are in alignment with all of these
things, not just GitHub&#x27;s model.&lt;&#x2F;p&gt;
&lt;p&gt;Another value, is &lt;strong&gt;being able to focus on how to mentally think about these
things and trying to do that with as little overhead as possible&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;You can see this point in terms of a comparison of the Stacked Branch workflow
versus a Patch Stack workflow. In a Stacked Branch workflow, you are creating
branches for each of your atomic commits, and then you&#x27;re defining the
relationships between those branches so it can formally store a directed
acyclic graph of those relationships.&lt;&#x2F;p&gt;
&lt;p&gt;And then there&#x27;s extra tooling both on the client side, where you manage your
changes locally, but also tooling on the application
side where it can read the directed acyclic graph and facilitate reviewing
pull requests in the particular order defined in the directed acyclic graph.
The DAG also enables additional automation in terms of management of these
branches and the DAG.&lt;&#x2F;p&gt;
&lt;p&gt;In my opinion, the Stacked Branch workflow&#x27;s functionally solves some of the
problems that you have when you start thinking about atomic commits. But it
doesn&#x27;t solve all of them. And it requires this overhead of defining and
managing the branches &amp;amp; the DAG in order to even solve the problems it does.&lt;&#x2F;p&gt;
&lt;p&gt;Again my goal with Git Patch Stack was to explore and find a way that things
fall into alignment with all of these things. That way developers can just
focus on the core concepts and principles &amp;amp; naturally be in alignment.&lt;&#x2F;p&gt;
&lt;p&gt;For example ideally, you don&#x27;t want to have to worry about creating branches up
front and maintaining branches at all. Instead, the relationships of your
patches are managed through their order in your patch stack. And it&#x27;s much
easier to think about those dependencies because that is the way those
dependencies end up in your actual tree later on.&lt;&#x2F;p&gt;
&lt;p&gt;The last value that I can think that we focus on is, and this isn&#x27;t that you&#x27;re
forced to do this but we do encourage it, that &lt;strong&gt;you have a linear Git
history&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you think about it, the concept of a patch stack is a linear history itself.
And so the idea is that when you integrate, if you&#x27;re integrating through Git
Patch Stacks tooling, you will end up with a linear history.&lt;&#x2F;p&gt;
&lt;p&gt;Now, technically Git Patch Stack is flexible enough that you can integrate
through GitHub, Bitbucket, or GitLab merges. If you do we recommend that you
configure it to do a rebase and merge so that you end up with a linear git
history.&lt;&#x2F;p&gt;
&lt;p&gt;But from a technical standpoint, you don&#x27;t have to integrate that way. You
could do forced merges where you always have a merge commit, for example, where
you use &lt;code&gt;git merge --no-ff&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;ll always create a commit even if it could fast forward. Some people prefer
to do that. Long ago in my career I believed that was the best approach because
I was focused on feature branches back then. However, now I no longer agree
with it.&lt;&#x2F;p&gt;
&lt;p&gt;So instead we push this idea of linear Git history. This helps all kinds of
things down the road. It helps you understand your Git history more quickly and
easily. It helps you understand and be able to revert logical changes from your
Git history.&lt;&#x2F;p&gt;
&lt;p&gt;I hope that provides some insight into what the goals are and why Git Patch
Stack exists. It&#x27;s definitely continues to be a journey exploring and trying to
find, or now days more like, refine this alignment.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Workflows</title>
        <published>2023-10-26T00:00:00+00:00</published>
        <updated>2023-10-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-workflows/"/>
        <id>https://drewdeponte.com/blog/git-workflows/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-workflows/">&lt;p&gt;&lt;em&gt;The following is a transcript of an audio recording I made exploring some of
the benefits and drawbacks of the Feature Branch, Classic Continuous
Integration, Stacked Branch, and Patch Stack workflows. I have also included
the audio below if you would prefer to listen.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;audio controls&gt;
	&lt;source src=&quot;git-workflows.mp3&quot; type=&quot;audio&#x2F;mpeg&quot;&gt;
Your browser does not support the audio element.
&lt;&#x2F;audio&gt;
&lt;p&gt;&lt;em&gt;Note: I added some headers into the transcript to try and make it a tad bit
easier to jump to different sections if you are particularly interested in one
workflow.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;transcript&quot;&gt;Transcript&lt;&#x2F;h2&gt;
&lt;p&gt;All right.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s talk about some common git workflows.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;feature-branch-workflow&quot;&gt;Feature Branch Workflow&lt;&#x2F;h3&gt;
&lt;p&gt;One of the most common git workflows is the Feature Branching workflow.&lt;&#x2F;p&gt;
&lt;p&gt;And I think one of the primary reasons why it&#x27;s so common, is largely due to
the fact that GitHub was created and GitHub heavily promoted this workflow.
This of course is because GitHub is built around this workflows model.&lt;&#x2F;p&gt;
&lt;p&gt;It is worth noting, that just because it&#x27;s the most common doesn&#x27;t mean it is
the best workflow. It doesn&#x27;t mean it&#x27;s the worst workflow. It could be
somewhere in between. The truth is the commonality of it doesn&#x27;t necessarily
indicate its value, quality, applicability to our needs.&lt;&#x2F;p&gt;
&lt;p&gt;We don&#x27;t know until we actually reason about it. Comparing and contrasting the
benefits and drawbacks of these various workflows. And even then, we still
might not know definitively. But it will likely give us a bit more confidence
and definitely a deeper understanding.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s get into the Feature Branch workflow.&lt;&#x2F;p&gt;
&lt;p&gt;The way this works is that you have your git tree, and you have a main branch,
which is your main line of development.&lt;&#x2F;p&gt;
&lt;p&gt;Now, you don&#x27;t work directly on that branch.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, what you do is you create a feature branch based on it, to do your
work in.&lt;&#x2F;p&gt;
&lt;p&gt;And so in that feature branch, you make, all of your commits, all of your
changes, inside of that feature branch which is isolated away from all of the
code in the main line that&#x27;s coming in from other developers.&lt;&#x2F;p&gt;
&lt;p&gt;So you&#x27;re in this safe little isolated world where you can pretend that no
other changes are really happening for some period of time. Basically the
period of time that it takes you to develop that feature.&lt;&#x2F;p&gt;
&lt;p&gt;And then you have to work to get that feature branch merged back into the main
branch and pushed up to the upstream&#x27;s main.&lt;&#x2F;p&gt;
&lt;p&gt;OK. Now how you go about this depends on your team dynamics and structure.&lt;&#x2F;p&gt;
&lt;p&gt;The way github facilitates this is via this concept they introduced called a
Pull Request. To use it you take your feature branch, you push your feature
branch up to the remote as a separate branch and then you open a Pull Request
which is effectively a merge request asking one of your teammates to review &amp;amp;
approve the merge of that branch into main line. This creates a Pull Request on
GitHub. And you can see the diff between the main line and the Feature Branch.&lt;&#x2F;p&gt;
&lt;p&gt;So you can see the changes made and people can comment on them and you can
discuss and debate whether those changes are good and you can iterate on your
feature and so on and so forth.&lt;&#x2F;p&gt;
&lt;p&gt;And then eventually, you know, once that&#x27;s approved and good, then you can
merge that into main, and you can push main up to the upstream main.&lt;&#x2F;p&gt;
&lt;p&gt;GitHub helps kind of streamline the merging process a little bit by providing a
button to trigger the merge via the web interface.&lt;&#x2F;p&gt;
&lt;p&gt;OK. Now, so far, we&#x27;ve talked about a few things.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a couple of things that are nice and a couple of things that are not nice.&lt;&#x2F;p&gt;
&lt;p&gt;One of the things we&#x27;ve talked about is this convenient green button merge thing.&lt;&#x2F;p&gt;
&lt;p&gt;We talked about this idea of a Pull Request where you can see the changes and
that&#x27;s also kind of nice.&lt;&#x2F;p&gt;
&lt;p&gt;But the other thing we talked about was this branch and this idea of
branch isolation. Which might seem like a nice thing initially, but you soon
realize that the longer you have a branch in isolation and you pretend that
there aren&#x27;t other changes being made to the repository from other teammates,
you are increasing the probability that you will run into a conflict and you
are increasing the probability that the conflict when you run into, will be
larger and more complicated to resolve.&lt;&#x2F;p&gt;
&lt;p&gt;So that is a downside to this approach.&lt;&#x2F;p&gt;
&lt;p&gt;The other downside that&#x27;s kind of hidden to this approach.&lt;&#x2F;p&gt;
&lt;p&gt;Or atleast less obvious, is that Git as a tool promotes this concept of having
logical small commits.&lt;&#x2F;p&gt;
&lt;p&gt;OK.&lt;&#x2F;p&gt;
&lt;p&gt;And logical commits means that they are a unit in themselves.&lt;&#x2F;p&gt;
&lt;p&gt;Another term related to this is called atomic commits.&lt;&#x2F;p&gt;
&lt;p&gt;Which can be conceptually thought of as the smallest, atom like commit, or
indivisible logical unit.&lt;&#x2F;p&gt;
&lt;p&gt;But fundamentally, the idea is that it&#x27;s a small logical change that that
doesn&#x27;t depend on other changes above it?&lt;&#x2F;p&gt;
&lt;p&gt;It only depends on changes that already exist in the git tree.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s a logical change that is buildable and testable and everything the way you
want it. And that commits in general should be designed in this way.&lt;&#x2F;p&gt;
&lt;p&gt;So the Feature Branch workflow with GitHub has kind of led away from this idea.&lt;&#x2F;p&gt;
&lt;p&gt;What generally happens is that people don&#x27;t take the time or think about the
commits themselves how they should be logically chunked.&lt;&#x2F;p&gt;
&lt;p&gt;In general people using the Feature Branch workflow don&#x27;t tend to think much
about the commits at all.&lt;&#x2F;p&gt;
&lt;p&gt;Instead the developers tend to just think about the Feature Branch as this
logically chunked thing and they don&#x27;t worry about the state of the commits or
whether they&#x27;re logically chunked or not.&lt;&#x2F;p&gt;
&lt;p&gt;Now, the reason this is a problem is because the Git tool itself, and the
tooling that it provides is designed around these commits being smaller logical
commits.&lt;&#x2F;p&gt;
&lt;p&gt;So Git has features that are built around this concept logical commits, and if
you don&#x27;t treat your commits that way, these features don&#x27;t really work.&lt;&#x2F;p&gt;
&lt;p&gt;So one of those super useful features is called git bisect. It is extremely
useful when you&#x27;re trying to isolate a bug by narrow down what code that
introduced it.&lt;&#x2F;p&gt;
&lt;p&gt;But there are other commands as well. Even when you do something like a git
blame and you&#x27;re trying to understand why a change was was made. Having logical
commits is invaluable.&lt;&#x2F;p&gt;
&lt;p&gt;So the downsides of this Feature Branch workflow are that it kind of takes the
focus off of the commit and moves the focus strictly on to this idea of a
Feature Branch.&lt;&#x2F;p&gt;
&lt;p&gt;And therefore people naturally pay less attention to the commits.&lt;&#x2F;p&gt;
&lt;p&gt;Resulting in you losing the ability to use those vuluable tools.&lt;&#x2F;p&gt;
&lt;p&gt;Then we also have the other downside of it, which is the branch isolation.&lt;&#x2F;p&gt;
&lt;p&gt;When you have a branch isolated for that long, you increase the probability of
conflicts and the difficulty of those conflicts.&lt;&#x2F;p&gt;
&lt;p&gt;OK. So that&#x27;s the Feature Branch workflow.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;classic-continuous-integration-workflow&quot;&gt;Classic Continuous Integration Workflow&lt;&#x2F;h3&gt;
&lt;p&gt;So let&#x27;s talk about this other workflow I will call the Classic Continuous
Integration workflow.&lt;&#x2F;p&gt;
&lt;p&gt;The reason I call this the Classic Continuous Integration workflow is
because it is largely a workflow that people do when following the Continuous
Integration methodology.&lt;&#x2F;p&gt;
&lt;p&gt;It is a bit simpler than the branch based workflow because it doesn&#x27;t really
deal with branches.&lt;&#x2F;p&gt;
&lt;p&gt;That doesn&#x27;t mean you can&#x27;t do branches with it if you want.&lt;&#x2F;p&gt;
&lt;p&gt;But in general you don&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, what you do is you make commits directly on your local main branch and
you pull in changes from upstream on a regular basis. Now when you pull these
changes in you do it in such a way that youl local main branch is rebased onto
the latest changes from upstream&#x27;s main.&lt;&#x2F;p&gt;
&lt;p&gt;Once you get your commit on local main to a good place you integrate your
commit with upstream&#x27;s main by pushing it up.&lt;&#x2F;p&gt;
&lt;p&gt;So it&#x27;s much simpler and it lets you focus on the commits.&lt;&#x2F;p&gt;
&lt;p&gt;Which makes it easier to create logical commits and think about the commits.&lt;&#x2F;p&gt;
&lt;p&gt;So we are in alignment with the Git and their best practices and
expectations to support functionality within their tooling.&lt;&#x2F;p&gt;
&lt;p&gt;The reason it&#x27;s called continuous integration is because this workflow is
driven off of people following the continuous integration methodology. Where
the idea is that you pull in changes on a regular basis and that you are
integrating your changes with upstream on a regular basis.&lt;&#x2F;p&gt;
&lt;p&gt;When we say a regular basis, we generally mean as quickly as possible.&lt;&#x2F;p&gt;
&lt;p&gt;This is because the the purest idea of continuous integration is that you and
your team are always working off of a shared single state.&lt;&#x2F;p&gt;
&lt;p&gt;Now, in reality, with the tooling today that&#x27;s not completely possible.&lt;&#x2F;p&gt;
&lt;p&gt;But with the idea is that with continuous integration, you want to get as close
to that ideal as possible.&lt;&#x2F;p&gt;
&lt;p&gt;And so we have this, via this constant pulling and making a commit and
integrating it upstream and then pulling, making a commit, integrating it
upstream, etc. is fundamentally the flow that you have.&lt;&#x2F;p&gt;
&lt;p&gt;Now there this solved some problems, right?&lt;&#x2F;p&gt;
&lt;p&gt;For example we&#x27;re now focused on the commit, the logical commit.&lt;&#x2F;p&gt;
&lt;p&gt;So we don&#x27;t have that problem, we don&#x27;t have branches.&lt;&#x2F;p&gt;
&lt;p&gt;We don&#x27;t have to worry about branch isolation, which reduces the odds of
conflicts and their respective difficulty. This is because we&#x27;re working closer
to that shared concept of shared truth.&lt;&#x2F;p&gt;
&lt;p&gt;And all of that&#x27;s great, but it does have its drawbacks, right?&lt;&#x2F;p&gt;
&lt;p&gt;The rub comes when you&#x27;re dealing with creating these logical commits on top of
main.&lt;&#x2F;p&gt;
&lt;p&gt;It requires you to do one of two things, to either write your code from an
inside out perspective.&lt;&#x2F;p&gt;
&lt;p&gt;Meaning you have to guess what&#x27;s going to be needed as a dependency to build
the future feature you&#x27;re trying to build and go do that inner most dependency
first, hoping that you&#x27;ve written its interface correctly and then integrate
that into upstream. And then the layer above it, and so on and so forth,
eventually to get to where your feature is complete.&lt;&#x2F;p&gt;
&lt;p&gt;But just hoping that your interface is correct, in my experience, is very
difficult. It is not very comfortable because you don&#x27;t have confidence that
it&#x27;s correct because you have no other software driving that development or
given you feedback about its correctness.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s one approach you can take, but that&#x27;s very difficult.&lt;&#x2F;p&gt;
&lt;p&gt;The other approach you can take is to use a technique called Feature Toggling,
which allows you to integrate code into upstream that is incomplete.&lt;&#x2F;p&gt;
&lt;p&gt;So you can write code that is not complete, that is not currently being used
because you have a feature toggle that&#x27;s turned off. But you can
integrate that code so that your other developers on your team are aware of it
and know about it and could build on it, provide feedback to you, or
provide guidance about how it might be used in another case, etc.&lt;&#x2F;p&gt;
&lt;p&gt;All of which are positive, useful things.&lt;&#x2F;p&gt;
&lt;p&gt;However, managing feature toggles is another layer of complexity, that has to
be dealt with.&lt;&#x2F;p&gt;
&lt;p&gt;Now managing that layer of complexity has a lot of other benefits.&lt;&#x2F;p&gt;
&lt;p&gt;Specifically Feature Toggles end up having a bunch of other benefits when
you start talking about things like release management.&lt;&#x2F;p&gt;
&lt;p&gt;So there&#x27;s a ton of other benefits that you get that in my opinion are much
more worth the overhead than the complexity of branches which don&#x27;t help you in
those realms at all. Branches only really help you with organization at the
workflow layer, but they don&#x27;t help you beyond that.&lt;&#x2F;p&gt;
&lt;p&gt;One of the other side effects of this workflow, is that the peer review process
is very different.&lt;&#x2F;p&gt;
&lt;p&gt;The idea is that instead of opening a pull request and having your code
reviewed, you do post commit review, which is where you have committed and
integrated your commit upstream prior to any review by a peer.&lt;&#x2F;p&gt;
&lt;p&gt;And you&#x27;re saying that is OK because it passes the build, and it passes all the
tests.&lt;&#x2F;p&gt;
&lt;p&gt;It is also been integrated into main and our automated CI tests have not
failed.&lt;&#x2F;p&gt;
&lt;p&gt;This is very different from the Feature Branch workflow where the review
happens prior to integration into upstream main.&lt;&#x2F;p&gt;
&lt;p&gt;Because in the Classic Continuous Integration workflow, the code gets
integrated into main prior to being reviewed by other developers.&lt;&#x2F;p&gt;
&lt;p&gt;You might be going well. This is a horrible idea. How could we do that? The
main is supposed to be this pure, perfect pristine thing.&lt;&#x2F;p&gt;
&lt;p&gt;The justification for this is simply the realization that you are lying to
yourself if you actually believe any code is perfect before it goes in. Just
think of how many times you have integrated a reviewed feature and then found a
bug or realized that it needed to be refactored to support something else.&lt;&#x2F;p&gt;
&lt;p&gt;The Classic Continuous Integration stance is simply accepting that main is this
ever evolving and changing thing and therefore adjusting it with a future
commit is no big deal as that is how we normally change it.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if you talk about tooling Feature Branch workflow works great with GitHub,
Bitbucket, and GitLab. As they are all built around the same model.&lt;&#x2F;p&gt;
&lt;p&gt;But when you start talking about the continuous integration methodology, and
you start talking about this post commit review process, it&#x27;s really difficult
to find off the shelf tools out there that focus on post commit review process&lt;&#x2F;p&gt;
&lt;p&gt;Most of them are kind of homegrown tools.&lt;&#x2F;p&gt;
&lt;p&gt;But yeah, so, that&#x27;s the Classic Continuous Integration workflow.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stacked-branch-workflow&quot;&gt;Stacked Branch Workflow&lt;&#x2F;h3&gt;
&lt;p&gt;This brings us to the Stacked Branch Workflow.&lt;&#x2F;p&gt;
&lt;p&gt;The Stacked Branch workflow is trying to solve one of the complexities that I
talked about in the Classic Continuous Integration workflow while keeping the
focus on these atomic logical commits.&lt;&#x2F;p&gt;
&lt;p&gt;So if you remember, one of the hidden complexities I mentioned was that when
you&#x27;re doing the Classic Continuous Integration workflow, you have to develop
your code from the inside out, or you have to use feature toggles.&lt;&#x2F;p&gt;
&lt;p&gt;So the way that the Stacked Branches workflow works is that you create a
branch, but each of your branches are really focused on one of these atomic
logical commits conceptually.&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;re making a branch for each of these tiny logical changes that you&#x27;re
making and then there&#x27;s additional tooling on top of Git that creates this
directed acyclic graph (DAG) that understands the relationship between your
branches.&lt;&#x2F;p&gt;
&lt;p&gt;This allows you to create branches and then define the dependency relationships
between them, effectively building a stack (or sequence) of related (or
dependent) branches.&lt;&#x2F;p&gt;
&lt;p&gt;Having this directed acyclic graph and tooling that is aware of it enables the
tooling to automate what would be an extremely tedious process of rebasing all
the following branches when a lower level dependency branch changes.&lt;&#x2F;p&gt;
&lt;p&gt;It also gives other tooling the information to know in which order the branches
need to be integrated.&lt;&#x2F;p&gt;
&lt;p&gt;OK. So it&#x27;s trying to focus on these logical commits.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s not totally in alignment with the continuous integration methodology.&lt;&#x2F;p&gt;
&lt;p&gt;But it does facilitate when you pull, rebasing all of your stack of branches on
top of the latest main.&lt;&#x2F;p&gt;
&lt;p&gt;So you&#x27;re at least locally integrating more frequently.&lt;&#x2F;p&gt;
&lt;p&gt;However, it fixes these problems by adding all of these layers of extra work.
Having to manage creating of branches, having to define relationships between
branches, having to rebase branches, etc.&lt;&#x2F;p&gt;
&lt;p&gt;It does enable you to build your code from the outside in though, which is good.&lt;&#x2F;p&gt;
&lt;p&gt;You still have to integrate your code in an inside out fashion or use feature
toggles.&lt;&#x2F;p&gt;
&lt;p&gt;The other downside to this approach is that because this isn&#x27;t part of pure Git.
And it does not align with the current Feature Branch workflow of GitHub,
Bitbucket, or GitLab. You need additional tooling on top of that.&lt;&#x2F;p&gt;
&lt;p&gt;So your entire team has to switch to this additional tooling and this
additional application to see the branches, code review, and know the order in
which those branches need to be reviewed, etc.&lt;&#x2F;p&gt;
&lt;p&gt;OK. So that&#x27;s the other major downside that even though it starts to solve one
of the core issues with the Classic Continuous Integration workflow.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;patch-stack&quot;&gt;Patch Stack&lt;&#x2F;h3&gt;
&lt;p&gt;So the last workflow that I&#x27;ll talk about is what we call the Patch Stack
workflow.&lt;&#x2F;p&gt;
&lt;p&gt;As you might imagine from the name, this workflow is model around the concept
of managing a stack of patches.&lt;&#x2F;p&gt;
&lt;p&gt;Now this isn&#x27;t a stack in the purest sense, you aren&#x27;t limited to just push &amp;amp; pop operations.
Like you might think if you&#x27;re thinking about a stack data structure. You can
reorder patches in the stack, put things in the middle of the stack, pull
things out of the stack, etc.&lt;&#x2F;p&gt;
&lt;p&gt;You can imagine it&#x27;s just this mutable stack of patches that you can change and
mutate and do whatever you want with.&lt;&#x2F;p&gt;
&lt;p&gt;In this flow, you have a stack of patches which, are basically the commits that
you make on top of your local main that have not yet been integrated into
upstream main.&lt;&#x2F;p&gt;
&lt;p&gt;And when you do the get pull, it rebases your local stack of patches onto the
now updated origin&#x2F;main.&lt;&#x2F;p&gt;
&lt;p&gt;So this meets the continuous integration needs because anytime you do a Git
pull, it is forcing you to integrate your local stack with the changes that
have been introduced by your other teammates.&lt;&#x2F;p&gt;
&lt;p&gt;Not only that, it focuses on this concept of patches or commits, which are just
logical commits.&lt;&#x2F;p&gt;
&lt;p&gt;These are the same small logical commits, which are also in alignment with
continuous integration.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that it allows you to develop your software in an outside-in fashion
while still doing the inside out integration similar to the stacked branch
workflow. Except in this workflow, you don&#x27;t really concern yourself with
branches at all.&lt;&#x2F;p&gt;
&lt;p&gt;You don&#x27;t deal with the overhead of branches.&lt;&#x2F;p&gt;
&lt;p&gt;Instead, you think about a stack of patches.&lt;&#x2F;p&gt;
&lt;p&gt;And if you want a commit to exist, that depends on another commit in your
stack, you just have to make sure that the commit that it depends on is lower
in the stack than the commit that you&#x27;re working on.&lt;&#x2F;p&gt;
&lt;p&gt;This allows you to refine patches over time and work outside in.&lt;&#x2F;p&gt;
&lt;p&gt;But as you resolve and figure out what those inner most dependencies are, you
can integrate those right away like you would in a continuous integration
workflow or you could request review for them earlier to get them reviewed and
integrated into the code base as quickly as possible, which is also more in
alignment with the continuous integration methodology.&lt;&#x2F;p&gt;
&lt;p&gt;That sounds great.&lt;&#x2F;p&gt;
&lt;p&gt;It sounds like it&#x27;s solving all the problems of the continuous integration workflow.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s talk about peer reviews though.&lt;&#x2F;p&gt;
&lt;p&gt;The Patch Stack workflow allows you to request review of an individual patch or
a series of patches.&lt;&#x2F;p&gt;
&lt;p&gt;And what happens behind the scenes is that this actually ends up mapping back
to branches.&lt;&#x2F;p&gt;
&lt;p&gt;When you request review of an individual patch, behind the scenes, it goes and
creates the branch, cherry-picks that patch into that branch, pushes that
branch up to the remote, and can even open the pull request for you on GitHub,
Bitbucket, etc.&lt;&#x2F;p&gt;
&lt;p&gt;This makes it so, it works with the existing tooling that&#x27;s there. In turn
allowing you your team to use the same workflow they&#x27;ve always used and the
same tooling they&#x27;ve already been using.&lt;&#x2F;p&gt;
&lt;p&gt;But locally, you can develop your code using the Patch Stack workflow.&lt;&#x2F;p&gt;
&lt;p&gt;You might be asking yourself, wait, what about this dependency thing?&lt;&#x2F;p&gt;
&lt;p&gt;Do we have deal with all the complexity of managing branches locally and then
defining the relationships between those branches to define the relationships
between dependencies?&lt;&#x2F;p&gt;
&lt;p&gt;Nope, the Patch Stack workflow takes a different stance.&lt;&#x2F;p&gt;
&lt;p&gt;When you have dependent commits like that you have two options.&lt;&#x2F;p&gt;
&lt;p&gt;One is you request review for those individual patches one at a time in the
order that they need to be integrated and wait for the core dependent one to be
integrated before you request review of the next one.&lt;&#x2F;p&gt;
&lt;p&gt;Or you can create what&#x27;s called a patch series and request review of a patch
series.&lt;&#x2F;p&gt;
&lt;p&gt;All that is, is saying, hey, I want to request review for these three patches
in series in this order they exist in the stack.&lt;&#x2F;p&gt;
&lt;p&gt;And that does the same thing behind the scenes.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;ll create a branch, it&#x27;ll cherry-pick those patches in sequence into that
branch, push it up to the remote, and create a pull request for you based on
those patches going into upstream main.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s how the Patch Stack workflow deals with dependent patches.&lt;&#x2F;p&gt;
&lt;p&gt;You can have multiple patch series stacked on top of each other in your patch
stack.&lt;&#x2F;p&gt;
&lt;p&gt;You can also have individual patches inter weaved in there if you want. It
allows you to manage all of that directly within your patch stack, which is
just you focusing and thinking about logical patches.&lt;&#x2F;p&gt;
&lt;p&gt;So that&#x27;s the Patch Stack workflow.&lt;&#x2F;p&gt;
&lt;p&gt;The benefits of the Patch Stack workflow is that it gets you as close as
possible to continuous integration but gives you the flexibility of defining a
patch series if you need to.&lt;&#x2F;p&gt;
&lt;p&gt;So you don&#x27;t have that overhead of being required to manage these branches and
their dependencies between each other.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, it works with the existing tooling.&lt;&#x2F;p&gt;
&lt;p&gt;So it works with the normal GitHub, Bitbucket, GitLab, etc. and their Feature
Branch based review process.&lt;&#x2F;p&gt;
&lt;p&gt;So you don&#x27;t have to worry about any of this post commit review stuff, or the
tooling around that, or getting custom tooling made, or any of that stuff. You
just use the same tools you are likely already using.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, another benefit of this is that it facilitates adoption more easily.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s say you as an individual are impressed with what you&#x27;ve seen from the
atomic commit community and want to start adopting those practices.&lt;&#x2F;p&gt;
&lt;p&gt;But your team is still working in a Feature Branch workflow.&lt;&#x2F;p&gt;
&lt;p&gt;Well, that&#x27;s completely fine.&lt;&#x2F;p&gt;
&lt;p&gt;You can use the Patch Stack workflow locally and the rest of your team never
even has to know.&lt;&#x2F;p&gt;
&lt;p&gt;They don&#x27;t care, they just see a Pull Request, and they do a review, the same
way they have previously for the Feature Branch workflow.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h3&gt;
&lt;p&gt;So those are the four different workflows I wanted to talk about.&lt;&#x2F;p&gt;
&lt;p&gt;Hopefully, this helps clear up some of the concepts as well as some of the pros and cons of these four workflows.&lt;&#x2F;p&gt;
&lt;p&gt;Personally, I think the Patch Stack workflow makes the most sense.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, hope you enjoyed. Until next time.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Cursor based Pagination with multi-key cursor</title>
        <published>2023-04-02T00:00:00+00:00</published>
        <updated>2023-04-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/cursor-based-pagination-with-multi-key-cursor/"/>
        <id>https://drewdeponte.com/blog/cursor-based-pagination-with-multi-key-cursor/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/cursor-based-pagination-with-multi-key-cursor/">&lt;p&gt;Let&#x27;s say for sake of discussion that we want to paginate a set of transactions
to be presented in a mobile app with infinite scroll implemented. We will also
assume that for sake of discussion our service is backed by PostgreSQL as our
database.&lt;&#x2F;p&gt;
&lt;p&gt;We obviously want to see these transactions in relation to time. Probably the
most recently created transactions first and then the older transactions as we
scroll through the infinite scroll. So we will likely want to order these
transactions by their timestamp in descending order.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cursor-based-pagination&quot;&gt;Cursor based Pagination&lt;&#x2F;h2&gt;
&lt;p&gt;Because of our use case we can use a strategy called Cursor Based pagination.
In this strategy we pass a &quot;cursor&quot; identifying the transaction of the last
item in the previous pages results and a limit to get back the next page.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;use-transaction-datetime-as-cursor&quot;&gt;Use &lt;code&gt;transaction_datetime&lt;&#x2F;code&gt; as cursor&lt;&#x2F;h2&gt;
&lt;p&gt;You might be thinking, well we have the &lt;code&gt;transaction_datetime&lt;&#x2F;code&gt;, can&#x27;t we just
use that as the &quot;cursor&quot;. The answer is of course you could. However, if you
have timestamps that aren&#x27;t super granular. This happens when dealing with
banks &amp;amp; transactions as you will get back a full timestamp object, but it will
only have information for the day, month, and year. This means in your dataset
you may have a decent number of transactions that are all effectively at the
same timestamp.&lt;&#x2F;p&gt;
&lt;p&gt;This is problematic because you have to either do a where condition in your
query of &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt; or &lt;code&gt;&amp;lt;=&lt;&#x2F;code&gt; to the cursor. If we do &lt;code&gt;&amp;lt;&lt;&#x2F;code&gt; we will miss out on
transactions that should be visible. If we do &lt;code&gt;&amp;lt;=&lt;&#x2F;code&gt; we will end up with
duplicate transactions. Neither of these are acceptable from a user experience
standpoint.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-if-we-combine-transaction-datetime-with-another-cursor&quot;&gt;What if we combine &lt;code&gt;transaction_datetime&lt;&#x2F;code&gt; with another cursor&lt;&#x2F;h2&gt;
&lt;p&gt;Well if we for example had a UUID for the &lt;code&gt;id&lt;&#x2F;code&gt; column of a transaction we could
use that, as ordering of UUIDs would be consistent. This would allow us to have
a query like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;SELECT * FROM&lt;&#x2F;span&gt;&lt;span&gt; transactions &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;ORDER BY&lt;&#x2F;span&gt;&lt;span&gt; transaction_datetime &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;DESC&lt;&#x2F;span&gt;&lt;span&gt;, id &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;DESC&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above we use a primary order of &lt;code&gt;transaction_datetime&lt;&#x2F;code&gt; with a secondary
order of &lt;code&gt;id&lt;&#x2F;code&gt;. This makes it so that if there are multiple transactions
associated with the same &lt;code&gt;transaction_datetime&lt;&#x2F;code&gt; that they will all be
consistently ordered by the &lt;code&gt;id&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-the-next-page&quot;&gt;Getting the Next Page&lt;&#x2F;h2&gt;
&lt;p&gt;Somehow we have to use the cursor now composed of two values
&lt;code&gt;transaction_datetime&lt;&#x2F;code&gt; and &lt;code&gt;id&lt;&#x2F;code&gt; to figure out where the dataset should start
for the next page of values.&lt;&#x2F;p&gt;
&lt;p&gt;If we tried to do something like the following&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;SELECT * FROM&lt;&#x2F;span&gt;&lt;span&gt; transactions &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span&gt; transaction_datetime &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;2021-02-23 04:23:23&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; AND&lt;&#x2F;span&gt;&lt;span&gt; id &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;A234U-23432aue-2343aue-aauo234&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We would have a problem because we would be filtering out transactions that are
less than the datetime but greater than the UUID. In turn making the resulting
set not what we want.&lt;&#x2F;p&gt;
&lt;p&gt;So instead we have to use a feature of PostgreSQL called &lt;em&gt;Composite Values&lt;&#x2F;em&gt; in
the where query. I think of this as allowing us to create a tuple of
values that it then knows how to compare in combination rather than
individually.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;sql&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;SELECT * FROM&lt;&#x2F;span&gt;&lt;span&gt; transactions &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;WHERE&lt;&#x2F;span&gt;&lt;span&gt; (transaction_datetime, id) &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; (&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;2021-02-23 04:23:23&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;A234U-23432aue-2343aue-aauo234&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With this we actually get back the correct set as we are sorting on the
combined value not the individual values.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Inversion of Control</title>
        <published>2023-02-09T00:00:00+00:00</published>
        <updated>2023-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/inversion-of-control/"/>
        <id>https://drewdeponte.com/blog/inversion-of-control/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/inversion-of-control/">&lt;p&gt;Within the last month, I have interacted with several developers that don&#x27;t have
a great understanding of the concept of &lt;em&gt;Inversion of Control (IoC)&lt;&#x2F;em&gt;. Just the
other day one of the developers at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; asked me to explain it
after I mentioned it as a way of separating DB concerns from business logic
concerns when the DB concerns are tied together by a DB transaction.&lt;&#x2F;p&gt;
&lt;p&gt;I introduced this developer to the concept of &lt;em&gt;IoC&lt;&#x2F;em&gt; and walked him through how
I think about code and the concept of &lt;em&gt;Separation of Concerns&lt;&#x2F;em&gt; in a way that
enables me to more easily understand how and where to apply &lt;em&gt;IoC&lt;&#x2F;em&gt;. So I figured
I might as well write it up so that I can share it with the rest of the world
in hopes that it can help others as well.&lt;&#x2F;p&gt;
&lt;p&gt;So let&#x27;s get into it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-inversion-of-control&quot;&gt;What Is Inversion of Control?&lt;&#x2F;h2&gt;
&lt;p&gt;The other day I was talking to another developer about struggling to find a
good resource that really explained &lt;em&gt;IoC&lt;&#x2F;em&gt;, and half-jokingly he asked
ChatGPT to explain it with the following.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Can you explain the coding principle “inversion of control”?&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;It came back with the following.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Inversion of control (IoC) is a software design principle that encourages the
design of loosely coupled components in which the flow of control is not
determined by a component itself, but by a container or framework that is
responsible for assembling the components and coordinating their behavior.
This results in a separation of concerns between the components and the
container, where the components focus on their own specific tasks, while the
container is responsible for managing their interactions.&lt;&#x2F;p&gt;
&lt;p&gt;IoC is often achieved through dependency injection, in which the container
supplies the components with their dependencies, rather than the components
creating or looking up their own dependencies. This leads to a flexible and
modular architecture, where components can be easily replaced or reused
without affecting the rest of the system.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;To be honest it did a great job at returning a pretty clear definition of what
&lt;em&gt;IoC&lt;&#x2F;em&gt; is. Good enough in fact that I wouldn&#x27;t even try to change it. Trying to
get ChatGPT to provide meaningful examples in article form, that I could hand
someone to teach them &lt;em&gt;IoC&lt;&#x2F;em&gt;, was a massive failure. And as we all know being able
to read a conceptual definition like the one above and being able to understand
it, internalize it, and apply it while coding in the wild is an
entirely different thing. Hence, why I am writing this article.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ioc-at-all-the-levels&quot;&gt;IoC at all the levels&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;em&gt;IoC&lt;&#x2F;em&gt; as a concept is applied &amp;amp; can be applied across all the different levels
of abstraction in programming. At the higher levels, we can classically see it
with the distinction between the concept of libraries and frameworks.
Frameworks are simply libraries that apply the concept of &lt;em&gt;IoC&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If we consider how we use a GUI framework. We generally create some sort of
Application level object and call &lt;code&gt;run()&lt;&#x2F;code&gt; on it. The GUI framework is in
control of the flow of execution of the program and reaches out to other
objects, we provide, to ask them to perform different pieces and hand the
framework back results so that it can continue to manage the control flow of
the application. On the other hand, if we were using a GUI library. We would be
having to manage the control flow of the application ourselves, and we would in
turn be calling out to different functions&#x2F;methods in the library to do
different pieces for us. So with this distinction, we can see that in the
library case we are responsible for the control flow of the application but in
the framework case we hand that responsibility of control flow over to the
framework.&lt;&#x2F;p&gt;
&lt;p&gt;At the lower levels of abstraction, we classically see it with most higher-order
functions, especially the higher-order functions on collections, e.g. &lt;code&gt;map&lt;&#x2F;code&gt;,
&lt;code&gt;reduce&lt;&#x2F;code&gt;, &lt;code&gt;filter&lt;&#x2F;code&gt;, etc. If we consider using &lt;code&gt;filter&lt;&#x2F;code&gt; as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;someCollection&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;filter&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isOld&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are handing the control flow of the program over to the &lt;code&gt;filter()&lt;&#x2F;code&gt; procedure
while it asks us to provide criteria to filter with via the provided closure.
This is an example of &lt;em&gt;IoC&lt;&#x2F;em&gt; just as the framework vs. library concept is. The
big distinction between them is that in the case of a full application
framework you are handing over control for the lifetime of the application. In
the case of &lt;code&gt;filter()&lt;&#x2F;code&gt; we are handing over control only for the lifetime of
that particular application of the filter process.&lt;&#x2F;p&gt;
&lt;p&gt;The key is understanding that we can hand over the control flow of the
application at any of the levels of abstraction and it is all &lt;em&gt;IoC&lt;&#x2F;em&gt;. It is
inverting the control by handing it over to something that in classical
imperative procedural code does not have the &quot;control&quot;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;understanding-ioc-with-code&quot;&gt;Understanding IoC with Code&lt;&#x2F;h2&gt;
&lt;p&gt;To better understand how to think about this concept in relation to code let&#x27;s
take a look at a simple example where we have a collection of numbers and
we want to have a new collection of numbers that has each value in it but with
5 added to it. In classic imperative procedural code, we would implement this
something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;separation-of-concerns&quot;&gt;Separation of Concerns&lt;&#x2F;h3&gt;
&lt;p&gt;Before we can start to think about the possibility of applying the concept of
&lt;em&gt;IoC&lt;&#x2F;em&gt; we have some groundwork that we have to do first. We need to understand
the various &lt;em&gt;concerns&#x2F;responsibilities&lt;&#x2F;em&gt; involved in the code and classify the
various lines, statements, and expressions in terms of these
&lt;em&gt;concerns&#x2F;responsibilities&lt;&#x2F;em&gt;. It is also extremely useful to understand the
high-level goal of the segment of code being analyzed as it will help form our
thinking conceptually when applying &lt;em&gt;IoC&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It is probably worth talking about the idea of a &lt;em&gt;concern&lt;&#x2F;em&gt;, &lt;em&gt;responsibility&lt;&#x2F;em&gt;,
&lt;em&gt;domain&lt;&#x2F;em&gt;, or &lt;em&gt;problem space&lt;&#x2F;em&gt; which are mostly used interchangeably. They all are
used to define a particular bound around a problem. The difficulty people find
with them is that you can in theory take a bound around any problem and break
it down further into smaller bounds around sub-problems infinitely. The other
thing that people tend to find difficult is that they are arbitrary. Meaning
you can define the bounds to be whatever you want. In practice in software
development, this is simply defining a bound around a problem space and
generally mapping an abstraction of some sort to that bound.&lt;&#x2F;p&gt;
&lt;p&gt;This breaking up of a bound around a problem into sub-problems with their
bounds is the foundation of the concept of &lt;em&gt;Separation of Concerns&lt;&#x2F;em&gt;.
And as we will see throughout this process &lt;em&gt;IoC&lt;&#x2F;em&gt; is simply a specific example
of &lt;em&gt;Separation of Concerns&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;understanding-the-concerns&quot;&gt;Understanding the Concerns&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s take a look at the example from above and see if we can identify the
overall &lt;em&gt;concern&#x2F;responsibility&lt;&#x2F;em&gt; and then try to classify concerns that the
various lines of code belong to.&lt;&#x2F;p&gt;
&lt;p&gt;Overall the &lt;em&gt;concern&lt;&#x2F;em&gt; of the example above is to take the &lt;code&gt;myNumbers&lt;&#x2F;code&gt; array and
create a new array containing the values from &lt;code&gt;myNumbers&lt;&#x2F;code&gt; but with 5 added to
it. That doesn&#x27;t feel like much of a &lt;em&gt;concern&lt;&#x2F;em&gt;, but technically it is and since
it is what we have right now let&#x27;s run with it.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we feel like we have a high-level &lt;em&gt;concern&lt;&#x2F;em&gt; figured
out let&#x27;s think about &lt;em&gt;IoC&lt;&#x2F;em&gt; a bit deeper. We talked at a high level about what
the inversion portion of &lt;em&gt;IoC&lt;&#x2F;em&gt; is. But what is the control portion in our current
context. The way I think about it is by trying to break the overall &lt;em&gt;concern&lt;&#x2F;em&gt;
into &lt;em&gt;sub concerns&lt;&#x2F;em&gt; where one of the &lt;em&gt;sub concerns&lt;&#x2F;em&gt; is the &quot;control&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;To do that we need to understand what the &quot;control&quot; is. It is essentially any
portion of the code that controls the flow of a process. So we have to start
thinking about the code that controls the flow of a process as one &lt;em&gt;concern&lt;&#x2F;em&gt;
and the various steps&#x2F;pieces of the process as other &lt;em&gt;concerns&lt;&#x2F;em&gt;. I also think
about this as code representing one of two things, the triggering of doing
something &amp;amp; the actual how of doing something. So we can start thinking about
the ability to separate the how of doing something from the triggering of doing
something. It may not be a perfect way of thinking, but it has tended to help
me.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s try and define the various concerns of our example. It is important to
realize that this is a process. It isn&#x27;t magical, and you don&#x27;t always know all
the &lt;em&gt;concerns&lt;&#x2F;em&gt; right out of the gate. Sometimes you just start knowing that
one concern is the &quot;control&quot; and the others you aren&#x27;t sure about yet. Removing
the noise of the code that you know is the &quot;control&quot; can help you think more
clearly about the code that is &lt;strong&gt;not&lt;&#x2F;strong&gt; control and its respective &lt;em&gt;concerns&lt;&#x2F;em&gt;.
Below is our example from above in classical imperative procedural form. We
will annotate it with comments to try and communicate the concerns as we
progress below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looking at &lt;code&gt;const myNumbers: Array&amp;lt;number&amp;gt; = [2, 4, 7, 13]&lt;&#x2F;code&gt; it is just
providing the starting value for the process. It isn&#x27;t controlling the flow of
the process. Therefore, I would &lt;strong&gt;not&lt;&#x2F;strong&gt; classify it as part of the &quot;control&quot;
&lt;em&gt;concern&lt;&#x2F;em&gt;. So let&#x27;s tag it with an empty comment &lt;code&gt;&#x2F;&#x2F;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F; other&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we look at the &lt;code&gt;let myNewNumbers: Array&amp;lt;number&amp;gt; = []&lt;&#x2F;code&gt; on the first line of
code and ask ourselves &quot;Why is it there?&quot; In this case, it is there to
support the flow of this process by being the new array that the new values
will live in. So let&#x27;s flag it as &quot;control&quot; with a comment.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;            &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OK so what about the &lt;code&gt;for (num in myNumbers) {&lt;&#x2F;code&gt;? Well, it is there to
facilitate iterating through the collection. This sounds like
controlling the flow of the process to me. So let&#x27;s flag it as control.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;            &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                        &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                                               &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;OK, now we are onto &lt;code&gt;let newNum = num + 5&lt;&#x2F;code&gt;. This is interesting because this is
doing two things. The &lt;code&gt;let newNum =&lt;&#x2F;code&gt; portion is controlling the flow of the
process while the &lt;code&gt;num + 5&lt;&#x2F;code&gt; portion is more about the work of computing a new
value and not really about the flow control of the process. So let&#x27;s flag it to
specify this detail.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;            &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                        &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                        &#x2F;&#x2F; `let newNum =` control, `num + 5` some other concern&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                                               &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What about &lt;code&gt;myNewNumbers.push(newNum)&lt;&#x2F;code&gt;? This seems to be code that manages how
this process flows, so it seems to be control. Let&#x27;s flag it as control.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;            &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                        &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                        &#x2F;&#x2F; `let newNum =` control, `num + 5` some other concern&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                   &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;                                               &#x2F;&#x2F; control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, we have classified all lines, statements, and expressions of code,
and it feels like we have a pretty decent understanding of what code exists for
the purpose of controlling the flow of the process and which code doesn&#x27;t. In
fact there are only two chunks of code that don&#x27;t belong to the &quot;control&quot;
&lt;em&gt;concern&lt;&#x2F;em&gt;, &lt;code&gt;const myNumbers: Array&amp;lt;number&amp;gt; = [2, 4, 7, 13]&lt;&#x2F;code&gt; and &lt;code&gt;num + 5&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;grouping-separating-concerns&quot;&gt;Grouping &amp;amp; Separating Concerns&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we have an understanding of at least some portion of the various
concerns. We need to focus on conceptually grouping and separating them. In
our case, we have the &quot;control&quot; &lt;em&gt;concern&lt;&#x2F;em&gt; and then two pieces of code that right
now we know are not part of the &quot;control&quot; &lt;em&gt;concern&lt;&#x2F;em&gt;. The first step in
separating concerns is to simply map those concerns to specific abstractions.&lt;&#x2F;p&gt;
&lt;p&gt;To start let&#x27;s take all the code that is &quot;control&quot; code and extract it to a
function we will call &lt;code&gt;foo&lt;&#x2F;code&gt; for now. &lt;em&gt;Note:&lt;&#x2F;em&gt; I use a garbage name for the
function like &lt;code&gt;foo&lt;&#x2F;code&gt; right now because I like to think about the concern
conceptually after having moved the &quot;control&quot; code into it as I think it makes
it easier to think about. If we do this we end up with something like the
following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; _________&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; _______&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	    myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; myNewNumbers is now [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I put &lt;code&gt;________&lt;&#x2F;code&gt; in the function where the other &lt;em&gt;concerns&lt;&#x2F;em&gt; were interacting
before. This helps us think about those elements in a more generic way.
To make this function usable we have to fill in those &lt;code&gt;______&lt;&#x2F;code&gt; blanks. The only
way to do that while maintaining the abstraction is to pass them in as
parameters to the function. Our example would now look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	    myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;], (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; =&amp;gt; [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;By doing this we have not only made the &lt;code&gt;foo&lt;&#x2F;code&gt; function usable. But we have made
it more generic as we can now hand it any Array of numbers to operate on, and we
can hand it any operation to perform on each element as long as it results in a
number.&lt;&#x2F;p&gt;
&lt;p&gt;At this point, we have successfully &lt;strong&gt;inverted control&lt;&#x2F;strong&gt;, and we have done so by
identifying the control code, extracted it out into a function, and then using
that function in its original place. It is important to understand that this
is &lt;strong&gt;IoC&lt;&#x2F;strong&gt; because when we call the &lt;code&gt;foo()&lt;&#x2F;code&gt; function. We are handing control
over to the &lt;code&gt;foo()&lt;&#x2F;code&gt; function for the lifetime of the &lt;code&gt;foo()&lt;&#x2F;code&gt; process while we
are still providing the details of the work it does.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;generalize-types&quot;&gt;Generalize Types&lt;&#x2F;h3&gt;
&lt;p&gt;When using IoC it is common practice to generalize functions to remove
unnecessary coupling to specific types from the &quot;control&quot; code. This is another
mechanism for focusing only on the flow control of the process and less on the
specifics of the types involved. This also has the benefit of generally making
the extracted abstraction more flexible.&lt;&#x2F;p&gt;
&lt;p&gt;If we start by looking at &lt;code&gt;myNumbers: Array&amp;lt;number&amp;gt;&lt;&#x2F;code&gt; and that it is only used
in the &lt;code&gt;for (num in myNumbers)&lt;&#x2F;code&gt; line. &lt;code&gt;for (x in y)&lt;&#x2F;code&gt; doesn&#x27;t care what type of
array &lt;code&gt;y&lt;&#x2F;code&gt; is. It just cares that it is an Array. If we make that change it
would look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;myNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;number&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNumbers&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newNum&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	    myNewNumbers&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newNum&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; myNewNumbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;], (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; =&amp;gt; [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This creates a temporary problem which is that the typing of &lt;code&gt;op&lt;&#x2F;code&gt; would now
also need to change so that it would take in a &lt;code&gt;A&lt;&#x2F;code&gt;. And then we are immediately
confronted with the next question. What type does &lt;code&gt;op&lt;&#x2F;code&gt; return. From looking at
the code, currently we have the values ending up in &lt;code&gt;myNewNumbers&lt;&#x2F;code&gt; which is a
&lt;code&gt;Array&amp;lt;number&amp;gt;&lt;&#x2F;code&gt;. So we would have to have it return a &lt;code&gt;number&lt;&#x2F;code&gt; if we didn&#x27;t
change the code further. But it doesn&#x27;t seem like there is any reason we
shouldn&#x27;t just allow that array to be generic as well so that &lt;code&gt;op&lt;&#x2F;code&gt; can return a
different type. This would allow the user to convert the types of
elements within a collection if they wanted. We should also update the names of
the parameters to represent more generic concepts.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;collection&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newCollection&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;B&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; collection&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newItem&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	    newCollection&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newItem&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newCollection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;foo&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;], (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; =&amp;gt; [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above &lt;code&gt;foo()&lt;&#x2F;code&gt; function now supports our existing use case of wanting to add
5 to each element of the array but also supports a bunch of other cool things
we can do because we have simply focused on separating an abstraction that
focuses as much as possible on the control flow of the process. This is what
&lt;em&gt;Inversion of Control&lt;&#x2F;em&gt; is all about.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;naming-abstraction&quot;&gt;Naming Abstraction&lt;&#x2F;h3&gt;
&lt;p&gt;So now it seems we need to think about what our &lt;code&gt;foo()&lt;&#x2F;code&gt; function
facilitates as a process, and we should try and come up with a meaningful name.
It lets us map each element of a collection from one value into
another value. So maybe we should call it something like &lt;code&gt;map()&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; map&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;collection&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newCollection&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;B&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; in&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; collection&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newItem&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; op&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	    newCollection&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;push&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;newItem&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; newCollection&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;map&lt;&#x2F;span&gt;&lt;span&gt;([&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 13&lt;&#x2F;span&gt;&lt;span&gt;], (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;num&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; num&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; &#x2F;&#x2F; =&amp;gt; [7, 9, 12, 18]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is actually how the standard &lt;code&gt;map()&lt;&#x2F;code&gt; function is implemented.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We still have the &quot;other&quot; concern that we talked about before. What is
interesting is that through this process that concern has also received its own
abstraction, the &lt;code&gt;op&lt;&#x2F;code&gt; closure.&lt;&#x2F;p&gt;
&lt;p&gt;So now we can see fully how Inversion of Control is a specific type of
Separation of Concerns, as the &quot;control&quot; concern and &quot;map item value&quot; concern
have been separated by abstractions. We can also see how the standard &lt;code&gt;map&lt;&#x2F;code&gt;,
&lt;code&gt;reduce&lt;&#x2F;code&gt;, and &lt;code&gt;filter&lt;&#x2F;code&gt; functions are examples of IoC. But we have also seen
what the process looks like for classifying and separating concerns looks like,
which is a great skill that is applicable far beyond Inversion of Control.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Making Code Reusable</title>
        <published>2023-01-18T00:00:00+00:00</published>
        <updated>2023-01-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/making-code-reusable/"/>
        <id>https://drewdeponte.com/blog/making-code-reusable/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/making-code-reusable/">&lt;p&gt;One thing that people don&#x27;t seem to naturally understand is that to make code
reusable you have to make it generic. To get a better understanding of this
lets walk through some examples and see if we can get a better understanding of
some good ways to make code more generic.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s say we have a class called &lt;code&gt;User&lt;&#x2F;code&gt; and user has a &lt;code&gt;firstName&lt;&#x2F;code&gt; and
&lt;code&gt;lastName&lt;&#x2F;code&gt; properties. It might look something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) { }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we find out that there is a need to access the user&#x27;s &lt;code&gt;fullName&lt;&#x2F;code&gt; within the
application.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;computed-property-getter&quot;&gt;Computed Property&#x2F;Getter&lt;&#x2F;h2&gt;
&lt;p&gt;Most people&#x27;s natural instinct is to simply add a &lt;code&gt;fullName&lt;&#x2F;code&gt; getter to the
&lt;code&gt;User&lt;&#x2F;code&gt; class as a computed property.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) { }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  get&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; + this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is great! Our immediate need is met. It lets us get the full name of a
user as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Bob&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Villa&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fullUserName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;fullName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, this code isn&#x27;t reusable. You need to ask yourself, &quot;What does the
action of combining a first name and last name conceptually have to do with a
user?&quot; The answer is, nothing other than that the user happens to have a first
name and a last name.&lt;&#x2F;p&gt;
&lt;p&gt;So how do we go about making this code more reusable? Well, step one is going
back to the version of &lt;code&gt;User&lt;&#x2F;code&gt; that didn&#x27;t have a &lt;code&gt;fullName&lt;&#x2F;code&gt; getter.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) { }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;parameterized-function&quot;&gt;Parameterized Function&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s try pulling this &lt;code&gt;fullName&lt;&#x2F;code&gt; computed property out into a parameterized
function and see how that feels.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we can get the full name as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Alice&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Jones&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fullUserName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ok now that we have extracted this into a function that is parameterized based
on the &lt;code&gt;firstName&lt;&#x2F;code&gt; and &lt;code&gt;lastName&lt;&#x2F;code&gt; arguments it is able to combine any pair of
&lt;code&gt;firstName&lt;&#x2F;code&gt; and &lt;code&gt;lastName&lt;&#x2F;code&gt; irrespective of where they came from. This is now
reusable by definition.&lt;&#x2F;p&gt;
&lt;p&gt;However, you may have noticed that the ergonomics is not quite as nice as it
was with the Getter&#x2F;Method approach. Let&#x27;s see if we can improve the ergonomics
a bit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;function-parameterized-to-anonymous-interface&quot;&gt;Function Parameterized to Anonymous Interface&lt;&#x2F;h2&gt;
&lt;p&gt;One of the complexities we have is that with it strictly parameterized to
&lt;code&gt;firstName&lt;&#x2F;code&gt; and &lt;code&gt;lastName&lt;&#x2F;code&gt; we have to create a mapping between the
&lt;code&gt;otherUser.firstName&lt;&#x2F;code&gt; and the &lt;code&gt;otherUser.lastName&lt;&#x2F;code&gt; by passing them as
parameters. It would be nice if we could simply pass a &lt;code&gt;User&lt;&#x2F;code&gt; to the &lt;code&gt;fullName&lt;&#x2F;code&gt;
function.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This simply moves the knowledge of how to access the &lt;code&gt;firstName&lt;&#x2F;code&gt; and &lt;code&gt;lastName&lt;&#x2F;code&gt;
of the &lt;code&gt;User&lt;&#x2F;code&gt; object from outside the function to the inside the
function. This has a problem though. We just made the code no longer reusable,
because it once again only works with objects of type &lt;code&gt;User&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To address these we can use TypeScript&#x27;s anonymous interface typing to specify
that the function should accept any object that has both a property of
&lt;code&gt;firstName&lt;&#x2F;code&gt; and a property of &lt;code&gt;lastName&lt;&#x2F;code&gt;. This looks as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;named&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; })&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; named&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; named&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Which allows us to now get the full name of the user as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Bob&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Villa&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fullUserName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Woot woot! We regained the generic and reusable nature that we had in the
parameterized function but in the cases where we have an object that matches
the properties of &lt;code&gt;firstName&lt;&#x2F;code&gt; and &lt;code&gt;lastName&lt;&#x2F;code&gt; it streamlines the usage. In the
cases where the properties don&#x27;t match that we simply have to do a mapping
similar to the parameterized function example.&lt;&#x2F;p&gt;
&lt;p&gt;Another cool thing about this is that it is a function that takes a single
argument which now plays much nicer in a functional programming world.&lt;&#x2F;p&gt;
&lt;p&gt;One question people generally ask at this point is where do I put this
&lt;code&gt;fullName&lt;&#x2F;code&gt; function though. If it isn&#x27;t part of &lt;code&gt;User&lt;&#x2F;code&gt; it shouldn&#x27;t be in the
same file as &lt;code&gt;User&lt;&#x2F;code&gt;. I would argue you are correct. It has nothing to do with
&lt;code&gt;User&lt;&#x2F;code&gt;. This is where the concept of domain, a.k.a. problem space, a.k.a.
concern comes into play. Organizing code based on concern is a much more useful
strategy than by data as data is a byproduct of the concern. In this particular
case we have a concern of &quot;Name Composition&quot; so I would move it to a
TypeScript module named &lt;code&gt;name_composition.ts&lt;&#x2F;code&gt; for the time being.&lt;&#x2F;p&gt;
&lt;p&gt;You may have also noticed that we aren&#x27;t 100% back to the ergonomics oh what we
had at the very beginning with the Getter&#x2F;Method approach. We can gain the full
ergonomics back by adding the following getter to the &lt;code&gt;User&lt;&#x2F;code&gt; class as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) { }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  get&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;this&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gives us the best of both worlds as it gives us the reusability of the
&lt;code&gt;fullName()&lt;&#x2F;code&gt; function while also giving us the convenience of having the
operation be discoverable via tooling on the &lt;code&gt;User&lt;&#x2F;code&gt; class. In the end giving us
the ability to get the &lt;code&gt;fullName&lt;&#x2F;code&gt; with either of the two following approaches.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; User&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Bob&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Villa&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fullUserName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;user&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fullUserName2&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; user&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;fullName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I personally prefer not having the getter on the &lt;code&gt;User&lt;&#x2F;code&gt; class as it is just
another layer of abstraction that isn&#x27;t necessary. However, a lot of people
value the discoverability of operations through tooling on the &lt;code&gt;User&lt;&#x2F;code&gt; class to
a high degree and think it is worth the cost.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;function-parameterized-to-named-interface&quot;&gt;Function Parameterized to Named Interface&lt;&#x2F;h2&gt;
&lt;p&gt;Another option we have is to parameterize the function based on a named
interface. For example, we could have an interfaced called &lt;code&gt;Named&lt;&#x2F;code&gt; which would
described our constraints of an object that has both a &lt;code&gt;firstName&lt;&#x2F;code&gt; and
&lt;code&gt;lastName&lt;&#x2F;code&gt; property.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Named&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  lastName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This would then allow us to write our function as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fullName&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;named&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Named&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; named&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;firstName&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; named&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastName&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is definitely more readable and easier to conceptually understand that the
&lt;code&gt;fullName()&lt;&#x2F;code&gt; function operates on conceptually any named object. However, it
does add some more weight to the implementation. So I can see going back and
forth on this. I think if there is more than one function that operates on the
concept of a &lt;code&gt;Named&lt;&#x2F;code&gt; object then it should definitely be formalized as a named
interface. If it is a weird one off concept and function maybe it is fine to
use the anonymous interface approach.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If we look back at what we did at a high level it looks as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;question the belonging of some code&lt;&#x2F;li&gt;
&lt;li&gt;identify that it is &lt;strong&gt;not&lt;&#x2F;strong&gt; owned naturally by the class&lt;&#x2F;li&gt;
&lt;li&gt;extract it to a parameterized function&lt;&#x2F;li&gt;
&lt;li&gt;decide to parameterize with an interface (either anonymous&#x2F;named) or leave it multiple parameters&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This process is always the same. You just rinse and repeat the above steps over
and over again as you are coding, and you will end up with a far more robust,
meaningful, and reusable code base.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Continuous Integration Standards</title>
        <published>2022-07-22T00:00:00+00:00</published>
        <updated>2022-07-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-continuous-integration/"/>
        <id>https://drewdeponte.com/blog/uptech-continuous-integration/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-continuous-integration/">&lt;p&gt;We are experimenting with a new variation of our workflow based on the Continous Integration Methology. It is designed to facilitate feature level engineering reviews while still enabling us to follow the Continuous Integration Methodology and operate purely on the main trunk.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tl-dr&quot;&gt;TL;DR&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;create-patch&quot;&gt;Create Patch&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; and follow &lt;a href=&quot;&#x2F;blog&#x2F;uptech-git-commit&#x2F;&quot;&gt;Git Commit Standards&lt;&#x2F;a&gt; as you normal would.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;integrating-a-patches&quot;&gt;Integrating a Patches&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;integrate as soon as patch is complete and passes all automated checks verifying the requirements: &lt;strong&gt;buildable&lt;&#x2F;strong&gt;, &lt;strong&gt;testable&lt;&#x2F;strong&gt;, &lt;strong&gt;isolatable&lt;&#x2F;strong&gt;, &lt;strong&gt;releasble&lt;&#x2F;strong&gt; are met.&lt;&#x2F;li&gt;
&lt;li&gt;request review of the patch &amp;amp; &lt;strong&gt;immediately&lt;&#x2F;strong&gt; integrate the patch&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps rr &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps int &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; The &lt;code&gt;gps rr&lt;&#x2F;code&gt; is done solely to create notifications in GitHub as some people use those notifications to help with the &quot;Keeping up with the code base&quot;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;keeping-up-with-the-code-base&quot;&gt;Keeping up with the code base&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gps fetch&lt;&#x2F;code&gt; or &lt;code&gt;gps pull&lt;&#x2F;code&gt; show the upstream patches&lt;&#x2F;li&gt;
&lt;li&gt;scan patches to identify any that are of immediate interest
&lt;ul&gt;
&lt;li&gt;related to what you are working on&lt;&#x2F;li&gt;
&lt;li&gt;patch created by someone you are mentoring, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;review immediate interest patches by going to their GitHub Commit pages and commenting on the code with questions, suggestions, etc.&lt;&#x2F;li&gt;
&lt;li&gt;track patches you have looked at with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt; commit selection state &amp;amp; auto refresh&lt;&#x2F;li&gt;
&lt;li&gt;read the commits to keep up with understanding how the code base is changing. To comment, ask questions, or make suggestions open the GitHub Commit page for that commit.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Some people use the PR notifications in GitHub to help them do this.
Ideally we would have some better tooling around this. Exploration in this is still happening.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;complete-feature&quot;&gt;Complete Feature&lt;&#x2F;h3&gt;
&lt;p&gt;Once all your feature&#x27;s patches are integrated:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;add a git ticket summary for each of the repositories involved as a comment, use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;git-ticket-summary&quot;&gt;git-ticket-summary&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;move the user story you have been working to the &quot;Needs Review&quot; column.&lt;&#x2F;li&gt;
&lt;li&gt;move onto your next task until someone reviews your feature&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;feature-review&quot;&gt;Feature Review&lt;&#x2F;h3&gt;
&lt;p&gt;You sould try and review a feature everytime you put a story in &quot;Needs Review&quot;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;pick a story in the &quot;Needs Review&quot; column that you want to review&lt;&#x2F;li&gt;
&lt;li&gt;drag the story you are going to review to &quot;In Review&quot;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;review the feature&#x27;s functionality&lt;&#x2F;strong&gt; in the &lt;strong&gt;dev&lt;&#x2F;strong&gt; environment to gain context and make sure it is meeting all the acceptance criteria&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;review the application architecture&lt;&#x2F;strong&gt; involved (how this feature works through the application architecture) while noting any logic&#x2F;algorithms that need further focus&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;review logic&#x2F;algorithm design&lt;&#x2F;strong&gt; in any areas of possible concern identified above&lt;&#x2F;li&gt;
&lt;li&gt;provide your feedback on the feature&#x27;s application architecture &amp;amp; algorithms&#x2F;logic in the ticket&lt;&#x2F;li&gt;
&lt;li&gt;if helpful you can comment on code in the commits, but make sure you still reference it in your comments in the ticket&lt;&#x2F;li&gt;
&lt;li&gt;if there are changes that need to be made move the ticket back to &quot;In Progress&quot; for the developer to address the concerns&lt;&#x2F;li&gt;
&lt;li&gt;rinse and repeat&lt;&#x2F;li&gt;
&lt;li&gt;once the story is good move the ticket to &quot;Ready for Release&quot;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;references&quot;&gt;References&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;github-commit-pages&quot;&gt;GitHub Commit Pages&lt;&#x2F;h3&gt;
&lt;p&gt;If you aren&#x27;t familiar with GitHub&#x27;s Commit pages. You can access them with the following url structure.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&#x2F;commit&#x2F;da5944f6157ff29cedaf8972e7f82f0d4e7a3a8c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The SHA at the end of the URL, &lt;code&gt;da5944f6157ff29cedaf8972e7f82f0d4e7a3a8c&lt;&#x2F;code&gt;, can be replaced with an SHA or short SHA of a commit get the URL for that commits GitHub Commit page.&lt;&#x2F;p&gt;
&lt;p&gt;This is useful because GitHub allows you to inline comment on the within the commit similar to how you can within Pull Requests.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Some terminals support detecting and linking to the GitHub Commit Pages from the SHAs or short SHAs in the terminal buffers, e.g. Visual Studio Code, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;alacritty&#x2F;alacritty&quot;&gt;Alacritty&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sublime-merge&quot;&gt;Sublime Merge&lt;&#x2F;h3&gt;
&lt;p&gt;If you aren&#x27;t familiar with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt; it is a very nice cross-platform Git GUI that detects changes to the Git repo and auto refreshes state. This makes it extremely nice as you can be working in a terminal or another app and make changes and they automatically update and reflect in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the context of this process I keep it up with the repository opened and as I &lt;code&gt;gps pull&lt;&#x2F;code&gt; I can quickly and easily see the new patches in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt; and checkout the code right there. If I find something I need to comment on I simply open that commit&#x27;s GitHub Commit Page and start a discussion about the code.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Journey to Small Pull Requests</title>
        <published>2022-03-15T00:00:00+00:00</published>
        <updated>2022-03-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/journey-to-small-pull-requests/"/>
        <id>https://drewdeponte.com/blog/journey-to-small-pull-requests/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/journey-to-small-pull-requests/">&lt;p&gt;We were struggling to deal with our pull requests. We weren&#x27;t getting quality peer reviews from our peers, we were having a hard time reverting commits when necessary, and had a hard time understanding our &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; history.&lt;&#x2F;p&gt;
&lt;p&gt;So we decided to dig into this and see if we could get to the core of it and possibly come up with a solution.&lt;&#x2F;p&gt;
&lt;p&gt;The first thing was just understanding all the of the issues we were running into and coming to the conclusion that they are all a side effect of &lt;strong&gt;big&lt;&#x2F;strong&gt; pull requests.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Big&lt;&#x2F;strong&gt; pull requests&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;effectively &lt;strong&gt;eliminate the value of peer review&lt;&#x2F;strong&gt; as the changesets are just too overwhelming for people to focus on.&lt;&#x2F;li&gt;
&lt;li&gt;silo changes from the team &lt;strong&gt;delaying feedback&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;silo changes from the team &lt;strong&gt;postponing integration&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;make &lt;strong&gt;conflict resolution more difficult&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;encourage &lt;strong&gt;poor git history &amp;amp; practices&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;make it &lt;strong&gt;hard to revert changes&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;result in a &lt;strong&gt;complicated git history&lt;&#x2F;strong&gt; making it hard to look back and understand how best to interact with or even understand changes&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;why-are-they-so-big&quot;&gt;Why are they so big?&lt;&#x2F;h2&gt;
&lt;p&gt;After understanding the issues were coming from &lt;strong&gt;big&lt;&#x2F;strong&gt; pull requests we decided we should try and understand why our pull requests were so &lt;strong&gt;big&lt;&#x2F;strong&gt; and see if there was a good reason for it.&lt;&#x2F;p&gt;
&lt;p&gt;We were following the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;get-started&#x2F;quickstart&#x2F;github-flow&quot;&gt;GitHub Flow&lt;&#x2F;a&gt; and using feature branches, which in turn became our pull requests. Containing all the necessary changes for an entire feature turned out to be the primary reason that our pull requests were &lt;strong&gt;big&lt;&#x2F;strong&gt;. Not only that, we noticed that developers weren&#x27;t caring about the individual commits at all and would have partial or broken commits in their branches or even arbitrary save point commits. This resulted in making reverting commits more difficult as well as breaking useful features of git like &lt;code&gt;git bisect&lt;&#x2F;code&gt;.  Beyond that it lended to the issues we had identified before.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;alternatives&quot;&gt;Alternatives&lt;&#x2F;h2&gt;
&lt;p&gt;So now we knew that if we wanted our pull requests to be &lt;strong&gt;small&lt;&#x2F;strong&gt; we couldn&#x27;t use feature branches. Instead we would have to scope our changes by a smaller concept than a feature. To help us identify which scoping concepts made the most sense we researched many other development workflows. The two that stood out as being different were the Continous Integration Methodology and Trunk Based Development, as the others all seem to use feature branches.&lt;&#x2F;p&gt;
&lt;p&gt;Both the Continous Integration Methodology and Trunk Based Development are focused around getting small, logical, buildable, testable, not-necessarily complete changes into mainline as quickly as possible. They both see this as a core principle to support other developers on the team being aware of the work being done and enabling contribution and planning around it.&lt;&#x2F;p&gt;
&lt;p&gt;Digging further into how people follow these methodologies and scope their changes. It seems to range from a single small addition of an architectural concept (e.g. add method to class) to the addition of a small&#x2F;initial architectural concept (e.g. adding a small class).&lt;&#x2F;p&gt;
&lt;p&gt;One other difference is that people following these methodologies integrate code prior to it being utilized by other components. For example they would write a class and integrate that class prior to that class being used by whatever layers or features above it.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that they even go as far as using Feature Toggles to facilitate including code in the code base but preventing it from being executed. This allows all of the code to be integrated and shared with the development team as quickly and early as possible while still preventing consumers from seeing incomplete features.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-about-peer-review&quot;&gt;What about Peer Review?&lt;&#x2F;h2&gt;
&lt;p&gt;One of our driving forces for looking at alternatives was to eliminate our problems with our peer reviews. Turns out that Continuous Integration &amp;amp; Trunk Based Development don&#x27;t provide much guidance on that front.&lt;&#x2F;p&gt;
&lt;p&gt;Many Continous Integration &amp;amp; Trunk Based Development teams forego what we think of as a peer review process coming from feature branches. Instead they opt for getting the small, logical, buildable, testable, but not-necessarily complete changes into mainline as quickly as possible and then in theory go back and review each of the commits after the fact. This is known as &lt;strong&gt;Post-commit&lt;&#x2F;strong&gt; review. What we classically think of as peer review with feature branches is known as &lt;strong&gt;Pre-commit&lt;&#x2F;strong&gt; review. The difference is simply &lt;strong&gt;Post-commit&lt;&#x2F;strong&gt; happens after a commit is integrated into mainline while the &lt;strong&gt;Pre-commit&lt;&#x2F;strong&gt; happens prior to a change being integrated into mainline.&lt;&#x2F;p&gt;
&lt;p&gt;So we then started exploring the tools and processes around &lt;strong&gt;Post-commit&lt;&#x2F;strong&gt; peer review. Turns out that there isn&#x27;t much there and the few tools that do exist are relatively antiquated and also require a full shift in terms of tooling and mentality. This was effectively a no-go for us as we work with many different clients and dev teams which all use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt;&#x2F;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bitbucket.org&quot;&gt;Bitbucket&lt;&#x2F;a&gt; pull requests for peer review. So we needed to figure out a way to do &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; for &lt;strong&gt;Pre-commit&lt;&#x2F;strong&gt; peer reviews.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;branches-on-branches-on-branches&quot;&gt;Branches on, Branches, on Branches&lt;&#x2F;h2&gt;
&lt;p&gt;Following our only path forward for peer review, &lt;strong&gt;Pre-commit&lt;&#x2F;strong&gt;, we started making &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; scoped down just as people do in Continous Integration and Trunk Based Development. This was great as we were seeing the benefits of &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; and see that it definitely does address the issues we identified at the beginning. However there was a ton of extra overhead and complexities in terms of managing these branches locally.&lt;&#x2F;p&gt;
&lt;p&gt;Generally we focus on implementing a specific feature&#x2F;change. In order to do this we build up context around it in our mind so that we can plan and implement an appropriate change to achieve our goal. This is great when doing feature branches because there is a 1-to-1 mapping between that context and the branch. However, remember we are creating a number of pull requests that are small, logical, buildable, testable, and not-necessarily complete changes that when combined should accomplish the end goal of the feature&#x2F;change. Continous Integration and Trunk Based Development teams sometimes refer to these smaller changes as Proof of Work. Just like when you were a kid in school and the teacher made you show your work on your math homework. Each of the small changes should be logical steps showing how you achieved your end goal. You might think it is natural to just create a branch for each of these logical changes. However, what you quickly find is that the logical changes begin to have dependencies on other logical changes you have made.&lt;&#x2F;p&gt;
&lt;p&gt;This means for you to continue being able to develop the feature you effectively have to create your next branch on top of the previous branch and so on. You then end up with effectively a chain of branches composing up your feature. The only one you can actually open a pull request for is the inner most branch. This is because if you opened a pull request for any of the other branches it would also include the changes beneath it as well. Putting us back in the camp of &lt;strong&gt;big pull requests&lt;&#x2F;strong&gt; which we don&#x27;t want to be in.&lt;&#x2F;p&gt;
&lt;p&gt;So we continued our experiment and dealing with the branch management overhead by accepting that it is ok that the inner most branch is the only one you can open a pull request for until it is integrated into mainline. However we quickly ran into the next issue. What happens when someone provides feedback on the pull request of the inner most branch and you have to make changes to it. Well, you have to make changes to it and then effectively go rebase each of the branches above it ontop of eachother one by one all of over again. This made the branch management overhead just too much to deal with.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;eliminate-branch-management-overhead&quot;&gt;Eliminate Branch Management Overhead&lt;&#x2F;h2&gt;
&lt;p&gt;So for &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; to be viable we determined we needed to find some way to eliminate or at least streamline all this branch management overhead. We pondered and struggled with this over time largely feeling like maybe it wasn&#x27;t possible. However while researching development workflows of various teams we came across an old idea, the &lt;strong&gt;patch&lt;&#x2F;strong&gt;. Patches were how changes were managed and shared back in the day with many open source projects. A diff&#x2F;patch would be created and emailed to the maintainer of the project. They would then review the patch and either apply it or reply back to the email requesting changes.&lt;&#x2F;p&gt;
&lt;p&gt;Teams that use patches still generally require that they are small, logical, buildable, testable, and most importantly &lt;strong&gt;independent&lt;&#x2F;strong&gt;. &lt;strong&gt;Independent&lt;&#x2F;strong&gt; doesn&#x27;t mean that one patch can&#x27;t depend on another patch. But it means that if the patch doesn&#x27;t have to depend on another patch it shouldn&#x27;t. This is generally addressed by the need to be &lt;strong&gt;logical&lt;&#x2F;strong&gt;, but having the additional explicit requirement of &lt;strong&gt;independence&lt;&#x2F;strong&gt; is worth thinking about. In the cases where a patch must have a dependency on another patch it is simply handled by communicating the required order in which those particular patches must be integrated.&lt;&#x2F;p&gt;
&lt;p&gt;Another interesting thing that maintainers do is locally manage a stack of patches they have recieved from contributors as they prepare changes to go into mainline.&lt;&#x2F;p&gt;
&lt;p&gt;This got our brains rolling again and got us thinking maybe if we added this requirement of &lt;strong&gt;independence&lt;&#x2F;strong&gt; and we start conceptually thinking about our commits on &lt;code&gt;main&lt;&#x2F;code&gt; as a stack of patches resting on &lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt;. It would eliminate the branch overhead all together. Not only that, if we used the &lt;code&gt;pull.rebase = true&lt;&#x2F;code&gt; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; feature it would force us to integrate our local stack of patches every time we pull. This would get us even closer to Continuous Integration and Trunk Based Development.&lt;&#x2F;p&gt;
&lt;p&gt;So now we had all the branch overhead gone and we are closer to Continuous Integration and Trunk Based Development than we have ever been before. But we needed to be able to do the equivalent of sending a patch to a maintainer for review but using &lt;strong&gt;Pre-commit&lt;&#x2F;strong&gt; review via pull requests.&lt;&#x2F;p&gt;
&lt;p&gt;Given that we are targeting &lt;strong&gt;independence&lt;&#x2F;strong&gt; and thinking about these commits as patches. It seemed natural when we wanted to request review of a patch to simply create a branch and cherry-pick the particular patch into that branch so that we could make a pull request from it. This worked and was far less overhead than all the branch management in the other path. Not only that it then allows &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; to help push us to &lt;strong&gt;independence&lt;&#x2F;strong&gt; by calling us out when we request review of a patch and it is &lt;strong&gt;not&lt;&#x2F;strong&gt; independent.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;too-many-pull-requests&quot;&gt;Too Many Pull Requests?&lt;&#x2F;h2&gt;
&lt;p&gt;One concern we had initially with this workflow was how the increase in the number of pull requests would impact things both on the producing pull requests side as well as the reviewing pull reqeusts side.&lt;&#x2F;p&gt;
&lt;p&gt;On the producing pull requests side we were pleasently surprised that we actually eliminated overhead. Before we used to have to write a pull request summary and description to give context about what the pull request is for and what it does in addition to all the commit messages. This went away because when you have a single commit branch for a pull request it grabs the commit summary and message as the pull request summary and description.&lt;&#x2F;p&gt;
&lt;p&gt;You could argue that there must be additional overhead in terms of the context that must be included in the commit messages. For us there wasn&#x27;t as our &lt;a href=&quot;&#x2F;docs&#x2F;standards&#x2F;git-commit&quot;&gt;Git Commit Standards&lt;&#x2F;a&gt; already required us to write good commit messages that include the necessary context. If your team is coming from a place of not having good commit messages there will likely be a bit of overhead in terms of commit message writing. It is well worth it though and will pay dividends not only in supporting this workflow but also in supporting &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; history spelunking.&lt;&#x2F;p&gt;
&lt;p&gt;We were also pleasently suprised when we realized that we stopped caring about pull requests being reviewed immediately. It turns out that this is a wonderful side effect of having your patches in a stack. You can continue working on the feature without any branch overhead irrespective of it takes 30 mins or 2 days to get a review.&lt;&#x2F;p&gt;
&lt;p&gt;On the reviewing pull requests side of things the act of reviewing pull requests becomes a lot easier as everything you are reviewing is logically scoped, buildable, testable, etc. It allows you to really focus in on the change and how it plays out with the application architecture. It also makes it easier to allow your self to do some deep focus work as your team doesn&#x27;t have the incessant need to ping you about their pull request to get it reviewed instantly.&lt;&#x2F;p&gt;
&lt;p&gt;There are definitely more pull requests. But when you come up for air from your deep focus you just tackle reviewing a few pull requests instead of one giant one. We have found that the organization and separation of these pull requests has only increased the speed and quality of our peer reviews. It is probably also worth mentioning that we use a product of ours, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pullwalla&lt;&#x2F;a&gt;, to identify which pull requests need review. This also helps us stay in deep focus.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;outside-in-inside-out&quot;&gt;Outside-In &amp;amp; Inside-Out&lt;&#x2F;h2&gt;
&lt;p&gt;In addition we were unsure exactly how things would pan out in situations where we have to go down a path to figure out how to implement something. Turns out that following best practices and doing outside-in development works great with this workflow. The key addition is that once we get to the inner most dependency we work our way inside-out requesting review of the patches.&lt;&#x2F;p&gt;
&lt;p&gt;Basically what ends up happening is that you create a bunch of logical WIP commits as you work from the outside-in. You do this until you get to the the inner most dependency (C) that has all the dependencies it needs. That patch (C) of the inner most dependency is what is fully baked and ready to have a pull request open. You are confident that your changes in C met the needs of B because you just walked through from the outside-in understanding the needs before you implemented C.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A - WIP: Add ability for user to Login&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;B - WIP: Add login ability to authentication service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;C - Add login() function to core underlying authentication library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then you step back up to then next level above that (B) and you refine that patch updating it to use the stuff provided by C and make it no longer a WIP commit.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A - WIP: Add ability for user to Login&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;B - Add login ability to authentication service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;C - Add login() function to core underlying authentication library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point you open a pull request for B. Then you start working on refining patch A, using the bits that you implemented in B and get it to a good place.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;A - Add ability for user to Login&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;B - Add login ability to authentication service&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;C - Add login() function to core underlying authentication library&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point you have a patch that technically implements the feature from a user perspective &amp;amp; adds the associated e2e tests. This is still a small, logical, buildable, testable, patch that you open a pull request for. The peer reviewer understand that this patch adds the feature and therefore when they review this pull request they do the full feature review as well as code review. Generally these inner patches are paired with unit tests while the outer most feature patch is paired with e2e tests.&lt;&#x2F;p&gt;
&lt;p&gt;There are many ways this can vary. For example with someone not doing outside-in development or maybe you have multiple internal dependency patches that aren’t intertwined. I think the important thing is just that the pull requests are opened from the inside-out.&lt;&#x2F;p&gt;
&lt;p&gt;Also one of the beautiful things about this workflow is that it decouples you from caring about how quickly your pull requests get reviewed because you are able to still continue development of your feature irrespective of how long it takes someone to review your pull requests. This happens thanks to the fact that the patch stack continues to hold the patches even after requesting review.&lt;&#x2F;p&gt;
&lt;p&gt;Further details on this process of outside-in and inside-out in relation to this workflow are covered in our article &lt;a href=&quot;&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using Git&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ticketing-alignment&quot;&gt;Ticketing Alignment&lt;&#x2F;h2&gt;
&lt;p&gt;When we were doing feature branches before the ticketing alignment was trivial. We basically had a 1-to-1 mapping between a user story and feature pull request. With the Git Patch Stack methodology we had to make a choice. Do we have multiple patches reference a single user story or do we modify how we do ticketing so that it better aligns with the logical patches.&lt;&#x2F;p&gt;
&lt;p&gt;After thinking about it briefly we decided that it makes the most sense to just have multiple patches reference the same user story. Each of the patches could also reference any related sub-tasks that belong to the parenting user story. The key for this to be successful is really just providing the necessary context in the patch commit messages.&lt;&#x2F;p&gt;
&lt;p&gt;The alternate path of changing how we define and structure tickets seemed like a bad idea as it would have required not just engineering to change but also the product and project managers.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;git-patch-stack&quot;&gt;Git Patch Stack&lt;&#x2F;h2&gt;
&lt;p&gt;After using this workflow and seeing and feeling the value that &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; provide. We decided we could relatively easily streamline the little bit of branch overhead involved with this workflow and further enforce the conceptual thinking around patches by creating a simple &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; extension.&lt;&#x2F;p&gt;
&lt;p&gt;So we created &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; and it has only further solidified the workflow, the mentality around it, and the vast benefits that fall out of &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; and this workflow in general.&lt;&#x2F;p&gt;
&lt;p&gt;For a deeper dive on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt;, this workflow and concepts to help identify these smaller logical chunks of work, see our post on &lt;a href=&quot;&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using Git&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Pull Request Standards</title>
        <published>2022-03-01T00:00:00+00:00</published>
        <updated>2022-03-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-pull-request/"/>
        <id>https://drewdeponte.com/blog/uptech-pull-request/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-pull-request/">&lt;p&gt;We &lt;strong&gt;require&lt;&#x2F;strong&gt; that Pull Requests have the following characteristics.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;small&lt;&#x2F;li&gt;
&lt;li&gt;logical&lt;&#x2F;li&gt;
&lt;li&gt;buildable&lt;&#x2F;li&gt;
&lt;li&gt;testable&lt;&#x2F;li&gt;
&lt;li&gt;releasable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;small&quot;&gt;Small&lt;&#x2F;h3&gt;
&lt;p&gt;It is crucial that pull requests are &lt;strong&gt;small&lt;&#x2F;strong&gt;. The quality of peer review exponentially decreases as the size of the pull request increases. If you are going to have PRs in the hundreds or thousands of lines of change range you may as well just not do peer review. Here at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; we believe in producing the highest quality code that we can and therefore we &lt;strong&gt;must&lt;&#x2F;strong&gt; have &lt;strong&gt;small&lt;&#x2F;strong&gt; pull requests.&lt;&#x2F;p&gt;
&lt;p&gt;If you are interested in how we got to small pull requests, checkout our post &lt;a href=&quot;&#x2F;blog&#x2F;journey-to-small-pull-requests&quot;&gt;Journey to Small Pull Requests&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;logical&quot;&gt;Logical&lt;&#x2F;h3&gt;
&lt;p&gt;It is also important that pull requests are &lt;strong&gt;logical&lt;&#x2F;strong&gt;. This means that the bounds of the content are well ordered and have clear &amp;amp; sound reasoning.&lt;&#x2F;p&gt;
&lt;p&gt;You might say well a &lt;em&gt;feature&lt;&#x2F;em&gt; is &lt;strong&gt;logical&lt;&#x2F;strong&gt;. Well, you would be correct. However, having a pull request contain an entire feature is in contradiction with the requirement of a pull request being small. Therefore we need to find some other logical bounding for the change. Generally application architecture concepts are a great aid for this. For example you could have a pull request that adds a method to a service to allow consumers to get a collection of items which would be logically bound around the change to that service. It could also be that you are making a cross-cutting change that is still logical. For example you could have a pull lequest that changes code from using strings to symbols which is spread across multiple application architecture concepts but is still &lt;strong&gt;logical&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Having a pull request be logical is crucial not only for understanding the evolution of the code base over time but is crucial to support functionality in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; like &lt;code&gt;bisect&lt;&#x2F;code&gt; and &lt;code&gt;revert&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;buildable&quot;&gt;Buildable&lt;&#x2F;h2&gt;
&lt;p&gt;Pull requests also must be &lt;strong&gt;buildable&lt;&#x2F;strong&gt;. Meaning that the state of the code in the pull request has to be in such a place that the library&#x2F;framework&#x2F;application&#x2F;suite can be built without error. This is crucial again to support functionality in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; like &lt;code&gt;bisect&lt;&#x2F;code&gt; and &lt;code&gt;revert&lt;&#x2F;code&gt; but is also import to not impede the development process of the team.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testable&quot;&gt;Testable&lt;&#x2F;h2&gt;
&lt;p&gt;A pull request being &lt;strong&gt;testable&lt;&#x2F;strong&gt; means that the change has automated tests covering it and that the test suite is able to be run with those tests included. In cases where code isn&#x27;t able to be tested with automated tests, maybe some UI change, then the changes have to be &lt;strong&gt;manually testable&lt;&#x2F;strong&gt; and the pull request description should include enough information to educate someone on how to manually test it.&lt;&#x2F;p&gt;
&lt;p&gt;This is crucial, especially when making smaller pull requests because it doesn&#x27;t make sense to pull down a pull request and manually test changes to an internal application architecture concept. So instead of getting our confidence from manual testing we get it through making sure that we have well written automated test coverage and that they are passing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;releasable&quot;&gt;Releasable&lt;&#x2F;h2&gt;
&lt;p&gt;We also require a pull request to be &lt;strong&gt;releasable&lt;&#x2F;strong&gt;. This doesn&#x27;t mean that you would idealisticly want to cut a release with just this one pull request. But it means that if push came to shove and you needed to for some reason the application&#x2F;library would be in such a state where it could be released.&lt;&#x2F;p&gt;
&lt;p&gt;This generally is a pretty easy requirement to meet as you can have code in your code base that is &lt;strong&gt;buildable&lt;&#x2F;strong&gt; &amp;amp; &lt;strong&gt;testable&lt;&#x2F;strong&gt; that isn&#x27;t used, and that is totally fine. The complexity with this requirement comes when you are dealing with changes that are visible to the consumer of the library&#x2F;application. That is where you have to then ask yourself if I make this change to the UI if push came to shove would this change be &lt;strong&gt;releasable&lt;&#x2F;strong&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;Remember it isn&#x27;t that if it was released it would be the ideal release. It is that it would be possible to release it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Backend Web Framework Design Exploration - Part 3</title>
        <published>2022-01-05T00:00:00+00:00</published>
        <updated>2022-01-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/be-wf-design-exploration-part-003/"/>
        <id>https://drewdeponte.com/blog/be-wf-design-exploration-part-003/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/be-wf-design-exploration-part-003/">&lt;p&gt;This is the third in a series of articles I am writing in which I do a Design
Exploration of a Backend Web Framework with the following constraints.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;only use functions &amp;amp; data - no classes w&#x2F; methods&lt;&#x2F;li&gt;
&lt;li&gt;use strong typing (via TypeScript) - no use of &lt;code&gt;any&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;trivially testable via basic unit style state based tests&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you didn&#x27;t start at the beginning I highly recommend it,
&lt;a href=&quot;&#x2F;blog&#x2F;be-wf-design-exploration-part-001&#x2F;&quot;&gt;Backend Web Framework Design Exploration - Part 1&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Within this article I will include simplified code examples. If however
you are interested in the real code &amp;amp; tests I used to do this design
exploration you can see them via the commits at my
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;be-wf-design-exploration&quot;&gt;be-wf-design-exploration&lt;&#x2F;a&gt;
Git repository.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dependencies-constructed-per-request&quot;&gt;Dependencies Constructed per Request&lt;&#x2F;h2&gt;
&lt;p&gt;Picking up where I left off in the previous article. I need to figure out how
this web framework should support Dependencies that need to be constructed
fresh per Request. This is something that most web frameworks support via their
dependency injection frameworks. Of course I have to manage this while
following the 3 key constraints above.&lt;&#x2F;p&gt;
&lt;p&gt;Previously I had the &lt;code&gt;fooHandler&lt;&#x2F;code&gt; with a dependency of &lt;code&gt;dbPool&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;RouteHandler&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span&gt;, body:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; dbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I am going to expand on this example with the &lt;code&gt;DatabasePool&lt;&#x2F;code&gt; by saying that our
&lt;code&gt;fooHandler&lt;&#x2F;code&gt; also needs another database pool. However, this one needed to be
constructed fresh with each request.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dependency-injection-frameworks&quot;&gt;Dependency Injection Frameworks&lt;&#x2F;h3&gt;
&lt;p&gt;Looking at all the dependency injection frameworks I have worked with. They are
effectively a set of functions that are registered often by type or name. Then
at some later point in time you call a dependency injection framework function
to instantiate an instance by either a type or name.  Often times the
registered function is executed only the first time and then memoized as a
singleton.  Effectively making them global singletons.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;functions-as-parameters&quot;&gt;Functions as Parameters&lt;&#x2F;h3&gt;
&lt;p&gt;Thinking about dependency injection frameworks and the fact that I need
something that can at some later point in time give me back in instance of this
other &lt;code&gt;DatabasePool&lt;&#x2F;code&gt;. It sounds very much to me like a function that is simply
responsible for knowing how to construct this other &lt;code&gt;DatabasePool&lt;&#x2F;code&gt; is the key.
In fact it can just be an explicit dependency of the &lt;code&gt;fooHandler&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This aligns at a high level with how common Dependency Injection frameworks
work to some extent while also abiding by the constraints. Specifically the
explicit dependency declaration constaint. Which in turn supports the trivial
testing requirement.&lt;&#x2F;p&gt;
&lt;p&gt;Applying this concept to a handler might look something like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  getOtherDbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;RouteHandler&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; otherDbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; getOtherDbPool&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span&gt;, body: `${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt; &amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;otherDbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;}` };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the usage in the routes builder looking as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; buildRoutes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; getOtherDbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Routes&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; getOtherDbPool&lt;&#x2F;span&gt;&lt;span&gt;) },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;bar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; barHandler&lt;&#x2F;span&gt;&lt;span&gt;() },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;health&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; healthHandler&lt;&#x2F;span&gt;&lt;span&gt;() },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;maybe-use-environment&quot;&gt;Maybe use Environment&lt;&#x2F;h3&gt;
&lt;p&gt;Some frameworks I have worked with use a concept known as Environments for
dependency injection. Basically, it is just a formalized Type that you
explicitly pass in as a parameter to your function that houses all your
dependency injection dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;The environment for &lt;code&gt;fooHandler&lt;&#x2F;code&gt; might look something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; FooEnvironment&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;	getOtherDbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then I could use it in place of the parameters of &lt;code&gt;fooHandler&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; FooEnvironment&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;RouteHandler&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; otherDbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; environment&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;getOtherDbPool&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span&gt;, body: `${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;environment&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt; &amp;amp; &lt;&#x2F;span&gt;&lt;span&gt;${&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;otherDbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;id&lt;&#x2F;span&gt;&lt;span&gt;}` };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looking at this I think the real value is that it facilitates grouping of
dependencies together. I think this would be valuable for grouping dependencies
maybe at a module level. I guess the only other value I would see from this on
a handler basis is just to provide a more defined convention for how a user
would want get dependencies into the handler. However, I could also just
provide examples probably without the need for this.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;review-next-up&quot;&gt;Review &amp;amp; Next Up&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at all of the above. The passing a function as an explicit dependency
to get get an instance of a something per request seems like the most direct
solution. It also meets all the constraints.&lt;&#x2F;p&gt;
&lt;p&gt;The Environment concept might make more sense if later on I decided that
requiring some modularization makes sense and therefore grouping dependencies
by module makes sense. But until then I think starting with the function
paramater technique makes the most sense.&lt;&#x2F;p&gt;
&lt;p&gt;Both of these techniques enable more precision in terms of instance creation
than being bound to a Request. This is because the handler can call the
function multiple times.&lt;&#x2F;p&gt;
&lt;p&gt;It is worth recognizing that it is really the &lt;strong&gt;builder function&lt;&#x2F;strong&gt; technique
that is still facilitating all of this. It is just that being able to pass a
function as a parameter combined with that approach facilitates this specific
use case.&lt;&#x2F;p&gt;
&lt;p&gt;This concept of &lt;strong&gt;builder function&lt;&#x2F;strong&gt; is used generally to implement the concept
of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Currying&quot;&gt;currying&lt;&#x2F;a&gt; in function programming.&lt;&#x2F;p&gt;
&lt;p&gt;Next up is figuring out midddleware &amp;amp; guards and how they might work in this
framework.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Backend Web Framework Design Exploration - Part 2</title>
        <published>2022-01-03T00:00:00+00:00</published>
        <updated>2022-01-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/be-wf-design-exploration-part-002/"/>
        <id>https://drewdeponte.com/blog/be-wf-design-exploration-part-002/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/be-wf-design-exploration-part-002/">&lt;p&gt;This is the second in a series of articles I am writing in which I do a Design
Exploration of a Backend Web Framework with the following constraints.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;only use functions &amp;amp; data - no classes w&#x2F; methods&lt;&#x2F;li&gt;
&lt;li&gt;use strong typing (via TypeScript) - no use of &lt;code&gt;any&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;trivially testable via basic unit style state based tests&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If you didn&#x27;t start at the beginning I highly recommend it,
&lt;a href=&quot;&#x2F;blog&#x2F;be-wf-design-exploration-part-001&#x2F;&quot;&gt;Backend Web Framework Design Exploration - Part 1&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Within this article I will include simplified code examples. If however
you are interested in the real code &amp;amp; tests I used to do this design
exploration you can see them via the commits at my
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;be-wf-design-exploration&quot;&gt;be-wf-design-exploration&lt;&#x2F;a&gt;
Git repository.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;dependency-injection-for-handlers&quot;&gt;Dependency Injection for Handlers&lt;&#x2F;h2&gt;
&lt;p&gt;Picking up where I left off in the previous article. I need to figure out how
this web framework should support injecting dependencies into handlers while
still supporting the 3 constraints above.&lt;&#x2F;p&gt;
&lt;p&gt;A very common use case for this would be for a handler to need to interact
with a database. This is generally done through a database connection pool.
So I am going to use that as an example use case.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;builder-function-technique&quot;&gt;Builder Function Technique&lt;&#x2F;h3&gt;
&lt;p&gt;In the previous article I used the &lt;strong&gt;builder function&lt;&#x2F;strong&gt; technique while
implementing the &lt;code&gt;router&lt;&#x2F;code&gt; function so that I could give that scope dependencies
while keeping the router signature the same &lt;code&gt;(Request) =&amp;gt; Route&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I can simply use the same technique here but applied to a handler if it needs
a dependency or two like a &lt;code&gt;dbPool&lt;&#x2F;code&gt; or something.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; RouteHandler&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; dbConn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; dbPool&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;getConnect&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; queryResults&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; dbConn&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;query&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some query&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This changes how I have to use it in the route definitions as we have to pass
the &lt;code&gt;dbPool&lt;&#x2F;code&gt; into the &lt;code&gt;fooHandler&lt;&#x2F;code&gt; builder function as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;) },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;bar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; barHandler&lt;&#x2F;span&gt;&lt;span&gt; }];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is functionally just fine. The handler resulting from the &lt;code&gt;fooHandler&lt;&#x2F;code&gt;
builder function is trivial to test via state based unit testing. However, if I
try to do an end-to-end test lets say as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;end-to-end request -&amp;gt; response&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { path: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some&#x2F;path&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;response&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;status&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I would have a big problem because it would be using the real database pool.
This is something that I want to be able to stub out in our end-to-end unit
tests.&lt;&#x2F;p&gt;
&lt;p&gt;This &lt;strong&gt;builder function&lt;&#x2F;strong&gt; technique can come in and save the day again. If I
apply the concept to building the routes and then use explicit dependency
declaration I get something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; buildRoutes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DatabasePool&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Routes&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;) },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;bar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; barHandler&lt;&#x2F;span&gt;&lt;span&gt; }];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case I am not building another function as I have in the past, but
instead I am building a collection of routes.&lt;&#x2F;p&gt;
&lt;p&gt;Which now enables the simple unit style testing at the higher end-to-end level
while still being able to stub out the &lt;code&gt;dbPool&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;end-to-end request -&amp;gt; response&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { path: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some&#x2F;path&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;buildRoutes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbPool&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;response&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;status&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;buildRoutes&lt;&#x2F;code&gt; &lt;strong&gt;builder function&lt;&#x2F;strong&gt; can be used to support other
dependencies as well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;review-next-up&quot;&gt;Review &amp;amp; Next Up&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at things thus far I think design wise it is still in a very good
place. This idea of using a &lt;strong&gt;builder function&lt;&#x2F;strong&gt; to build the routes helps
me meet all the constraints. It also provides a natural logical grouping of routes.&lt;&#x2F;p&gt;
&lt;p&gt;For example I could do something like define a builder specific to a particular
REST resource and compose its routes together with those of another builder.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;concat&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				buildResourceARoutes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbConn&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				buildResourceBRoutes&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbConn&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Beyond that it can provide a natural grouping mechanism for dependencies.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;().&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;concat&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				buildRoutesNeedingDb&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dbConn&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				buildRoutesNeeding&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;depA&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; depB&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; depC&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above two &lt;code&gt;concat&lt;&#x2F;code&gt; examples don&#x27;t read the nicest. But that is easy enough
to fix with the addition of another function to make composition of routes
easier if later on I decide it is worth it.&lt;&#x2F;p&gt;
&lt;p&gt;Next up I am planning on tackeling how I address dependencies that should
be constructed fresh for each request.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Backend Web Framework Design Exploration - Part 1</title>
        <published>2021-12-30T00:00:00+00:00</published>
        <updated>2021-12-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/be-wf-design-exploration-part-001/"/>
        <id>https://drewdeponte.com/blog/be-wf-design-exploration-part-001/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/be-wf-design-exploration-part-001/">&lt;p&gt;This is the first in a series of articles I am writing in which I do a Design
Exploration of a Backend Web Framework with the following constraints.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;only use functions &amp;amp; data - no classes w&#x2F; methods&lt;&#x2F;li&gt;
&lt;li&gt;use strong typing (via TypeScript) - no use of &lt;code&gt;any&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;trivially testable via basic unit style state based tests&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; Within this article I will include simplified code examples. If however
you are interested in the real code &amp;amp; tests I used to do this design
exploration you can see them via the commits at my
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;be-wf-design-exploration&quot;&gt;be-wf-design-exploration&lt;&#x2F;a&gt;
Git repository.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-the-constraints&quot;&gt;Why the constraints?&lt;&#x2F;h2&gt;
&lt;p&gt;It has been my experience that applying constraints like this pushes you
to think about problem solving in different ways. My hope is that by forcing
myself to think within these constraints that I will have some valuable take
aways in terms of deeper understandings of design principles and best
practices.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-these-constraints&quot;&gt;Why these constraints?&lt;&#x2F;h2&gt;
&lt;p&gt;Throughout my career I have used a lot of different backend web frameworks in a
lot of different languages. Sadly I can&#x27;t think of one that actually
facilitates end-to-end &lt;code&gt;request -&amp;gt; response&lt;&#x2F;code&gt; testing in a simple unit testing style.
Generally you have to do a bunch of horrible magic to facilitate dealing with
dependencies (database, etc.) or use a bunch of unique magic provided by the
framework.&lt;&#x2F;p&gt;
&lt;p&gt;I believe this magic is unnecessary nonsense and that it is possible to
design a framework in such a way that would naturally facilitate simple unit
style testing.  Hence, the constraint of requiring everything be trivially
testable via basic unit style state based tests.&lt;&#x2F;p&gt;
&lt;p&gt;Additionally, I am constantly faced with developers having this strange
impulsive fear of functions.  These developers generally build classes that
have no real state and no need to actually be a class.  In fact they seem to
simply use the class to implicitly share dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;I think this conciously or unconciously boils down to people thinking that
explicit dependency declarations via function paramaters are bad. I believe
this is due to people worrying about &quot;threading&quot; dependencies through layers
and layers of functions and not understanding how modularity works.&lt;&#x2F;p&gt;
&lt;p&gt;My instinct is that explicit dependency declaration is extremely valuable. Not
only does it facilitate testing but  it can also act as an indicator of poor
design. For example seeing heavy parameter &quot;threading&quot; should tell you
something is likely off with the design.  Therefore I have included the
constraint of only using functions &amp;amp; data to try and prove not only to myself
but hopefully to others that using explicit dependency declarations is
extremely valuable.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, over the years I have moved further and further away from dynamic
languages and closer to static strongly typed languages. The amount of aid the
the compiler provides these days is amazingly valuable and I believe it outways
the limitations.  So I thought it would be interesting to see what sort of
implications there are from having that requirement in this context.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;guiding-architectural-concept&quot;&gt;Guiding Architectural Concept&lt;&#x2F;h2&gt;
&lt;p&gt;For the sake of discussion lets say we want a web framework that would help us
build a REST API. REST APIs are built on top of the HTTP protocol and the
HTTP protocol is a Request-Response protocol. That means that a client makes a
request with some data and the server responds with some data.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;be-wf-design-exploration-part-001&#x2F;high-level-client-server.png&quot; alt=&quot;Client Server&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;When I think about this Request-Response concept it feels very similar to the
concept of a &lt;strong&gt;function&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; add&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When you call the function &lt;code&gt;add(5, 2)&lt;&#x2F;code&gt; it is equivalent in my eyes to a client
making a &lt;strong&gt;request&lt;&#x2F;strong&gt; to a server with the data &lt;code&gt;{ &quot;x&quot;: 5, &quot;y&quot;: 2 }&lt;&#x2F;code&gt; and getting
back a &lt;strong&gt;response&lt;&#x2F;strong&gt;, in this case the return value of the function.&lt;&#x2F;p&gt;
&lt;p&gt;Given such similarity to a concept that exists naturally in all these languages
I am going to think of each request-response pair as a function in the hope
that it can help guide my design.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-a-backend-web-framework-does&quot;&gt;What a Backend Web Framework does?&lt;&#x2F;h2&gt;
&lt;p&gt;I am going to start by focusing on the core functionality of the framework and
see if I can evolve it from there.  At the most basic level I think a Backend
Web Framework needs to do the following.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Receive a request&lt;&#x2F;li&gt;
&lt;li&gt;Identify the request &amp;amp; it&#x27;s associated handler&lt;&#x2F;li&gt;
&lt;li&gt;Execute the matched handler&lt;&#x2F;li&gt;
&lt;li&gt;Receive the response from the handler&lt;&#x2F;li&gt;
&lt;li&gt;Transport the response back to the client&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;design-001&quot;&gt;Design 001&lt;&#x2F;h3&gt;
&lt;p&gt;Naively this might look something like the following.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;be-wf-design-exploration-part-001&#x2F;design-001.png&quot; alt=&quot;Design 001&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;However this design has one major problem. The &lt;code&gt;router&lt;&#x2F;code&gt; doesn&#x27;t meet &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Single-responsibility_principle&quot;&gt;single
responsibility principle&lt;&#x2F;a&gt;. Infact in this design it is responsible for doing the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;mapping a request to a handler&lt;&#x2F;li&gt;
&lt;li&gt;coordinating execution of the handler &amp;amp; tunneling the response&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This problem would prevent the &lt;code&gt;router&lt;&#x2F;code&gt; from being tested in isolation from
the execution of the mapped handler which goes against defined constraints.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;design-002&quot;&gt;Design 002&lt;&#x2F;h3&gt;
&lt;p&gt;Taking the learnings from the first design. I decided to separate the concerns
of the &lt;strong&gt;mapping a request to a handler&lt;&#x2F;strong&gt; and the &lt;strong&gt;coordination of the
execution of a handler&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;be-wf-design-exploration-part-001&#x2F;design-002-w-improvements.png&quot; alt=&quot;Design 002&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This shift now makes it so the &lt;strong&gt;process request&lt;&#x2F;strong&gt; &amp;amp; &lt;strong&gt;router&lt;&#x2F;strong&gt; abide by the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Single-responsibility_principle&quot;&gt;single responsibility principle&lt;&#x2F;a&gt;. In turn enabling testing of the router
configuration in isolation.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;initial-framework&quot;&gt;Initial Framework&lt;&#x2F;h2&gt;
&lt;p&gt;The following is the initial framework implementation based on Design 002. To
see the full implementation at this stage checkout commit
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;be-wf-design-exploration&#x2F;commit&#x2F;9bd3e3a30c330736e9620ca0c60b98e9e58fd8a8?diff=unified&quot;&gt;9bd3e3&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  path&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  status&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; number&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;  &#x2F;&#x2F; ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; RouteHandler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; interface&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Route&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  pattern&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;  handler&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; RouteHandler&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Array&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Route&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Router&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Route&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; routeMatches&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; route&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Route&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Bool&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Route&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Router&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Route&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; matchedRoute&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; routes&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;find&lt;&#x2F;span&gt;&lt;span&gt;((&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; routeMatches&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; route&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;matchedRoute&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; matchedRoute&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;export&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Router&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;handler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above seems pretty reasonable at least at a high level. Probably the most
interesting technique I have used thus far is in the implementation of the
&lt;code&gt;router&lt;&#x2F;code&gt; function. It is simply a builder function that builds the
actual instance of type &lt;code&gt;Router&lt;&#x2F;code&gt; and returns it. It accomplishes this by
returning an anonymous function that matches the &lt;code&gt;Router&lt;&#x2F;code&gt; type signature.&lt;&#x2F;p&gt;
&lt;p&gt;That by itself isn&#x27;t really that interesting. However the fact that the builder
function can take in parameters which are then available to the scope of
actual router implementation (anonymous function) is extremely valuable. It is
what enables us to feed dependencies into a function while having it&#x27;s
signature map to typed signature that knows nothing about those dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;This technique is commonly used in functional programming.&lt;&#x2F;p&gt;
&lt;p&gt;To make sure it supports all the levels of testing I want before adding support
for anything else. I whip up a couple tests.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;routing configuration&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = ...&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; route&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;)(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;route&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toStrictlyEqual&lt;&#x2F;span&gt;&lt;span&gt;({ pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some&#x2F;path&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; somePathHandler&lt;&#x2F;span&gt;&lt;span&gt; });&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;test&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;end-to-end request -&amp;gt; response&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, ()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { path: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some&#x2F;path&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;response&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;status&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above allows us to test the following things.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;end-to-end test with a request&lt;&#x2F;li&gt;
&lt;li&gt;test routing configuration in isolation&lt;&#x2F;li&gt;
&lt;li&gt;test the route handler in isolation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;&#x2F;h2&gt;
&lt;p&gt;To get a better feel for what this framework might actually look like to use
in this state. I have broken down a rough example.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; *&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;.&#x2F;wf&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; barHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 200&lt;&#x2F;span&gt;&lt;span&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; notFoundHandler&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Response&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span&gt; { status:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 404&lt;&#x2F;span&gt;&lt;span&gt; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; routes&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; fooHandler&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    { pattern: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;bar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, handler:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; barHandler&lt;&#x2F;span&gt;&lt;span&gt; }];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;router&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;routes&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; notFoundRoute&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; Normally this request would come in via an HTTP Server and get translated&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; into a wf.Request object and in turn handed to the wf.process() function.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; However, this works as a means of simulating this for the development of&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; the framework without needing to build the HTTP Server portion.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Request&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; { path: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; };&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; response&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; wf&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;process&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;request&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; router&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I threw the above into a single file to facilitate seeing it all at once. In
reality this would obviously be broken up into different files.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;review-next-up&quot;&gt;Review &amp;amp; Next Up&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at what I have thus far I am feeling pretty good about the design. It
feels simple and clean yet still extremely robust and flexible while meeting
all of the outlined constraints.&lt;&#x2F;p&gt;
&lt;p&gt;Next up is going to be interesting as I need to figure out how to ideally
facilitate dependency injection within the framework.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Patch Stack - Add a Patch</title>
        <published>2021-09-23T00:00:00+00:00</published>
        <updated>2021-09-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-patch-stack-add-patch/"/>
        <id>https://drewdeponte.com/blog/git-patch-stack-add-patch/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-patch-stack-add-patch/">&lt;div class=&quot;video-wrapper&quot;&gt;
  &lt;iframe src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;NTh8dr4HaTQ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;Today we are focused on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt;, an open source tool we developed
and use for a patch stack based workflow in &lt;code&gt;git&lt;&#x2F;code&gt;, instead of doing feature
branches.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-git-patch-stack&quot;&gt;What is Git Patch Stack?&lt;&#x2F;h2&gt;
&lt;p&gt;You might still be asking, &quot;Well, what is that?&quot; Basically it&#x27;s a workflow that
we can use to conceptually create logically independent patches, and we have a
stack of them. So think of a stack of plates. Except, you can do things like
reorder them, squash them together, split them apart, etc.&lt;&#x2F;p&gt;
&lt;p&gt;In this workflow you generally work all on the &lt;code&gt;main&lt;&#x2F;code&gt; branch, and it
facilitates you building on top of the changes you have already made. Rather
than you having to worry about creating a branch that is based on top of
another branch and then based on top of another branch and so on and so forth.&lt;&#x2F;p&gt;
&lt;p&gt;It also promotes proper &lt;code&gt;git&lt;&#x2F;code&gt; usage so that you have logical chunks. Enabling
tooling like &lt;code&gt;git bisect&lt;&#x2F;code&gt; to actually work.&lt;&#x2F;p&gt;
&lt;p&gt;To learn more about this workflow checkout my post, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using
Git&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;adding-patches-to-your-stack&quot;&gt;Adding Patches to your Stack&lt;&#x2F;h2&gt;
&lt;p&gt;Today we&#x27;re going to focus on how we create patches on our stack and what is a
stack in terms of &lt;code&gt;git&lt;&#x2F;code&gt;? &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; is really just a layer of
tooling built directly on top of &lt;code&gt;git&lt;&#x2F;code&gt; itself. So if we look at our &lt;code&gt;git&lt;&#x2F;code&gt; tree
here, we have a small project.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-add-patch&#x2F;initial-git-tree-with-skeleton.png&quot; alt=&quot;Initial git tree with skeleton&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It has an initial skeleton of a Rust project. That&#x27;s just a Hello World program
right now, and we can see we have a branch called &lt;code&gt;main&lt;&#x2F;code&gt; that were checked out
on. That&#x27;s why &lt;code&gt;HEAD&lt;&#x2F;code&gt; points to it, and we then have an upstream &lt;code&gt;main&lt;&#x2F;code&gt; with a
remote of &lt;code&gt;origin&lt;&#x2F;code&gt;. That happens to be where &lt;code&gt;main&lt;&#x2F;code&gt; points to on our GitHub
repository for this.&lt;&#x2F;p&gt;
&lt;p&gt;Technically, in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; terms, any branch that has an upstream is
a Patch Stack. So you can have as many of these Patch Stacks as you want, as long
as they are branches that have remote upstreams. To add patches on to a stack,
you first have to be checked out on a branch that has an associated upstream.
In our case, &lt;code&gt;main&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;make-a-change&quot;&gt;Make a change&lt;&#x2F;h3&gt;
&lt;p&gt;Then we just make changes like we normally would in &lt;code&gt;git&lt;&#x2F;code&gt;. We add a commit
and that commit conceptually becomes a patch. So let&#x27;s do that real quick.
Let&#x27;s go look at our source code here. We have a &lt;code&gt;main()&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Hello, world!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Let&#x27;s say that we want to add another function called &lt;code&gt;foo()&lt;&#x2F;code&gt; for some reason,
and we want this function to print &quot;Foo&quot;, nothing too crazy.  So we add a
function.  We&#x27;re not even going to use the function. We&#x27;re just going to add it
to the code base so that we can use it in the future.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Hello, world!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it. Now we just do a &lt;code&gt;git diff&lt;&#x2F;code&gt; to verify our changes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;diff --git a&#x2F;src&#x2F;main.rs b&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt;index e7a11a9..0e47771 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;--- a&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+++ b&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;@@ -1,3 +1,7 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt; fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt;     println!(&amp;quot;Hello, world!&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+fn foo() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+    println!(&amp;quot;Foo&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;blockquote&gt;
&lt;p&gt;I have a git alias of &lt;code&gt;di&lt;&#x2F;code&gt; setup so I can just run &lt;code&gt;git di&lt;&#x2F;code&gt; to get the diff
quicker. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-Basics-Git-Aliases&quot;&gt;Git Aliases&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Once we verify the change is what we want, then we stage that change.
We can stage that change by doing a &lt;code&gt;git add&lt;&#x2F;code&gt; of that file. So far, we&#x27;re just
using all normal &lt;code&gt;git&lt;&#x2F;code&gt; commands, and now it&#x27;s staged. So we can do a &lt;code&gt;git diff --cached&lt;&#x2F;code&gt; and that will show us all the changes that are staged as a diff.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;diff --git a&#x2F;src&#x2F;main.rs b&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt;index e7a11a9..0e47771 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;--- a&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+++ b&#x2F;src&#x2F;main.rs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;@@ -1,3 +1,7 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt; fn main() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt;     println!(&amp;quot;Hello, world!&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+fn foo() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+    println!(&amp;quot;Foo&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;+}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It looks good. Looks like the changes we want.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;I have a git alias of &lt;code&gt;dc&lt;&#x2F;code&gt; setup so I can just run &lt;code&gt;git dc&lt;&#x2F;code&gt; to get the diff
quicker. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-Basics-Git-Aliases&quot;&gt;Git Aliases&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h3 id=&quot;add-patch-to-stack&quot;&gt;Add Patch to Stack&lt;&#x2F;h3&gt;
&lt;p&gt;If we do a &lt;code&gt;git commit&lt;&#x2F;code&gt;, it pops up my editor and I can enter the commit message&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Add foo() function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that in the future we can print the message when necessary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ideally, we provide more context but because this is a contrived example. We
don&#x27;t really have it. Now we have a commit.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-add-patch&#x2F;added-foo-commit.png&quot; alt=&quot;Added foo() commit&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we look at our &lt;code&gt;git&lt;&#x2F;code&gt; tree, you
can see we have a commit here that we&#x27;re pointing to on &lt;code&gt;main&lt;&#x2F;code&gt;, which is the
&quot;Add foo() function&quot; patch. And then underneath that in the tree, we have the
initial skeleton commit we had before.&lt;&#x2F;p&gt;
&lt;p&gt;Now, if we run &lt;code&gt;git ps ls&lt;&#x2F;code&gt;, which is how we list our stack of patches.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-add-patch&#x2F;git-ps-ls-with-added-foo-commit.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can now see that our stack of patches consist of one commit, the commit that
we just added on there, aka a patch.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;add-another-patch&quot;&gt;Add another Patch&lt;&#x2F;h3&gt;
&lt;p&gt;So let&#x27;s add another one real quick just so we can
see what it&#x27;s like to have two. Let&#x27;s just copy this and paste that, and change this
word to bar, change this to bar and then we&#x27;ll add another function.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;rust&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Hello, world!&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Foo&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; bar&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    println!&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Bar&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we just &lt;code&gt;git add&lt;&#x2F;code&gt;, &lt;code&gt;git dc&lt;&#x2F;code&gt; to verify our staged code. All looks good. We
commit it with the message.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Add bar() function&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that we can print the &amp;quot;Bar&amp;quot; message in the future.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Right now we should have two patches in our stack.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-patch-stack-add-patch&#x2F;two-patches-on-stack.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We have patches zero, which is the index of that patch currently. And we have
patch index one.&lt;&#x2F;p&gt;
&lt;p&gt;The short sha of those commits, a.k.a. patches visible to the right of the
shas. We can also see the patch summaries.&lt;&#x2F;p&gt;
&lt;p&gt;As you get into &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; further, you&#x27;ll see indications here that
will indicate things like whether that patch has been requested for review, the
patch has been published, or there&#x27;s been changes since you requested review.
But for now that&#x27;s it.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s how you add a patch to the top of your stack.&lt;&#x2F;p&gt;
&lt;p&gt;Hope you enjoyed.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>SwiftUI: Composable Button Styles</title>
        <published>2021-06-14T00:00:00+00:00</published>
        <updated>2021-06-14T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/swiftui-composable-button-styles/"/>
        <id>https://drewdeponte.com/blog/swiftui-composable-button-styles/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/swiftui-composable-button-styles/">&lt;p&gt;One frustrating&#x2F;annoying things about SwiftUI Buttons for me has been the
mechanism for styling them. In order to get information about the state of the
button (e.g. if it is pressed, not pressed) you have to build a &lt;code&gt;struct&lt;&#x2F;code&gt;
that implements the &lt;code&gt;ButtonStyle&lt;&#x2F;code&gt; protocol. This would generally look something
like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyColoredButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; ButtonStyle&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; pressedBackgroundColor: Color &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; notPressedBackgroundColor: Color &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; makeBody&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;configuration&lt;&#x2F;span&gt;&lt;span&gt;: Configuration)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return&lt;&#x2F;span&gt;&lt;span&gt; configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;background&lt;&#x2F;span&gt;&lt;span&gt;(configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isPressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; pressedBackgroundColor &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span&gt; notPressedBackgroundColor)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then to use it you simply do the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;Button&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;buttonStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;MyColoredButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h2&gt;
&lt;p&gt;This is great and all until you decide that you also want your button to have
an animated scale effect tied to the &lt;code&gt;isPressed&lt;&#x2F;code&gt; state as well. You might think
you could just create a new &lt;code&gt;MyAnimatedScaleButtonStyle&lt;&#x2F;code&gt; struct and tack it on
like so.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;Button&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;buttonStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;MyColoredButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;buttonStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;MyAnimatedScaleButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Sadly SwiftUI only takes the first button style in the chain and applies
it. The rest are ignored. This means you basically have to create a super
unique button style for each particular use case and have all your styling
slammed into it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-solution-a-micro-framework&quot;&gt;A Solution (A Micro Framework)&lt;&#x2F;h2&gt;
&lt;p&gt;Taking from Functional Programming we can effectively use Function Composition
to facilitate making a tiny lightweight framework to facilitate building
composable button styles.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;typealias&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; ButtonStyleClosure&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; (ButtonStyleConfiguration, A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; B&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;precedencegroup&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; ForwardComposition&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	associativity&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;left&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;infix operator&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; &amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt;ForwardComposition&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; &amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; B&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; C&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; f&lt;&#x2F;span&gt;&lt;span&gt;: @&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;escaping&lt;&#x2F;span&gt;&lt;span&gt; ButtonStyleClosure&amp;lt;A, B&amp;gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;    _&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; g&lt;&#x2F;span&gt;&lt;span&gt;: @&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;escaping&lt;&#x2F;span&gt;&lt;span&gt; ButtonStyleClosure&amp;lt;B, C&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; ButtonStyleClosure&amp;lt;A, C&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; { configuration, a &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;        g&lt;&#x2F;span&gt;&lt;span&gt;(configuration, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;f&lt;&#x2F;span&gt;&lt;span&gt;(configuration, a))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; ComposableButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;B&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; ButtonStyle&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; buttonStyleClosure: ButtonStyleClosure&amp;lt;ButtonStyleConfiguration.Label, B&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; buttonStyleClosure&lt;&#x2F;span&gt;&lt;span&gt;: @&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;escaping&lt;&#x2F;span&gt;&lt;span&gt; ButtonStyleClosure&amp;lt;ButtonStyleConfiguration.Label, B&amp;gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;        self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;buttonStyleClosure&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; buttonStyleClosure&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; makeBody&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;configuration&lt;&#x2F;span&gt;&lt;span&gt;: Configuration)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;        return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; buttonStyleClosure&lt;&#x2F;span&gt;&lt;span&gt;(configuration, configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Button&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;    func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; composableStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;B&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; buttonStyleClosure&lt;&#x2F;span&gt;&lt;span&gt;: @&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;escaping&lt;&#x2F;span&gt;&lt;span&gt; ButtonStyleClosure&amp;lt;ButtonStyleConfiguration.Label, B&amp;gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;        return self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;buttonStyle&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;ComposableButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;(buttonStyleClosure))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This allows us to define custom &lt;code&gt;ButtonStyleClosure&lt;&#x2F;code&gt; functions. The follow are
just a few examples. But the idea is that you can create whatever of these
&lt;code&gt;ButtonStyleClosure&lt;&#x2F;code&gt;s you want and then use Function Composition to combine
them.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; ButtonStateColors&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; pressed: Color&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; notPressed: Color&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; scaledButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; configuration&lt;&#x2F;span&gt;&lt;span&gt;: ButtonStyleConfiguration, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; view&lt;&#x2F;span&gt;&lt;span&gt;: A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;scaleEffect&lt;&#x2F;span&gt;&lt;span&gt;(configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isPressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.98&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;animation&lt;&#x2F;span&gt;&lt;span&gt;(.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;spring&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;response&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;dampingFraction&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.5&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;blendDuration&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.5&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; roundedButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; configuration&lt;&#x2F;span&gt;&lt;span&gt;: ButtonStyleConfiguration, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; view&lt;&#x2F;span&gt;&lt;span&gt;: A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; view.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;cornerRadius&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;8&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; defaultPaddingButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; configuration&lt;&#x2F;span&gt;&lt;span&gt;: ButtonStyleConfiguration, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; view&lt;&#x2F;span&gt;&lt;span&gt;: A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; view.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;padding&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; coloredButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; configuration&lt;&#x2F;span&gt;&lt;span&gt;: ButtonStyleConfiguration, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; view&lt;&#x2F;span&gt;&lt;span&gt;: A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; backgroundColors &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; ButtonStateColors&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;        pressed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;cta_button_highlight_color&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;        notPressed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;cta_button_color&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; foregroundColors &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; ButtonStateColors&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;        pressed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;cta_button_text_color&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;        notPressed&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Color&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;cta_button_text_color&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;background&lt;&#x2F;span&gt;&lt;span&gt;(configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isPressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; backgroundColors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; backgroundColors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;notPressed&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;foregroundColor&lt;&#x2F;span&gt;&lt;span&gt;(configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isPressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; foregroundColors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; foregroundColors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;notPressed&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Allowing us to simply use these with our Function Composition operator we
defined in the framework as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;Button&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;composableButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;(defaultPaddingButtonStyle &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; coloredButtonStyle &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; roundedButtonStyle &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; scaledButtonStyle)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;This gives us lots of reuse and facilitates making more generic button styles
while allowing us to use them throughout our app rather than having to make
unique button styles for each case.&lt;&#x2F;p&gt;
&lt;p&gt;It does have a limitation though. It would be ideal if we could create
higher level functions by nesting closures. Which would give us even more
power. For example we could create a more general
&lt;code&gt;foregroundColorButtonStyle(colors:)&lt;&#x2F;code&gt; function like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foregroundColorButtonStyle&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;A&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; View&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; colors&lt;&#x2F;span&gt;&lt;span&gt;: ButtonStateColors)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; (ButtonStyleConfiguration, A)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt; some&lt;&#x2F;span&gt;&lt;span&gt; View {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span&gt; { configuration, view &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		view.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;foregroundColor&lt;&#x2F;span&gt;&lt;span&gt;(configuration.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isPressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; ?&lt;&#x2F;span&gt;&lt;span&gt; colors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pressed&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; :&lt;&#x2F;span&gt;&lt;span&gt; colors.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;notPressed&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In theory this would enable us to be able to be even more composible. However,
it turns out Swift 5.4.1 doesn&#x27;t support &lt;code&gt;some View&lt;&#x2F;code&gt; in closures. So the above
sadly won&#x27;t work. I briefly tried to come up with a nice workaround but wasn&#x27;t
able to get anything nice to work.&lt;&#x2F;p&gt;
&lt;p&gt;Despite this one limitation it is still far superior in my mind compared to
what SwiftUI provides out of the box.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Changelog Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/changelog-standards/"/>
        <id>https://drewdeponte.com/blog/changelog-standards/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/changelog-standards/">&lt;p&gt;At &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; we keep a &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; following the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;keepachangelog.com&quot;&gt;keepachangelog.com&lt;&#x2F;a&gt; standard with all libraries and applications we create.&lt;&#x2F;p&gt;
&lt;p&gt;We do this by using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;git-cl&quot;&gt;git-cl&lt;&#x2F;a&gt; tool that we built. It enables us to get all
the values of keeping a &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; while not having to deal with the
workflow impedances.&lt;&#x2F;p&gt;
&lt;p&gt;To understand more about &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;git-cl&quot;&gt;git-cl&lt;&#x2F;a&gt; you can checkout our &lt;a href=&quot;&#x2F;blog&#x2F;keep-a-changelog-without-conflicts&#x2F;&quot;&gt;Keep a Changelog
without Conflicts&lt;&#x2F;a&gt; blog post which also includes a video introducing the
tool.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Codebase Organization</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/codebase-organization/"/>
        <id>https://drewdeponte.com/blog/codebase-organization/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/codebase-organization/">&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;&#x2F;h2&gt;
&lt;p&gt;The following is the TLDR of how I believe you should organize your code base.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;organize code according to architecture &lt;strong&gt;not&lt;&#x2F;strong&gt; types of architecture element types&lt;&#x2F;li&gt;
&lt;li&gt;if in framework that does organize by architecture elment types
&lt;ul&gt;
&lt;li&gt;see if you can organize by architecture and then move the organization by element types into the folders representing the architectural components.&lt;&#x2F;li&gt;
&lt;li&gt;if you can&#x27;t, follow the framework convention up until you reach natural boundary (e.g. &lt;code&gt;lib&lt;&#x2F;code&gt; folder), then switch to organizing by architecture&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;major-strategies&quot;&gt;Major Strategies&lt;&#x2F;h2&gt;
&lt;p&gt;There are basically two major strategies people use to organize their codebases.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;around types of architecture components (e.g. &lt;code&gt;models&lt;&#x2F;code&gt;, &lt;code&gt;views&lt;&#x2F;code&gt;, &lt;code&gt;controllers&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;around actual application architecture&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;around-types-of-architecture-components&quot;&gt;Around Types of Architecture Components&lt;&#x2F;h3&gt;
&lt;p&gt;Frameworks like Rails and NestJS are examples that follow this strategy where
they have a folder for &lt;code&gt;models&lt;&#x2F;code&gt;, &lt;code&gt;controllers&lt;&#x2F;code&gt;, etc.&lt;&#x2F;p&gt;
&lt;p&gt;Organizing your codebase around these types of architecture components has the
following advantages.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;you don&#x27;t have to think very hard when you are trying to figure out where to
put something. Controllers go in the &lt;code&gt;controllers&lt;&#x2F;code&gt; folder, &lt;code&gt;models&lt;&#x2F;code&gt; in the
models folder, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This benefit however is not always true because there is generally a boundary
where this falls apart as the framework doesn&#x27;t provide direction. The &lt;code&gt;lib&lt;&#x2F;code&gt;
folder is often one of these boundaries. The framework provides guidence in
terms of organization right up until that point and then all of the sudden
&lt;code&gt;lib&lt;&#x2F;code&gt; is just a dumpster full of stuff.&lt;&#x2F;p&gt;
&lt;p&gt;Organizing your codebase around these types of architecture components also
doesn&#x27;t help people understand anything from the codebase other than that there
are things called &lt;code&gt;controllers&lt;&#x2F;code&gt;, &lt;code&gt;models&lt;&#x2F;code&gt;, and &lt;code&gt;views&lt;&#x2F;code&gt;. But it doesn&#x27;t give you
any knowledge in terms of how certain controllers, models, or views relate to
one another. You have no idea from the organization of the codebase how to find
a particular part of the application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;around-application-architecture&quot;&gt;Around Application Architecture&lt;&#x2F;h3&gt;
&lt;p&gt;An alternative approach that people take is to instead organize their codebase
around the actual application architecture.&lt;&#x2F;p&gt;
&lt;p&gt;When you have put that thought in, people coming into the code base can
&lt;strong&gt;quickly and easily understand the application architecture&lt;&#x2F;strong&gt;. They can also
&lt;strong&gt;quickly navigate&lt;&#x2F;strong&gt; to appropriate areas of the code they want to focus on.&lt;&#x2F;p&gt;
&lt;p&gt;This strategy also helps with creating &lt;strong&gt;logical commits&lt;&#x2F;strong&gt;, which I am a big
fan of, and &lt;strong&gt;reducing conflicts&lt;&#x2F;strong&gt; in source control systems.&lt;&#x2F;p&gt;
&lt;p&gt;People often perceive the fact that you have to think about where to put
folders and files in your codebase as a negative thing.&lt;&#x2F;p&gt;
&lt;p&gt;I believe this effort is one of the more valuable activities actually. It is
effectively a forcing function driving you to make sure you have a sound
application architecture and understand where the piece you are working on
should fit within it.&lt;&#x2F;p&gt;
&lt;p&gt;Using techniques like modularization and concepts like the The Onion
architecture can help you figure out and evolve your application archicture and
your codebase organization.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but-with-frameworks&quot;&gt;But with Frameworks&lt;&#x2F;h2&gt;
&lt;p&gt;I know from experience fighting against a frameworks inherent design is
generally not a great strategy. So how do we organize our codebase around the
Application Architecture when we working with a framework like Rails or NestJS?&lt;&#x2F;p&gt;
&lt;p&gt;Simple, we follow the convention of the framework up until we reach that
natural boundary where it stops providing direction, e.g. the &lt;code&gt;lib&lt;&#x2F;code&gt; folder.
Everything inside that &lt;code&gt;lib&lt;&#x2F;code&gt; folder we would organize around application
architecture and &lt;strong&gt;not&lt;&#x2F;strong&gt; by category of architecture component.&lt;&#x2F;p&gt;
&lt;p&gt;This at least gives developers the knowledge around that area of the code.
Ideally it would be great if we could get those benefits at the framework level
of things as well. However, it just isn&#x27;t worth fighting against the framework
to make it happen.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Squads &amp; Guilds</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/squads-and-guilds/"/>
        <id>https://drewdeponte.com/blog/squads-and-guilds/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/squads-and-guilds/">&lt;p&gt;At Uptech Studio we organize ourselves in a similar fashion to Spotify with Squads &amp;amp; Guilds. However, how we define Squads &amp;amp; Guilds is a bit different.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;&#x2F;h2&gt;
&lt;p&gt;Below is an explainer describing what Squads &amp;amp; Guilds are to us and some examples of how people fit into them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;squads-and-guilds&#x2F;uptech-squads-explainer.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;squads-and-guilds&#x2F;uptech-squads-explainer.png&quot; alt=&quot;Visual explaining what Squads &amp;amp; Guilds&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;squads&quot;&gt;Squads&lt;&#x2F;h2&gt;
&lt;p&gt;A &lt;strong&gt;squad&lt;&#x2F;strong&gt; is simply a group of people organized around delivering a particular project&#x2F;product. They are &lt;strong&gt;on the hook&lt;&#x2F;strong&gt; as they are responsible for delivering the project&#x2F;product to the client. Squads are formed and disbanded as needed around the various projects&#x2F;products.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;squad-representatives&quot;&gt;Squad Representatives&lt;&#x2F;h3&gt;
&lt;p&gt;Squad &lt;strong&gt;representatives&lt;&#x2F;strong&gt; are a subset of the Squad that is responsible for representing the various competencies to the client. Generally there is one person from each of the necessary competencies, e.g. Design, Engineering, Product. Squad Representatives are generally comitted for the lifetime of the project as they are the face of the squad to the client. If projects are long term we may shift representives around but generally try to minimize that.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;guilds&quot;&gt;Guilds&lt;&#x2F;h2&gt;
&lt;p&gt;A &lt;strong&gt;guild&lt;&#x2F;strong&gt; is a group of people focused on a particular competency, e.g. Dev-Ops, Mobile, Web, Backend, Product, Desktop, Data Engineering, Design. The following are things that guild members often help with.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;helping&lt;&#x2F;strong&gt; people do a certain task to hit deadlines. The assisting guild member bills their time against the project though.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;pairing&lt;&#x2F;strong&gt; with you if you are stuck, or need to be leveled up on a tool&#x2F;concept. The helping guild member &lt;strong&gt;should NOT&lt;&#x2F;strong&gt; bill their time to the project.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;peer review&lt;&#x2F;strong&gt; the guild is responsible for helping you when you need a peer review and you don&#x27;t have anyone with necessary competency in your Squad to do it. If you are doing the peer review, &lt;strong&gt;bill your time&lt;&#x2F;strong&gt; against the project.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;manage time&lt;&#x2F;strong&gt; being a Guild member you have obligations to get your own work done. You shouldn&#x27;t be doing peer reviews &amp;amp; pairing for other projects non-stop. So manage your time and make sure you can meet your obligations.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;sharing&lt;&#x2F;strong&gt; you share your knowledge, tools, reusable code, best practices, etc. within the guild.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;standards&lt;&#x2F;strong&gt; you collaborate within the guild to define standards &amp;amp; best practices.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;multiple guilds&lt;&#x2F;strong&gt; you can be a member of more than one guild as you may have more than one competency.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Our primary communication mechanism for Guilds is &lt;strong&gt;Slack Channels&lt;&#x2F;strong&gt;, e.g. &lt;strong&gt;#mobile-guild&lt;&#x2F;strong&gt;, &lt;strong&gt;#backend-guild&lt;&#x2F;strong&gt;, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-squads-guilds&quot;&gt;Why Squads &amp;amp; Guilds?&lt;&#x2F;h2&gt;
&lt;p&gt;Basically we needed a way to facilitate making sure we were focusing and delivering for our clients (the focus of the Squad) while also facilitating cross-pollination and elimination of siloing across the organization (the focus of the Guild). We have found this structure and the intention behind it to be extremely effective on both these fronts.&lt;&#x2F;p&gt;
&lt;p&gt;Below you can see a visualization of what Squad might look like in relation to Guilds.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;squads-and-guilds&#x2F;uptech-squads-example.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;squads-and-guilds&#x2F;uptech-squads-example.png&quot; alt=&quot;Visual example of Squads &amp;amp; Guilds&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Agile Development</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-agile-development/"/>
        <id>https://drewdeponte.com/blog/uptech-agile-development/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-agile-development/">&lt;h1 id=&quot;kanban&quot;&gt;Kanban&lt;&#x2F;h1&gt;
&lt;p&gt;We are big believers in Agile methodologies. However, we don&#x27;t prescribe to strict Scrum. Instead we use Kanban as we feel it better aligns with the fluidity and agileness necessary with the earlier stage companies we work with.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-agile-development&#x2F;example-kanban-board.png&quot; alt=&quot;Example Kanban Board&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In Kanban the columns on the board represent the prioritized queue of items that need to be done by each role in the software development process. Items move across the board until complete.&lt;&#x2F;p&gt;
&lt;p&gt;We often use work in progress limits for each column to guide us around capacity issues and enforce prioritization.&lt;&#x2F;p&gt;
&lt;p&gt;The Kanban boards provide all stakeholders with a clear view into the development pipeline. Boards can be customized via grouping and filtering.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;columns&quot;&gt;Columns&lt;&#x2F;h2&gt;
&lt;p&gt;Columns in Kanban are intended to be customized to the process at hand. By default most Kanban tools provide the following columns at a minimum.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TODO&lt;&#x2F;strong&gt; - all things that the team can work on. By default, this list will continue to grow each week.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;In Progress&lt;&#x2F;strong&gt; - all the things the team is working on&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Done&lt;&#x2F;strong&gt; - the things the team has completed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We generally evolve these on our projects to some combination of the following colmuns.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Selected for Dev&lt;&#x2F;strong&gt; - Every new issue starts in Needs Review. Each week, we review this list and move issues to keep it empty.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Specs Needed&lt;&#x2F;strong&gt; - Stories that need further specification, UX, and&#x2F;or UI assets.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ready for Dev&lt;&#x2F;strong&gt; - Issues that are ready for the developers.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;In Progress&lt;&#x2F;strong&gt; - Issues being worked on by a developer.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;QA&#x2F;Acceptance&lt;&#x2F;strong&gt; - Issues delivered by development and is now with QA and&#x2F;or Product for testing.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Accepted&lt;&#x2F;strong&gt; - Issues that are accepted and ready for release.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Released&lt;&#x2F;strong&gt; - Issues that have been deployed to users.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; The above columns are guidelines we use to stay in alignment with each other. But if we are on a project where we feel like a couple of these columns aren&#x27;t need and are just ritual we will get rid of those columns.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;standups&quot;&gt;Standups&lt;&#x2F;h1&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; has remote employees all over the US. Therefore our team is often pretty fragmented in terms of physical location. For example, I might be on-site at a client&#x27;s office while another member is at a different client&#x27;s office, and yet other members are at our office. This physical fragmentation makes it difficult to stay on top of what is going on across the organization on a day-to-day basis.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;normal-solution&quot;&gt;Normal Solution&lt;&#x2F;h3&gt;
&lt;p&gt;Normally, in a startup we would have a standup every morning to kick-off the day. If you aren&#x27;t familiar, a standup is a time-boxed meeting that is used in many agile methodologies to facilitate communication around individuals&#x27; daily commitments, as well as raise awareness of any challenges (a.k.a.  blockers). The reason it is called a standup is because the thinking is that if everyone has to stand during the meeting it would help keep the meeting short. For further details on standups and their intent check out the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;Stand-up_meeting&quot;&gt;Wikipedia page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;our-solution&quot;&gt;Our Solution&lt;&#x2F;h3&gt;
&lt;p&gt;Given that our team is rarely in the same physical location at the same time, we have taken the principles and intent from the standup and adapted it to our situation by using a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;slack.com&quot;&gt;Slack&lt;&#x2F;a&gt; &lt;code&gt;#standups&lt;&#x2F;code&gt; channel to share our commitments and blockers every morning at 10 am. To aid with making sure we have the standup right at 10am everyday, we set up a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;208423427-Set-a-reminder&quot;&gt;Slack reminder&lt;&#x2F;a&gt; in the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel.&lt;&#x2F;p&gt;
&lt;p&gt;Then in the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel we communicate the classic standup information: What did I do yesterday?, What am I doing today?, Do I have any blockers? Specifically, we use the following template and generally prepare the mornings standup in a text buffer before pasting it into the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel. The template&#x2F;example below is based on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;202288908-Format-your-messages&quot;&gt;Slack message format&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_Tue July 11, 2017 - Standup_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Yesterday*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_1_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• One thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_2_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Yet another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Today*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_1_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Something else I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_2_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Blockers*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A blocker that is currently preventing me from accomplishing something or will in the near future&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the above is pasted into &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;slack.com&quot;&gt;Slack&lt;&#x2F;a&gt; it looks as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-agile-development&#x2F;slack-screenshot.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Without this virtual standup every morning we wouldn&#x27;t be able to successfully run our business. It constantly triggers discussions, questions, suggestions, etc. that help keep the business on track and moving in the right directions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;client-standups&quot;&gt;Client Standups&lt;&#x2F;h2&gt;
&lt;p&gt;Not only do we post our complete standup in the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel to share with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;. We also post client scoped versions of our standups in shared channels between &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; and the respective client, .e.g. &lt;code&gt;#client1-uptech&lt;&#x2F;code&gt;. This helps in a number of ways.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;it helps keeps the client updated and clued into what things are progressing&lt;&#x2F;li&gt;
&lt;li&gt;it gives an opportunity to highlight and remind the client about blockers that they might be able to facilitate&lt;&#x2F;li&gt;
&lt;li&gt;it helps stay in alignment with client team and any coordination efforts between &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; and them&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The following is what the above &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;UpTech Studio&lt;&#x2F;a&gt; standup would look like scoped down to &lt;code&gt;client1&lt;&#x2F;code&gt; and would be what we would shared in the &lt;code&gt;#client1-uptech&lt;&#x2F;code&gt; channel.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_Tue July 11, 2017 - Standup_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Yesterday*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• One thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Today*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Something else I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Blockers*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;tools&quot;&gt;Tools&lt;&#x2F;h2&gt;
&lt;p&gt;The following are a few tools we have created&#x2F;found that help with this process. Though at the end of the day, like any tool&#x2F;process it comes down to having an open minded collaborative team that understands the importance of process and communication to really get the value out of a practice like this. Tools are never a solution for culture but they can reduce friction.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gumleaf&quot;&gt;Gumleaf&lt;&#x2F;h3&gt;
&lt;p&gt;Gumleaf is a side project of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&quot;&gt;Drew De Ponte&lt;&#x2F;a&gt; &amp;amp; &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;anthonycastelli.me&quot;&gt;Anthony Castelli&lt;&#x2F;a&gt; where the beta release is being shared with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; to get feedback. It is a personal task management solution built around the concept of daily standups and also provides features to trivially scope standups down to specific clients as well as export standups in the Slack format.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-agile-development&#x2F;gumleaf-screenshot.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This has become a daily driver for most of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;vim-neovim&quot;&gt;Vim&#x2F;Neovim&lt;&#x2F;h3&gt;
&lt;p&gt;Given that this is such a core part of our process we created the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;vim-slack-format&quot;&gt;Vim Slack Format&lt;&#x2F;a&gt; plugin to provide syntax highlighting in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vim.org&quot;&gt;Vim&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;neovim.io&quot;&gt;Neovim&lt;&#x2F;a&gt; for the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;202288908-Format-your-messages&quot;&gt;Slack message format&lt;&#x2F;a&gt;. When using this plugin it looks as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-agile-development&#x2F;vim-slack-format-screenshot.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This allows you to have a &lt;code&gt;standups.slack&lt;&#x2F;code&gt; file to facilitate keeping historical track of your standups in an easily searchable format where you keep the most recent standup at the top of the file. Some people even like to keep this in a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; repository so that their history is pushed up to a remote on a regular basis.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;planning-prioritization&quot;&gt;Planning &amp;amp; Prioritization&lt;&#x2F;h1&gt;
&lt;p&gt;Given that we don&#x27;t do Scrum. We don&#x27;t really do formal &quot;sprint planning&quot;. In fact we don&#x27;t actually believe in the constraint of a &quot;sprint&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Instead we focus on &quot;roadmap planning&quot; and &quot;iteration planning&quot;. The destinction is that we do plan for an iteration (roughly a week or two out). However, that planning simply funnels into the Kanban board as to what we are targeting working on. If that changes as more information comes in it isn&#x27;t a problem as we are just working down through the prioritized columns. This differs from the concept of formal sprints where a sprint&#x27;s tickets are usually locked in until the following sprint.&lt;&#x2F;p&gt;
&lt;p&gt;We have a &lt;strong&gt;weekly&lt;&#x2F;strong&gt; Planning &amp;amp; Prioritization meetings.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;planning&quot;&gt;Planning&lt;&#x2F;h3&gt;
&lt;p&gt;During the &lt;strong&gt;Planning&lt;&#x2F;strong&gt; portion of the meeting we do the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;quickly review the roadmap against all new information and make sure it still holds, adjusting as needed&lt;&#x2F;li&gt;
&lt;li&gt;review all the items in &lt;strong&gt;Selected for Dev&lt;&#x2F;strong&gt; column and determine where on the board the tickets should go. The &lt;strong&gt;Selected for Dev&lt;&#x2F;strong&gt; column needs to be empty at the end of the meeting. Items can go back to the backlog if needed.&lt;&#x2F;li&gt;
&lt;li&gt;make sure WIP limits are adhered to and we remove items from a column to make room for other higher priority tickets when the limit has been reached.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;prioritization&quot;&gt;Prioritization&lt;&#x2F;h2&gt;
&lt;p&gt;During the &lt;strong&gt;Prioritization&lt;&#x2F;strong&gt; portion of the meeting we do the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;review the priority of the epics making sure they still hold, adjusting as needed&lt;&#x2F;li&gt;
&lt;li&gt;prioritize the tickets within each of the epics covering at least a few iterations worth of work out (making sure we prioritized work in the backlog if we complete all the work planned for this iteration).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;attendees&quot;&gt;Attendees&lt;&#x2F;h2&gt;
&lt;p&gt;This meaning is owned &amp;amp; lead by Product but Engineers, QA, Design, etc. generally attend.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;demos&quot;&gt;Demos&lt;&#x2F;h1&gt;
&lt;p&gt;We generally do &lt;strong&gt;weekly&lt;&#x2F;strong&gt; or &lt;strong&gt;bi-weekly&lt;&#x2F;strong&gt; demos with the client.&lt;&#x2F;p&gt;
&lt;p&gt;We use these as clear opportunities to &lt;strong&gt;show progress&lt;&#x2F;strong&gt; and &lt;strong&gt;get feedback&lt;&#x2F;strong&gt; on the work we have done for the client. Some clients like to be in the nitty gritty and get regular builds of the apps and provide feedback along the way. Others even when we provided regular builds won&#x27;t really look at them until we have a &lt;strong&gt;demo&lt;&#x2F;strong&gt;. We do demos irrespective of the clients behavior as it is good practice to take a step back and look at the work that has been done and how it relates to the higher level product goals.&lt;&#x2F;p&gt;
&lt;p&gt;When we do our &lt;strong&gt;Planning &amp;amp; Prioritization&lt;&#x2F;strong&gt; meeting each week we discuss our plans for what we are going to demo the next week. We are extremely careful not to let things be driven completely by the demo and become DDD (Demo Driven Development). But it is an important attribute to take into consider while planning and prioritizing work.&lt;&#x2F;p&gt;
&lt;p&gt;We generally try and avoid demos of APIs and network requests as much as possible and focus on demos of application UI as much as possible. There are of course exceptions to this. For example if the project was to build a public facing API for a service. Then it would make sense for the demo to be Paw&#x2F;Postman interacting with the public API.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;retrospective&quot;&gt;Retrospective&lt;&#x2F;h1&gt;
&lt;p&gt;We do hold Retrospective meetings &lt;strong&gt;bi-weekly&lt;&#x2F;strong&gt; for the squad to review how things are going. We also collect the following information from the team.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;what went well?&lt;&#x2F;li&gt;
&lt;li&gt;what didn&#x27;t go well?&lt;&#x2F;li&gt;
&lt;li&gt;define action items with owners as a team to improve the process&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We also review cycle time and throughput trends to make sure there are no underlying issues that need to be addressed.&lt;&#x2F;p&gt;
&lt;p&gt;This meeting is owned and lead by Product.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;feedback-loop&quot;&gt;Feedback Loop&lt;&#x2F;h1&gt;
&lt;p&gt;In our minds &lt;strong&gt;Agile Development&lt;&#x2F;strong&gt; is really all about feedback loops. It is about listening, being aware, and gather feedback continuously throughout the process so that we adjust according to that feedback as we progress along.&lt;&#x2F;p&gt;
&lt;p&gt;Once we start the &lt;strong&gt;Agile Development&lt;&#x2F;strong&gt; process doesn&#x27;t mean we forgo all of the other processes we did initially (e.g. Discovery &amp;amp; Definition, Project Planning, Design Review, Roadmaping, Milestone Planning). In fact we continue to do them iteratively. Basically maintaining the goals of them along the way as we learn things through the &lt;strong&gt;Agile Development&lt;&#x2F;strong&gt; process.&lt;&#x2F;p&gt;
&lt;p&gt;The way we think about it is really that we are maintaining and evolving the artifacts that came out of the initially upfront engineering process while we iterate through the &lt;strong&gt;Agile Development&lt;&#x2F;strong&gt; process.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Branching Strategies</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-branching-strategies/"/>
        <id>https://drewdeponte.com/blog/uptech-branching-strategies/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-branching-strategies/">&lt;p&gt;Branching strategies are generally applicable in two contexts.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;strategies used for development&lt;&#x2F;li&gt;
&lt;li&gt;strategies used for releases&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;strategies-for-development&quot;&gt;Strategies for Development&lt;&#x2F;h2&gt;
&lt;p&gt;Our preferred branching strategy is a style of &lt;strong&gt;trunk-based development&lt;&#x2F;strong&gt;. This means that in terms of collaboration we have that happen over the mainline branch (a.k.a. trunk) by following a workflow we developed to facilitate the creation of &lt;strong&gt;small pull requests&lt;&#x2F;strong&gt; and the highest quality peer reviews. You can read more about this in our post, &lt;a href=&quot;&#x2F;blog&#x2F;journey-to-small-pull-requests&quot;&gt;Journey to Small Pull Requests&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Behind the scenes our workflow does use branches (&lt;strong&gt;not&lt;&#x2F;strong&gt; feature branches) when requesting review of patches. In turn enabling the peer reviewer to review in a manner that they would be used to. This also enables us to work with teams that don&#x27;t follow our workflow and allows us to still use our workflow and get the values and benefits while still playing nicely with a team that is doing feature branches.&lt;&#x2F;p&gt;
&lt;p&gt;We don&#x27;t believe in Feature Branches as outlined in &lt;a href=&quot;&#x2F;blog&#x2F;journey-to-small-pull-requests&quot;&gt;Journey to Small Pull Requests&lt;&#x2F;a&gt; as they introduce a number of difficult problems in relation to writing quality code.&lt;&#x2F;p&gt;
&lt;p&gt;We also keep a linear &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; history through our workflow so that it is easy to go back and revert commits, etc. if necessary.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;strategies-for-release&quot;&gt;Strategies for Release&lt;&#x2F;h2&gt;
&lt;p&gt;Many people use a branching strategy for releases. For example they might have a &lt;strong&gt;production&lt;&#x2F;strong&gt;, &lt;strong&gt;qa&lt;&#x2F;strong&gt;, and &lt;strong&gt;dev&lt;&#x2F;strong&gt; branch mapping to respective environments. We do &lt;strong&gt;NOT&lt;&#x2F;strong&gt; use environment based branching or any other branching strategy for releases generally. We instead use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; tags to manage releases.&lt;&#x2F;p&gt;
&lt;p&gt;This enables us to have and maintain our linear history while actually using immutable tags to represent releases and in turn trigger automated builds and deployments. In some cases we might also choose to do manually triggered releases.&lt;&#x2F;p&gt;
&lt;p&gt;Sometimes we are stuck in a client&#x27;s environment in which they have built up a bunch of automation around environment based branching. In those case we generally recommend that client make their automation work in such a way that they don&#x27;t have to merge branches back and forth and instead the branches can be force pushed to, triggering automation and deploys. This helps mitigate a bunch of confusion within the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; history.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Error Handling</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-error-handling/"/>
        <id>https://drewdeponte.com/blog/uptech-error-handling/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-error-handling/">&lt;p&gt;Our general position on error handling is that we should be using &lt;code&gt;Result&lt;&#x2F;code&gt; types with base exception classes so that we can easily transition between the &lt;code&gt;Result&lt;&#x2F;code&gt; type world and the &lt;code&gt;Exception&lt;&#x2F;code&gt; worlds.&lt;&#x2F;p&gt;
&lt;p&gt;The following is a presentation &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&quot;&gt;Drew De Ponte&lt;&#x2F;a&gt; gave that covers this topic and how we should be thinking about error handling.&lt;&#x2F;p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;--t3vn-dE8Y&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-error-handling&#x2F;abstractions-and-errors-export.pdf&quot;&gt;Abstractions &amp;amp; Errors - Slides&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;typescript-example&quot;&gt;TypeScript Example&lt;&#x2F;h2&gt;
&lt;p&gt;The following is an example of how we can create a Base exception in TypeScript and how we can create Custom exception types and use them with &lt;code&gt;Result&lt;&#x2F;code&gt; types and how we can programmatically handle the cases.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;typescript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; Ok&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;ts-results&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; Here we define a CustomError that all custom errors should extend from so&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; that the custom errors don&amp;#39;t have to worry about setting their name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; appropriately.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; CustomError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;constructor&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; This is something that we have seen on the web for issues where Babel won&amp;#39;t&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; set the stack trace properly when the class doesn&amp;#39;t extend properly. But&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; from our testing this hasn&amp;#39;t seemed to be needed and it is also our&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; understanding that super() now does this.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;         if (typeof Error.captureStackTrace === &amp;#39;function&amp;#39;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;             Error.captureStackTrace(this, this.constructor);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;         } else {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;             this.stack = (new Error(message)).stack;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;         }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; This is an error type that is useful to have around because if you have a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; function that returns Result&amp;lt;someType, yourErrorType&amp;gt; you don&amp;#39;t want that&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; function to throw an exception because you are using Result. So inside&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; the function you would do something like the following:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; try {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; 		...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; } catch (e: any) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; 		return new Err(new UnhandledError(&amp;#39;some message&amp;#39;, e))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; This allows you to identify it is an unhandled error but still get to the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; internal error object if needed later on.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UnhandledError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; CustomError&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	origError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Error&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	constructor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; string&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; origError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		this&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;origError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; origError&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; The following are examples of defined custom error types as a hierarchy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; for categorization. In this example we have a DashboardEventsError as a&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; base category for the errors and then we have MyErrorClassA and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; MyErrorClassB as specific errors within that category.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DashboardEventsError&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; CustomError&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; DashboardEventsError&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; extends&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; DashboardEventsError&lt;&#x2F;span&gt;&lt;span&gt; {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; The following is code I used to vet the functionality of the custom errors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; and make sure that they meet all the expectations of the interface for the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; Error type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;some message&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can we get the name and is it the correct custom name&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;name: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;name&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can we get the message&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;message: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can get stack trace&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;message: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;stack&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can we conditionally check the custom type to programmatically handle specific errors&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an instance of MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an instance of MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an instance of MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an instance of MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can conditionally check if it is an instance of custom base class type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; DashboardEventsError&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an DashboardEventsError&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an DashboardEventsError&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - can conditionally check if it is an instance of Error type&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Error&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an Error&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an Error&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - do we get the custom type name and stack trace when it is thrown&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;throw&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; Sadly because of limitations of TypeScript I haven&amp;#39;t found a good way yet&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; to meet the following criteria. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - communicating to the user via the type system what the possible error types are&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - requiring handling of all possible returned errors or explicitly declare not handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; The following are just explorations I started but didn&amp;#39;t really go anywhere to meet those requirements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - communicating to the user via the type system what the possible error types are&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; typescript doesn&amp;#39;t seem to complain even through I declared the possible&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; return types that I am returning a different error type. So not really&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; useful as a tool for the author of the function. Maybe it could be seen as&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; documentation for the consumer&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;any&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; |&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UnhandledError&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	try&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;in try&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;error a&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; catch&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; any&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;in the catch&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Err&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;new&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UnhandledError&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;message&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; e&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; - requiring handling of all possible returned errors or explicitly declare not handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; I don&amp;#39;t believe there is anything in TypeScript to support exhaustive&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; handling of error types. I have contemplated having a pairing function with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; each function that enforces this. However, there is nothing to help the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; author of that function make sure they aren&amp;#39;t forgetting any error types.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; Also it doesn&amp;#39;t help the use case when you are mapping errors in the middle&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; of a chain.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; So I think for the time being unless we were to look into a TypeScript&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F; compiler extension we are stuck in this less than ideal world.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; result&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;result&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;ok&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;result ok&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;result err&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an instance of MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an instance of MyErrorClassA&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; instanceof&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is an instance of MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;it is NOT an instance of MyErrorClassB&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;envolving-classified-error-classes&quot;&gt;Envolving Classified Error Classes&lt;&#x2F;h2&gt;
&lt;p&gt;Creating unique error classes for each specific function will result in a lot of different error classes. However, we need to make sure that we formalize explicitly all the possible errors that can result from a function. One obvious way to collapse the number of errors is to make Errors more generic. For example you could have a &lt;code&gt;FileNotFound&lt;&#x2F;code&gt; error for one function and you can also have another function use the same &lt;code&gt;FileNotFound&lt;&#x2F;code&gt; error. How do you know how to make an error generic or not or if you make it too generic.&lt;&#x2F;p&gt;
&lt;p&gt;I have found that defining the error classes with their associated data helps a lot. It gives you a guide to understand if the associated data makes sense in the other generic cases as well. So the recommendation is to start wtih a specific error definition with associated data and then extrapolate from there into a generic type that can be reused.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;faqs&quot;&gt;FAQs&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Is it common for nearly every function in an application to return a Result to handle potential errors? At which point, if any, would that become unnecessary? It seems like this has become the ideal solution for dealing with breaking errors in the Trans-Serv, but I don’t want to find myself in a position of over-using or defaulting to Results if that is not generally the ideal way to design&#x2F;build applications.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In reference to, &quot;Is it common for nearly every function in an application to return a Result to handle potential error?&quot; The answer is generally yes it is common to use it everywhere and you generally should. The point at which it becomes un-necessary is the point at which an error is handled programmatically. Usually this is at the bounds of the application (e.g. user interface where error is presented to the user, or where an error is internally programmatically handled). You should be using Result whenever it is possible for the operation you are performing to fail. The only caveat to this is if you are in an async chain (aka a promise chain) and you want a function to throw an exception explicitly for being used in that context of an async chain. However, generally in these cases the async chain is basically mapped back to a result at the end anyways.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;At what point does piping, mapping, or promise chaining become “too large”? Is the limit determined on the amount of the logic inside each consecutive call? For example, would it be easier to follow a larger number of chains if it’s purely passing in the next function, as opposed to having chains where logic must be implemented beyond calling a single function (even if it is only a few lines)? Is the latter case a “smell” that the logic should be extracted into a new function to cater to the former?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In reference to &quot;At what point does piping, mapping, or promise chaining become “too large”?&quot; This is a subjective thing and hard to get away from it being subjective because the driver of it is readability and being able to easily understand what is going on in the chain. If I have to read through a chain of 20 different steps to understand what the entire chain is trying to accomplish it is too large. I should be able to quickly look at it and understand and somewhere around up to 5 steps or so is a good rule of thumb. It is worth noting though that if you have a really large chain, you should be collapsing multiple steps into a single step with a name that has meaning using pipe(). Having chains where you hand it a lambda is a smell. The ideal is to be in a situation where your chain is completely composed of named functions. This drastically aids with the understanding of the chain and its intent without having to worry about the details of understanding the implementations of those lambdas. If you feel like you have to do logic beyond a single function it is a &quot;smell&quot; that, that logic should be extracted out into a new function.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Ok so new question relating to error handling.  For the stream creation helper function, Jon suggested that we return a FileNotFound error to be specific if a file is not found.  The way our Error handling works currently, everything bubbles up to the TransactionServiceError class which then emits the error with an http error code - if I understand correctly.  If an internal function is using the helper function to transform a file path into a stream, we would want to throw a FileNotFound error - but it would not be an http error of 404, it would be an internal error.  When handled by the calling function it might be transformed into a 404, depending on the context (e.g. if it is interacting with the outside and needs to communicate that the file path is missing), or it might remain an internal matter to be passed along as a generic 500 error for the greater service.   So how do we handle this sort of instance?  I created a FileNotFound error so it would contain the message to be handled internally, and it could theoretically be caught and transformed into a TransactionServiceError code 404 by something that handles it...  but I am not sure if that is how we want to manage this?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Im not certain we want everything to be a TransactionServiceError right, since not everything has an http code. Functions can and should have their own errors to inform the caller of the status via Result. TransactionServiceError was designed in relation to Faktory Jobs consuming failures when calling routes, which is separate from this. The potential transformation is outside the scope of this context. This &lt;code&gt;FileNotFoundError&lt;&#x2F;code&gt; could be transformed by the caller (if needed).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;I would ideally like to catch any errors that might occur when creating the stream - in a try catch or something similar.  Since it&#x27;s a stream it is a bit more complex, since it has an event to listen to for errors .. which I assume the handler would want to handle in this case.  But in general, if I were to need to catch unexpected errors how would I manage an exception that doesn&#x27;t conform to the Result signature here? Or should I use a more generic Result signature with Error as the Error type and just pass up exceptions as wrapped errors in the result, for e.g. (and the missing file error would still be of type FileNotFoundError)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The function should try to do its best to prevent rouge exceptions. What we have here in this example is good and if there is a rogue exception then the caller should handle it or not. I dont like the idea of a generic Error type in the signature since its unclear of the intent of the function. Rogue exceptions are well that, rouge. We should do our best and the example code above seems to do the best it can. I’d say make a judgement call and we can go from there.&lt;&#x2F;p&gt;
&lt;p&gt;The one addition I would add to that is that you can handle &quot;rouge&quot; &#x2F; unhandled errors not by generalizing the return type to use Error but instead by formalizing the concept of Unhandled error as part of the valid error type in the return type.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Git Commit Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-git-commit/"/>
        <id>https://drewdeponte.com/blog/uptech-git-commit/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-git-commit/">&lt;p&gt;The Git commit is probably the most fundamental unit we have to manage the growth and evolution of our source code. Git commits can be extremely useful sometimes and other times they can be useless. The following are the guidelines we have honed in on over the years to help make sure that our commits end up being the valuable kind.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;commit-characteristics&quot;&gt;Commit Characteristics&lt;&#x2F;h2&gt;
&lt;p&gt;To aid with making sure our commits are the valuable kind and ensure they play nicely in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; and Continuous Integration methodologies we use the following characteristics as a checklist.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;logical&lt;&#x2F;li&gt;
&lt;li&gt;buildable&lt;&#x2F;li&gt;
&lt;li&gt;testable&lt;&#x2F;li&gt;
&lt;li&gt;not-necessarily complete&lt;&#x2F;li&gt;
&lt;li&gt;releasable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;logical&quot;&gt;Logical&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Each commit should be a logical unit.&lt;&#x2F;strong&gt; This means it should include only changes related to that logical unit. This includes related code changes, automated test changes, tooling changes, etc. This is &lt;strong&gt;crucial&lt;&#x2F;strong&gt; to support the ability to easily revert changes when necessary. It is also crucial for aiding in doing any sort of git commit tree spelunking.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;buildable&quot;&gt;Buildable&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Each commit should be buildable.&lt;&#x2F;strong&gt; This means that each commit must NOT break the build tooling or build process of the application. This is important to make sure that all the Git tooling (e.g. git bisect) continues to be able to be used. It also more clearly supports Git tree spelunking and hot fixing as no matter what commit you pick it should be in a buildable state.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;testable&quot;&gt;Testable&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Each commit should be testable.&lt;&#x2F;strong&gt; This means that each commit must NOT break the automated testing tools or the tests. Similar to buildable this is important to make sure that all the Git tooling (e.g. git bisect) continue to work. It also helps with hot fixing, etc.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;not-ncessarily-complete&quot;&gt;Not-Ncessarily Complete&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Each commit does NOT have to be complete.&lt;&#x2F;strong&gt; This means that you could for example have a commit that introduces a new method to an existing class. That is a complete logical change that is buildable and testable. But it isn&#x27;t complete in terms of its interactions with other application architecture concepts. This is really just a reminder that we should &lt;strong&gt;NOT&lt;&#x2F;strong&gt; be including tagentially related changes into our logical commits.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;releasable&quot;&gt;Releasable&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;Each commit should be releasable.&lt;&#x2F;strong&gt; This means that once that commit is integrated into mainline. We should be able to cut a release of the application without a problem. So it shouldn&#x27;t break the release process and it shouldn&#x27;t leave the user experience of the application in a broken state. Most of the time you will find that commits can just naturally be releasable. But sometimes it means that you have to create initially unused alternate code paths or use feature flags&#x2F;toggles to manage code paths so that code can be integrated into mainline while still keeping the commit releasable.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;git-patch-stack&quot;&gt;Git Patch Stack&lt;&#x2F;h2&gt;
&lt;p&gt;To help us follow these best practices we have developed a workflow on top of Git called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-ps.sh&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; and built a small command line Git extension to help streamline it. You can get a deeper understanding of this workflow and how to use it via our blog posts, &lt;a href=&quot;&#x2F;blog&#x2F;journey-to-small-pull-requests&#x2F;&quot;&gt;Journey to Small Pull Requests&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using Git&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-communication-tool&quot;&gt;A Communication Tool&lt;&#x2F;h2&gt;
&lt;p&gt;Just as import if not &lt;em&gt;more important&lt;&#x2F;em&gt; than the source code change is the commit message itself. This is the only mechanism a commit author has to communicate very important things like, &lt;strong&gt;what&lt;&#x2F;strong&gt;, &lt;strong&gt;intention&lt;&#x2F;strong&gt;, &lt;strong&gt;reason (a.k.a. why)&lt;&#x2F;strong&gt;, &lt;strong&gt;approach (a.k.a. how)&lt;&#x2F;strong&gt;, all crafted with &lt;strong&gt;context&lt;&#x2F;strong&gt;. Having this crucial information bound to the source code change is amazingly powerful and valuable when developing and maintaining an application over time.&lt;&#x2F;p&gt;
&lt;p&gt;We have found it is also a useful communication tool for some automation tasks. Specifically for including Changelog entry information so that we don&#x27;t create unnecessary conflicts in the commit itself. &lt;a href=&quot;&#x2F;blog&#x2F;keep-a-changelog-without-conflicts&#x2F;&quot;&gt;Git Changelog&lt;&#x2F;a&gt; can then use this information to generate our Changelog files for us.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;official-git-commit-message-format&quot;&gt;Official Git Commit Message Format&lt;&#x2F;h3&gt;
&lt;p&gt;Git as a tool has guidelines for commit messages to work best with git and its various tools. This format is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Short summary of change (50 charecters or less in length)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One ore more paragraphs of text hard wrapped at 72 characters in length.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;our-git-commit-message-format&quot;&gt;Our Git Commit Message Format&lt;&#x2F;h3&gt;
&lt;p&gt;We have built on the Official Git Commit Message Format to make sure we include this extremely important information. The following outlines our format.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Short summary of change (the what) - 50 characters or less in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One or more paragraphs explaining the INTENTION &amp;amp; REASON of the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;change with valuable context. (Hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;One or more paragraphs explaining the APPROACH taken to attempt to achieve&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the INTENTION or a portion of the INTENTION.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(Hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Associated Ticket Identifers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Git Changelog header and entries if applicable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;definitely-not-what-we-are-looking-for&quot;&gt;Definitely &lt;strong&gt;NOT&lt;&#x2F;strong&gt; what we are looking for&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Intergrate Sentry for crash handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;or even worse&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Update project.pbxproj&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Picture someone throwing this commit over a wall to you with no other information and they asked you to review it. What would you actually be able to say about it other than what is already included in the diff. You could maybe call out a small syntactical, style, or maybe some logic things strictly based on the diff itself. But you wouldn&#x27;t be able to provide any value in the peer review on if the changes meet the &lt;strong&gt;intent&lt;&#x2F;strong&gt; because you don&#x27;t know what the &lt;strong&gt;intent&lt;&#x2F;strong&gt; is. You can&#x27;t analyze the &lt;strong&gt;approach&lt;&#x2F;strong&gt; and provide valuable analysis of it, nor can you understand if the change is the right change to make to reach the over arching &lt;strong&gt;reason&lt;&#x2F;strong&gt; for the change. We don&#x27;t even know from the short summary provided what in the project.pbxproj file changed. As a result you&#x27;d have to read the entire diff of changes and infer the intent, approach, and reason.&lt;&#x2F;p&gt;
&lt;p&gt;Making logical, purposeful, buildable, testable, not-necessarily complete, but releasable commits with verbose commit messages may seem like overkill, but it becomes immensely useful for all the reasons stated in this guide, and more important when you no longer have access to the original developer who made the change! There are even benefits seen when the developer can&#x27;t recall the intent, approach, and reason of changes that were made only a couple months ago.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;what-we-are-looking-for&quot;&gt;What we are looking for&lt;&#x2F;h4&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Intergrate Sentry for crash handling&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;We did this because we previously had to get rid of MS AppCenter because&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;it wasn&amp;#39;t compatible with mac Catalyst. The belief is that Sentry is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;actually compatible and may be a better solution for us with the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;need to support mac Catalyst. Also, living with out crash reporting is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;just not smart.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This involved making a build configuration change to the Debug&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Information Format changing it from `dwarf` to `dwarf-with-dysm` so that&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;we could also add a build phase script that would upload the build&amp;#39;s&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;dsyms to Sentry so that it could symbolic the backtraces.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Beyond that we registered the sentry API tokens and enabled the crash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;handler at app launch. Note: We did this with two different Sentry&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;projects, one for the mac Catalyst build and the other for the iOS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(iPad&#x2F;iPhone) build. This is necessary because they are separate builds&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;that get deployed separately.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;commit-message-template&quot;&gt;Commit Message Template&lt;&#x2F;h3&gt;
&lt;p&gt;If you are having difficulties remembering the git commit message format and what you need to provide in your message you are in luck. Git provides a commit message template feature. You can set it up with the follownig steps.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Create your template file in a safe place with the following content. Common practice is to put it in &lt;code&gt;~&#x2F;.gitmessage&lt;&#x2F;code&gt;.&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Short summary of change (the what) ( &amp;lt;= 50 chars )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# INTENTION of the change &amp;amp; REASON for change&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# (Hard wrapped at 72 chars) &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# APPROACH taken &amp;amp; WHY in relation to attempting to achieve INTENTION&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# (Hard wrapped at 72 characters)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Deployment or Rollout Considerations&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Automated Tests considerations - if **NOT** why?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Associated Ticket Identifers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Git Changelog header and entries if applicable&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# [changelog]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# added: some addition you made that you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# changed: some change you made that you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# deprecated: some deprecation notice you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# removed: some removal you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# fixed: some fix you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# security: some security fix you want in your changelog&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Configure Git to use your new commit message template&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git config --global commit.template ~&#x2F;.gitmessage&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Make commits &lt;strong&gt;without&lt;&#x2F;strong&gt; (&lt;code&gt;-m&lt;&#x2F;code&gt;) and it will bring up the commit message template in your editor.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Peer Reviews</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-peer-reviews/"/>
        <id>https://drewdeponte.com/blog/uptech-peer-reviews/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-peer-reviews/">&lt;p&gt;The intent of this document is to provide a reference document for the Peer
Review Process that we follow.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;goals&quot;&gt;Goals&lt;&#x2F;h2&gt;
&lt;p&gt;The following are the main intentions of this process.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;improve code maintainability&lt;&#x2F;li&gt;
&lt;li&gt;reduce defects in production&lt;&#x2F;li&gt;
&lt;li&gt;developer growth&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;participants&quot;&gt;Participants&lt;&#x2F;h2&gt;
&lt;p&gt;All developers, no matter skill level, should participate in the peer
review process. If only a subset of the team does the peer reviews, this bogs
down the more senior people with a disproportionate amount of work. The senior
people usually are already spending time helping others, so we don&#x27;t want to put
even more work on them. Additionally junior people can benefit from looking at
senior developer&#x27;s work. They can see what the code should be like and learn
tips&#x2F;tricks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;mindset&quot;&gt;Mindset*&lt;&#x2F;h2&gt;
&lt;p&gt;Please be open to suggestions from your peer reviewers and don&#x27;t take things
personally. On the flip side, please be aware that someone has put in a lot of
effort into their code and sometimes there can be multiple viewpoints. In order
to have a better collaborative experience for all people involved and still
achieve the stated goals, please consider the following suggestions:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ask questions:&lt;&#x2F;strong&gt; How does this method work? If this requirement changes,
what else would have to change? How could we make this more maintainable?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Compliment &#x2F; reinforce good practices:&lt;&#x2F;strong&gt; One of the most important parts of
the code review is to reward developers for growth and effort. Few things feel
better than getting praise from a peer. Try to offer as many positive
comments as possible.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Discuss directly for more detailed points:&lt;&#x2F;strong&gt; On occasion, a recommended
architectural change might be large enough that it’s easier to discuss it in
person rather than in the comments. Similarly, if you are discussing a point
and it goes back and forth, just pick it up in person and finish out the
discussion.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Explain reasoning:&lt;&#x2F;strong&gt; It’s best both to ask if there’s a better alternative
and justify why you think it’s worth fixing. Sometimes it can feel like the
changes suggested can seem nit-picky without context or explanation.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Make it about the code:&lt;&#x2F;strong&gt; It’s easy to take notes from code reviews
personally, especially if we take pride in our work. It’s best to make
discussions about the code than about the developer. It lowers resistance and
it’s not about the developer anyway, it’s about improving the quality of the
code.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Suggest importance of fixes:&lt;&#x2F;strong&gt; Not all suggestions made need to be acted
upon. Clarifying if an item is important to fix before it can be considered
done is useful both for the reviewer and the reviewee. It makes the results of
a review clear and actionable.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;process&quot;&gt;Process&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;developer-responsibilities&quot;&gt;Developer Responsibilities&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Developer makes a patch&lt;&#x2F;li&gt;
&lt;li&gt;Developer runs all automated test suites and makes sure it&#x27;s green, or
relies on CI server to do so and awaits green response.&lt;&#x2F;li&gt;
&lt;li&gt;Developer manually tests the feature to see if acceptance, functional, ux,
and ui criteria are met.&lt;&#x2F;li&gt;
&lt;li&gt;Deveolper Requests Review of their patch
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; at this point the pull request should meet the &lt;a href=&quot;&#x2F;blog&#x2F;uptech-pull-request&#x2F;&quot;&gt;Pull Request Standards&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;If a patch is not complete, but you want feedback on it earlier in the
process, you can Request Review of it, but indicate clearly in the title
and description that the patch is not complete and not ready to be
merged and what you&#x27;re looking for feedback on.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;reviewer-responsibilities&quot;&gt;Reviewer Responsibilities&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Peer Reviewer assigns themselves to the pull request.&lt;&#x2F;li&gt;
&lt;li&gt;Peer Reviewer checks out the code&lt;&#x2F;li&gt;
&lt;li&gt;Peer Reviewer runs automated tests, if they fail, deny the pull request.&lt;&#x2F;li&gt;
&lt;li&gt;Peer Reviewer does manual testing
&lt;ul&gt;
&lt;li&gt;Does it meet the acceptance criteria identified in the ticket?&lt;&#x2F;li&gt;
&lt;li&gt;Are there any performance issues?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Peer Reviewer reads through the diff and comments on it. (see What to look
for when reviewing below)&lt;&#x2F;li&gt;
&lt;li&gt;Peer Reviewer approves&#x2F;rejects the PR depending on their findings.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;more-developer-responsibilities&quot;&gt;More Developer Responsibilities&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Once approved, the Developer should then publish the patch to close the
pull request and integrate the code. The peer reviewer should &lt;strong&gt;NOT&lt;&#x2F;strong&gt; merge
the code as the developer knows best if it should be integrated into mainline
or not.&lt;&#x2F;li&gt;
&lt;li&gt;Developer should cleanup their remote branch associated with their PR.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;what-to-look-for-when-reviewing&quot;&gt;What to look for when reviewing*&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;high-level&quot;&gt;High Level&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Don&#x27;t Repeat Yourself (DRY):&lt;&#x2F;strong&gt; If you see a block of code that is
duplicated, wrap it in a function and re-use it.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Code left in a better state than found:&lt;&#x2F;strong&gt; If you are changing an area of the
code that’s messy, it’s tempting to add in a few lines and leave. Go one step
further and leave the code nicer than it was found.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;style&quot;&gt;Style&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Commented code:&lt;&#x2F;strong&gt; Good idea to remove any commented out lines.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Function length:&lt;&#x2F;strong&gt; Rule of thumb is that a function should be somewhere
around 1-10 lines in length. If you see a method above 10 lines, it’s likely
needs to be broken down into smaller pieces&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Test coverage:&lt;&#x2F;strong&gt; All new features and bug fixes should have tests. Are the
tests thoughtful? Do they cover the failure conditions? Are they easy to read?
How fragile are they? How big are the tests? Are they slow?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Number of Mocks:&lt;&#x2F;strong&gt; Mocking is great. Mocking everything is not great. Use a
rule of thumb where if there’s more than 3 mocks in a test, it should be
revisited. Either the test is testing too broadly or the function is too
large. Maybe it doesn’t need to be tested at a unit test level and would
suffice as an integration test. Either way, it’s something to discuss.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Meets requirements:&lt;&#x2F;strong&gt; Take a look at the requirements of the story, task, or
bug which the work was filed against. If it doesn’t meet one of the criteria,
it’s better to bounce it back before it goes to QA.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;* some items taken from: &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kevinlondon.com&#x2F;2015&#x2F;05&#x2F;05&#x2F;code-review-best-practices.html&quot;&gt;Code Review BestPractices&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Process</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-process/"/>
        <id>https://drewdeponte.com/blog/uptech-process/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-process/">&lt;h1 id=&quot;discovery-definition&quot;&gt;Discovery &amp;amp; Definition&lt;&#x2F;h1&gt;
&lt;p&gt;One of the first phases we go through in a project is what we refer to in the engineering space as &lt;strong&gt;Discovery &amp;amp; Definition&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The goal of this phase is to get a decent understanding of what the project should be and what the initial scope of the project should be.&lt;&#x2F;p&gt;
&lt;p&gt;This is generally done through a series of meetings between the stake holders and Uptech Studio Product, Engineering, and Design representatives. This is where we combine what we know the client wants with our knowledge and expertise to eventually result in what we are actually going to build for them. This is also often where we pose questions or push back on the client to identify if ideas have been vetted and tested to make sure that their money will be well invested.&lt;&#x2F;p&gt;
&lt;p&gt;Once we have these meetings and have come to a conclusion as to what the product should be and what our initial scope will be we move onto the next phase, Estimations.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;estimations&quot;&gt;Estimations&lt;&#x2F;h1&gt;
&lt;p&gt;Prior to this Product is responsible for outlining User Stories based on the learnings from the Discovery &amp;amp; Definition phase.&lt;&#x2F;p&gt;
&lt;p&gt;Here at Uptech Studio we aren&#x27;t big believers in estimates. In fact we generally don&#x27;t believe or trust in estimates. But our clients need to be able to budget and plan, not down to a date or week even. But they need to have an understand of relatively large time range and budget range to find out if they can even afford to pay us and if the timeline will work for their business need.&lt;&#x2F;p&gt;
&lt;p&gt;So we use this as an opportunity to have the Tech Lead start to think through all the stories and what is going to be involved with them and estimate the story at the &lt;strong&gt;scale of indivdual developer worker days&lt;&#x2F;strong&gt;. This is generally done in Airtable.&lt;&#x2F;p&gt;
&lt;p&gt;We then sum up all the working days and add a &lt;strong&gt;multiplier&lt;&#x2F;strong&gt; based on confidence and unknows using around &lt;strong&gt;1.5&lt;&#x2F;strong&gt; and &lt;strong&gt;2&lt;&#x2F;strong&gt; to account for the fact that estimates are generally over optimistic.&lt;&#x2F;p&gt;
&lt;p&gt;These numbers can then be used to compute roughly time range and cost range based on these estimates.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;project-planning&quot;&gt;Project Planning&lt;&#x2F;h1&gt;
&lt;p&gt;The &lt;strong&gt;Project Planning&lt;&#x2F;strong&gt; phase is where we take the knowledge we gained around the project scope and start planning out the high level technical details around the work. The goal of this phase is to do an initial relatively high level of planning to start to breaking down the technical problem space and identify unknowns, concerns, and blockers. This is generally achieved with the following artifacts of this process which are the responsibility of the Tech Lead to produce.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Systems Architecture&lt;&#x2F;li&gt;
&lt;li&gt;Project Detailed Spec&lt;&#x2F;li&gt;
&lt;li&gt;Defining Unknowns&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;systems-architecture&quot;&gt;Systems Architecture&lt;&#x2F;h2&gt;
&lt;p&gt;The first artifact for this phase is a Systems Level Architecture diagram that the Tech Lead is responsible for putting together. The goal of this is to simply start the conversation and discussion around all the entities in play at a system level and how they are going to interact with eachother. Over time this continues to be updated and used as a conversation piece to discuss and review systems level interactions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-detailed-spec&quot;&gt;Project Detailed Spec&lt;&#x2F;h2&gt;
&lt;p&gt;The Project Detailed Spec is a document that the Tech Lead is again responsible for. This document defines the project scope and goals for review as well as the Systems Architecture to provide context. Beyond that it is a vehicle to explore the next tier down of technical problem solving. This could be how the various components would be interacting with each other. Is it done via GraphQL, REST, etc? What are some rough ideas of what the key functional data is needed to be passed between these system components. These types of questions and thinking. It isn&#x27;t to formalize 100% exactly what the payloads will look like. It is just to get an idea and an understanding to gain more confidence.&lt;&#x2F;p&gt;
&lt;p&gt;The process of the Tech Lead walking through, planning this out and documenting it helps them start to think through all of the components and how they will interact to accomplish the defined goals. This also helps identify up front major unknowns, concerns, and blockers very early on in the project so that those things can be focused on from the get go.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-design-review&quot;&gt;Project Design Review&lt;&#x2F;h2&gt;
&lt;p&gt;Once the Project Detailed Spec is produced the Tech Lead then schedules a &lt;strong&gt;Project Design Review&lt;&#x2F;strong&gt; internal to Uptech Studio. This meeting enables a round of review and feedback on the architecture and design that is documented in the Project Detailed Spec. This generally should have a representative from Product, Design, and Engineering. The people at this point aren&#x27;t from your Squad.  As a Tech Lead you can choose to do Squad internal rounds of feedback with the engineers prior to this meeting.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;project-kick-off&quot;&gt;Project Kick-off&lt;&#x2F;h2&gt;
&lt;p&gt;Once the Tech Lead has held the Project Design Review, gotten feedback, and integrated that feedback into their Systems Level Architecture diagram and Project Detailed Spec they then schedule a &lt;strong&gt;Project Kick-off&lt;&#x2F;strong&gt; meeting with their Squad. This involves all members of the Squad and provides in opportunity to go over everything covered in the Detailed Spec from the project Goals down to how the various components will be interacting and with what data.&lt;&#x2F;p&gt;
&lt;p&gt;The purpose of this meeting is for all the members to get comfortable with all of this and voice any concerns, suggestions, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;upfront-planning&quot;&gt;Upfront Planning?&lt;&#x2F;h2&gt;
&lt;p&gt;I thought Uptech Studio did Agile. We do! Nothing in Agile says that you shouldn&#x27;t do up front planning. Agile is all about iterating and getting feedback throughout the process and adjusting to that feedback. But nothing in it says you shouldn&#x27;t think about how you would build or implement something. Our experience over the years has informed our opinion that doing a small amount of up front planning like this is often a game changer in terms of the success of a project.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;design-review&quot;&gt;Design Review&lt;&#x2F;h1&gt;
&lt;p&gt;This document describes how and when a software design review should take place.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-is-it&quot;&gt;What is it?&lt;&#x2F;h2&gt;
&lt;p&gt;A design review is an opportunity to get feedback on your application design prior to spending a
lot of time working on the implementation.&lt;&#x2F;p&gt;
&lt;p&gt;Even if you love to do emergent design using TDD, when projects are large and complex, some
upfront design is necessary. It&#x27;s hard to identify all the components that exist and what their
interactions are with existing systems without taking some time to think through it. It&#x27;s also
really helpful so you can break down a larger project into smaller components.&lt;&#x2F;p&gt;
&lt;p&gt;As a general rule of thumb if a project is going to take &lt;strong&gt;more than a week&lt;&#x2F;strong&gt; to develop, then it
probably should have a design review. Smaller projects will have real quick meetings, whereas
larger projects will probably take some serious brain power.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;when-does-it-take-place&quot;&gt;When does it take place?&lt;&#x2F;h2&gt;
&lt;p&gt;A design review should happen after the requirements have been documented and delivered to the
implementation team, but before any code has been written.&lt;&#x2F;p&gt;
&lt;p&gt;Ideally the product owner will have a kickoff meeting with the team to go over this new feature
and how it should work. After that, the engineers can review the requirements in detail and start
coming up with an implementation plan.&lt;&#x2F;p&gt;
&lt;p&gt;Within a few days of the kickoff meeting, the engineers should have a design review meeting to go
over the plan.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;who-should-be-part-of-it&quot;&gt;Who should be part of it?&lt;&#x2F;h2&gt;
&lt;p&gt;The technical lead of the project is responsible for scheduling time to plan and document the
proposed design. They are also responsible for scheduling the review meeting and making sure they
have proper representation at the meeting.&lt;&#x2F;p&gt;
&lt;p&gt;A design review should have the following people:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Technical Lead&lt;&#x2F;li&gt;
&lt;li&gt;Backend Representative&lt;&#x2F;li&gt;
&lt;li&gt;Front-end Representative&lt;&#x2F;li&gt;
&lt;li&gt;Infrastructure Representative&lt;&#x2F;li&gt;
&lt;li&gt;QA Representative (Ideally the person that will be testing this feature)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Including members from other teams helps to address any concerns they may have earlier in the
process as opposed to later when it&#x27;s more expensive to change.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-does-the-meeting-run&quot;&gt;How does the meeting run?&lt;&#x2F;h2&gt;
&lt;p&gt;During the meeting, the technical lead on the project should review the feature being implemented
at a high level so everyone in the room understands what the business objectives are. After that,
they should walk through a document detailing the implementation plan.&lt;&#x2F;p&gt;
&lt;p&gt;The document should include the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A high level description&lt;&#x2F;li&gt;
&lt;li&gt;A diagram of the different systems&#x2F;components&lt;&#x2F;li&gt;
&lt;li&gt;A sequence diagram indicating interactions between components&#x2F;systems&lt;&#x2F;li&gt;
&lt;li&gt;Interface specifications (REST API, Message Formats, etc.)&lt;&#x2F;li&gt;
&lt;li&gt;Callout for new Infrastructure components&lt;&#x2F;li&gt;
&lt;li&gt;Rollout plan - call out any sequencing required&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;why-should-we-do-this&quot;&gt;Why should we do this?&lt;&#x2F;h2&gt;
&lt;p&gt;Because we want to build awesome products with the highest standards in mind and avoid making
desicions that may bite us in the future.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;roadmapping&quot;&gt;Roadmapping&lt;&#x2F;h1&gt;
&lt;p&gt;The &lt;strong&gt;Roadmapping&lt;&#x2F;strong&gt; phase is where the Tech Lead and the Product representative collaborate together to define a Roadmap of Milestones for the project. During this process we take a number of things into account.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;technical dependencies &amp;amp; constraints&lt;&#x2F;li&gt;
&lt;li&gt;best way to show client progress without fabricating Demos or doing Demo Driven Development.&lt;&#x2F;li&gt;
&lt;li&gt;make sure we can internally deliver testable versions to stakeholders&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is done in Jira using the Roadmap feature. The high level Milestones are broken out and defined &amp;amp; prioritized first based on the criteria above in collaboration with Product.&lt;&#x2F;p&gt;
&lt;p&gt;The Product person then takes the User Stories from the Estimations phase, cleans them up (adding any new ones, adding details to stories, etc.), and organizes them into the roadmapped milestones.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;milestone-planning&quot;&gt;Milestone Planning&lt;&#x2F;h1&gt;
&lt;p&gt;The &lt;strong&gt;Milestone Planning&lt;&#x2F;strong&gt; process is basically the same process that we do in terms of &lt;strong&gt;Project Planning&lt;&#x2F;strong&gt;. The main difference is that we are planning within the scope of a defined &lt;strong&gt;Milestone&lt;&#x2F;strong&gt;. This process is again driven by the Tech Lead. It can be thought of in the following sections.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scoped-systems-architecture-diagram&quot;&gt;Scoped Systems Architecture Diagram&lt;&#x2F;h2&gt;
&lt;p&gt;When doing Milestone Planning you are scoping your thought process and in turn your created artifacts to a particular milestone. Therefore, you are creating a System Architecture Diagram that only focuses on the needs for this particular milestone. This is useful again to provide context but also useful to remove the noise of everything outside of the scope of this Milestone.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;application-architecture&quot;&gt;Application Architecture&lt;&#x2F;h2&gt;
&lt;p&gt;The Application Architecture is where you start to visually layout how your team is going to build an application that will meet the needs of the goals. This again is about components, how data flows through them, and what components handle different types of processing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scoped-protocol-specifications&quot;&gt;Scoped Protocol Specifications&lt;&#x2F;h2&gt;
&lt;p&gt;These protocol specifications again aren&#x27;t inteded to be 100% accurate in terms of every piece of data. It is intended to be a tool to make the Tech Lead think through the core data that needs to be exchanged via this different channels and what those protocols would look like.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;infrastructure-diagram-depends-on-need&quot;&gt;Infrastructure Diagram (depends on need)&lt;&#x2F;h2&gt;
&lt;p&gt;Infrastructucture Diagrams aren&#x27;t always necessary. Basically if there is something complex and abnormal necessary in the infrastructure then we should create an infrastructure diagram. The other use case might be that a client is explicitly requesting or pushing for an Infrastructure Diagram.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sequence-diagram-depends-on-need&quot;&gt;Sequence Diagram (depends on need)&lt;&#x2F;h2&gt;
&lt;p&gt;A Sequence Diagram is again dependent. If you are in a situation where you need to clearly define and communicate about complex interactions between system level or software level components a Sequence Diagram is the tool for you.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;flow-chart-depends-on-need&quot;&gt;Flow Chart (depends on need)&lt;&#x2F;h2&gt;
&lt;p&gt;Flow Charts again aren&#x27;t required but are super useful when you have some complex logic that needs to be planned out and thought out.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;detailed-design-spec&quot;&gt;Detailed Design Spec&lt;&#x2F;h2&gt;
&lt;p&gt;The Tech Lead then puts together a Detailed Design Spec similar to the concept and structure of the Project Design Spec from before except scoped down to the concerns of this one milestone.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unknowns&quot;&gt;Unknowns&lt;&#x2F;h2&gt;
&lt;p&gt;Part of this process is identifying unknowns. We use these unknowns to guide us by effectively being blockers that need to be figured out to complete this milestone. We need to try and answer these unknowns as much as possible prior to the design review. However, some unknowns might be dependent on getting feedback from 3rd party vendors, etc. We should start those conversations with product and the 3rd party vendor ASAP, prior to the design review.&lt;&#x2F;p&gt;
&lt;p&gt;This list of unknowns should be a working list of blockers that should get formalized as tickets and prioritized generally to be figured out ASAP. There are sometimes cases where you might want to not prioritize resolving one of these unknowns until later. This should be vetted with the project&#x27;s principal engineer.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;design-review-1&quot;&gt;Design Review&lt;&#x2F;h2&gt;
&lt;p&gt;Once completed the Tech Lead schedules a design review (same process as before) except this time it happens within the Squad. If the Squad feels they need external imput from people outside the Squad they are welcome to invite other people.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;kick-off-meeting&quot;&gt;Kick-off Meeting&lt;&#x2F;h2&gt;
&lt;p&gt;Once the Design Review process is complete. The Tech Lead schedules a kick-off meeting for the Squad. This has the same purpose as before. It is to get everyone comfortable with everything and provide a venue for people to raise concerns, ask questions, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;task-breakout&quot;&gt;Task Breakout&lt;&#x2F;h2&gt;
&lt;p&gt;One thing that different Squads tend to do differently is task breakout. Some Squads have an extra step here after the kick-off meeting where they schedule a meeting with Squad Product representative and the Engineers on the Squad and go through the tickets in the Milestone and breakout sub-tasks for each of the stories.&lt;&#x2F;p&gt;
&lt;p&gt;Other Squads don&#x27;t do this meeting and instead leave the task breakout to the Engineer that grabs the story. We don&#x27;t have strong opinions on this. It is really whatever the Squad is comfortable with. The key is that our Squads are constantly self evaluating so if there is a problem in this area they can quickly adjust.&lt;&#x2F;p&gt;
&lt;h1 id=&quot;milestone-estimations&quot;&gt;Milestone Estimations&lt;&#x2F;h1&gt;
&lt;p&gt;Despite our dislike for estimates due to their inaccurate nature we still do
them in some form because the reality of the situation is that we need to know
relatively early in the process if we are going to be able to hit a timeline or
not. Obviously we can&#x27;t know this 100% because as we have stated estimates are
very inaccurate. However, they can gives us a pulse to know if we
think we are significantly going to miss a timeline. This is crucial as that
pulse is what instigates pruning of non-crucial features and setting
expectations appropriately with the client.&lt;&#x2F;p&gt;
&lt;p&gt;To facilitate this we of course start with the initial estimates from the
Discovery &amp;amp; Definition phase. However, things have likely changed since that
time and the developers haven&#x27;t thought about the complexities of each of those
milestones.&lt;&#x2F;p&gt;
&lt;p&gt;To facilitate this when a Journey is reviewed by product with the associated
dev team. The dev team goes back through the milestones of that Journey and
puts together estimates based on the following thinking.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;origination-of-thinking&quot;&gt;Origination of Thinking&lt;&#x2F;h3&gt;
&lt;p&gt;Historically we have focused on the concepts of &lt;strong&gt;Complexity&lt;&#x2F;strong&gt; and
&lt;strong&gt;Effort&lt;&#x2F;strong&gt; while putting together estimates and it was only our
Milestone Planning that thought about unknowns and risk.&lt;&#x2F;p&gt;
&lt;p&gt;However, relatively recently Theo dropped a video where he broke down what he
has thought of for a system for estimates. It is very much in alignment with
our current approach as it takes &lt;strong&gt;Complexity&lt;&#x2F;strong&gt; and &lt;strong&gt;Effort&lt;&#x2F;strong&gt; into
consideration. However, beyond that it takes into account &lt;strong&gt;Risk&lt;&#x2F;strong&gt; and goes
through the reasons for estimating in a more analytical fashion. Therefore, we
have effectively adopted his approach with some small tweaks.&lt;&#x2F;p&gt;
&lt;p&gt;We also differ from his approach in that after thinking through these
characteristics we then estimate how long things will take (in developer days)
using these characteristics guidence. This is critical for us to understand how
we are making progress in terms of our estimates so that we can make
adjustments and manage client expectations appropriately.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=XhUAIVJ62dQ&quot;&gt;Theo - Why Are Estimations So Hard??? PLANNING TASKS AS AN ENGINEER&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;why-we-estimate&quot;&gt;Why we estimate?&lt;&#x2F;h2&gt;
&lt;p&gt;We do estimates at the epic level for the following reasons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Identify who should do it&lt;&#x2F;li&gt;
&lt;li&gt;Identify when it should be done&lt;&#x2F;li&gt;
&lt;li&gt;Identify low performers&lt;&#x2F;li&gt;
&lt;li&gt;Bring risk to the forefront so that it can be addressed&#x2F;mitigated&lt;&#x2F;li&gt;
&lt;li&gt;Prioritize based one ^&lt;&#x2F;li&gt;
&lt;li&gt;Identify how long it will take (this will be wrong, but hopefully taking the following system into account will help make it less wrong)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;the-breakdown&quot;&gt;The Breakdown&lt;&#x2F;h2&gt;
&lt;p&gt;Our estimation system is broken down into 3 categories, Complexity,
Effort, and Risk.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;&#x2F;strong&gt; (1-10) - How &quot;hard&quot; is this thing to do?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Effort&lt;&#x2F;strong&gt; (1-10) - How much work does it take?&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Risk&lt;&#x2F;strong&gt; (1-10) - What are the chances that Complexity or Effort is off?&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;&#x2F;h2&gt;
&lt;p&gt;When first getting a team started thinking in this way we have found that it is
useful to often go down to the story level and document the &lt;strong&gt;Complexity&lt;&#x2F;strong&gt;,
&lt;strong&gt;Effort&lt;&#x2F;strong&gt;, and &lt;strong&gt;Risk&lt;&#x2F;strong&gt; as it ends up being a forcing function to think about
the complexities and risk. Then go back up to the milestone and produce the
milestones &lt;strong&gt;Complexity&lt;&#x2F;strong&gt;, &lt;strong&gt;Effort&lt;&#x2F;strong&gt;, and &lt;strong&gt;Risk&lt;&#x2F;strong&gt;. Then you can look at the
stories overall and validate that your estmiate for the milestone makes sense.&lt;&#x2F;p&gt;
&lt;p&gt;Once the devs start to get the feeling for thinking about &lt;strong&gt;Complexity&lt;&#x2F;strong&gt;,
&lt;strong&gt;Effort&lt;&#x2F;strong&gt;, and &lt;strong&gt;Risk&lt;&#x2F;strong&gt; this process goes really quickly.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;breaking-out-research-tasks&quot;&gt;Breaking out Research Tasks&lt;&#x2F;h2&gt;
&lt;p&gt;As we go through this process we are often running into &lt;strong&gt;Risks&lt;&#x2F;strong&gt; and most of
the time you need to do some further research to understand and mitigate the
risk. This is the perfect time to break those tasks out.&lt;&#x2F;p&gt;
&lt;p&gt;You can also see by doing so how breaking the research task out helps you to
think about and adjust the characteristics for the story and its associated
research task.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;example&quot;&gt;Example&lt;&#x2F;h2&gt;
&lt;p&gt;The following are a couple examples from the video referenced above with the addition of the developer days estimates.&lt;&#x2F;p&gt;
&lt;p&gt;Display voice levels in pre-call view&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;&#x2F;strong&gt;: 4&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Effort&lt;&#x2F;strong&gt;: 2&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Risk&lt;&#x2F;strong&gt;: 6&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Estimate&lt;&#x2F;strong&gt;: 4 dev days&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To reduce the risk of this task we could create a research task to figure out
one of the bigger pieces of risk. For example.&lt;&#x2F;p&gt;
&lt;p&gt;Identify how to get voice levels from 3p SDK&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complexity&lt;&#x2F;strong&gt;: 2&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Effort&lt;&#x2F;strong&gt;: 2&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Risk&lt;&#x2F;strong&gt;: 4&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Estimate&lt;&#x2F;strong&gt;: 1 dev day&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio README.md Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-readme/"/>
        <id>https://drewdeponte.com/blog/uptech-readme/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-readme/">&lt;p&gt;We require &lt;code&gt;README.md&lt;&#x2F;code&gt; files in our repositories so that people can understand the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;what the repository is&lt;&#x2F;li&gt;
&lt;li&gt;how it fits into the bigger context&lt;&#x2F;li&gt;
&lt;li&gt;how to get the development environment up and running&lt;&#x2F;li&gt;
&lt;li&gt;how to contribute to it&lt;&#x2F;li&gt;
&lt;li&gt;how to run the test suites&lt;&#x2F;li&gt;
&lt;li&gt;how to deploy it.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;readme-md-content&quot;&gt;README.md Content&lt;&#x2F;h2&gt;
&lt;p&gt;The following is an example of a &lt;code&gt;README.md&lt;&#x2F;code&gt; file and its content. Use this as a template.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;markdown&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; git-ps - Git Patch Stack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Git patch stack is an add-on command for Git that facilitates using a patch-stack [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Git&lt;&#x2F;span&gt;&lt;span&gt;][] workflow while still using pull requests for peer review. It accomplishes this by managing your stack of patches and behind the scenes creating branches for patches you request review on and pushing them up to origin.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;It consists of the following commands:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps ls&lt;&#x2F;span&gt;&lt;span&gt;` to list the stack of patches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps show &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;`to show the patch diff and details&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps pull&lt;&#x2F;span&gt;&lt;span&gt;` to fetch the state of origin&#x2F;master and rebase the stack of patches onto it&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps rebase&lt;&#x2F;span&gt;&lt;span&gt;` to interactive rebase the stack of patches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps rr &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;` to request review of the patch or update existing request to review&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps pub &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;` to publish a patch into upstream&amp;#39;s mainline (aka origin&#x2F;master)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps --version&lt;&#x2F;span&gt;&lt;span&gt;` to output the version of information for reference &amp;amp; bug reporting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Installation&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;If you are on a platform other than macOS you will have to build your own&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;version from source.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; macOS&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;To install on macOS we provide a [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Homebrew&lt;&#x2F;span&gt;&lt;span&gt;](http:&#x2F;&#x2F;brew.sh) tap which provides&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;` formula. You can use it by doing the following:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;####&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Add the Tap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	brew tap &amp;quot;uptech&#x2F;homebrew-oss&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;####&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; brew install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	brew install uptech&#x2F;oss&#x2F;git-ps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Build from Source&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;If you are on another platform you will have to build from source. Given&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;that `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;` is managed via [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;GNU make&lt;&#x2F;span&gt;&lt;span&gt;][]. It can be built as follows:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	$ make build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Once you have built it successfully you can install it in `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&lt;&#x2F;span&gt;&lt;span&gt;` using the following:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	$ make install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Development&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;We use [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;GNU make&lt;&#x2F;span&gt;&lt;span&gt;][] to manage the developer build process with the following commands.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;make build&lt;&#x2F;span&gt;&lt;span&gt;` - build release version of the `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;make install&lt;&#x2F;span&gt;&lt;span&gt;` - install the release build into `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;make uninstall&lt;&#x2F;span&gt;&lt;span&gt;` - uninstall the release build from `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&lt;&#x2F;span&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;make clean&lt;&#x2F;span&gt;&lt;span&gt;` - clean the build directory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Recommended Git Configuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;People using the patch-stack workflow often enable the pull-rebase option in their `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;.gitconfig&lt;&#x2F;span&gt;&lt;span&gt;` as follows. &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**Note:**&lt;&#x2F;span&gt;&lt;span&gt; This is &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**NOT**&lt;&#x2F;span&gt;&lt;span&gt; required as `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git ps rebase&lt;&#x2F;span&gt;&lt;span&gt;` is used generally. However, it is recommended so when you play outside of `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git ps&lt;&#x2F;span&gt;&lt;span&gt;` you get the same awesome benefits.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	[pull]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			rebase = true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This makes it so that when you do a `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git pull&lt;&#x2F;span&gt;&lt;span&gt;` it will automatically trigger a rebase on top of the tracked branches remote. So, if you are using `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;` and you do a `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git pull&lt;&#x2F;span&gt;&lt;span&gt;` to get recent changes from `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;master&lt;&#x2F;span&gt;&lt;span&gt;`. [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Git&lt;&#x2F;span&gt;&lt;span&gt;][] will automatically initiate a rebase of your changes that were sitting in `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;` ontop of `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;master&lt;&#x2F;span&gt;&lt;span&gt;` on to the new `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;master&lt;&#x2F;span&gt;&lt;span&gt;`. This is exactly what you want as conceptually your stack of patches are always sitting on top of the latest `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;master&lt;&#x2F;span&gt;&lt;span&gt;`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; What is a patch-stack workflow?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The patch stack workflow is a different mental model for doing development locally. Instead of having feature branches and doing work inside them you generally do all your work directly on `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;` by convention. You can think of your local `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;` being a conceptual stack of patches (a.k.a. commits) on top of `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;master&lt;&#x2F;span&gt;&lt;span&gt;`.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The idea is that instead of creating feature branches you simply make commits on your local `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;master&lt;&#x2F;span&gt;&lt;span&gt;` and perform interactive rebases to squash, reorder, ammend, etc. your patches as you continue to develop. This has an amazing benefit. &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**It eliminates the dependent branch problem.**&lt;&#x2F;span&gt;&lt;span&gt; You know the one where you created one change in a branch and submitted for review, but then you went off to create another branch on top of the last one, and so on. Soon enough you have to make changes as a result of the review to the first feature branch. And, down the feature branch rebasing train you go.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The Patch Stack workflow also expects each patch (a.k.a. commit) to be &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**small, buildable, logical units of work with valuable messages**&lt;&#x2F;span&gt;&lt;span&gt; providing the &lt;&#x2F;span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;*what*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;*why*&lt;&#x2F;span&gt;&lt;span&gt;, and any &lt;&#x2F;span&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;*contextual details around how*&lt;&#x2F;span&gt;&lt;span&gt;. This aids drastically in the code review process as each patch becomes a very focused piece of work with clear intent. It also helps conceptually &amp;quot;show your work&amp;quot;, the logical progression of changes (patches) needed to accomplish some larger goal. These principles are as extremely valuable when doing historical spelunking to learn a code base or to iron out a bug. These principles bring even more value as they enable you to take advantage of all the amazing features of [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Git&lt;&#x2F;span&gt;&lt;span&gt;][], e.g. `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git bisect&lt;&#x2F;span&gt;&lt;span&gt;`, etc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Common tasks git-ps assists with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Visualizing your Stack of Patches&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] provides the &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**list**&lt;&#x2F;span&gt;&lt;span&gt; command (`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git ps ls&lt;&#x2F;span&gt;&lt;span&gt;`) to visualize your current stack of patches and the state around each of the patches. The output of this command for the example above would look something like the following.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		2     4387d1 add login view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		1     23d7a6 add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		0     af73d2 add lib to facilitate making REST API requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This outputs what we call the `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;` on the left followed by, state identifiers (not visible in this example), and then the short SHA of the patch and its summary.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;The following is a description of the structure and the possible state identifiers.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git-ps ls result structure:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	[patch-index] [review status] [commit short sha] [commit summary]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&amp;quot;0  rr  788032 Update README with deployment instructions&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git-ps ls Review Status:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				Has NOT requested a review (AKA Empty)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	rr    Requested a review and it&amp;#39;s unchanged since requesting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	rr+   Requested a review and it has changed since requesting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	p     Commit has been published to upstreams mainline&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Submitting a Patch for Review or Integration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] also makes submitting a patch for review or integration much easier. Instead of having to do these four steps as discussed in sections above.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1. create a branch based on the current branch&amp;#39;s upstream remote branch (e.g. `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;main&lt;&#x2F;span&gt;&lt;span&gt;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;2. cherry pick the patch you want reviewed to this new branch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3. push this branch up to the remote (e.g. `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;this-patches-branch&lt;&#x2F;span&gt;&lt;span&gt;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;4. create a pull request from this new branch (`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;this-patches-branch&lt;&#x2F;span&gt;&lt;span&gt;`) into upstream mainline (`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;origin&#x2F;main&lt;&#x2F;span&gt;&lt;span&gt;`)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] simplifies this down to a single command called &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**request review**&lt;&#x2F;span&gt;&lt;span&gt; (`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git ps rr &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;`).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;If we wanted to request review or even re-request review of a patch we simply do the following.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git ps rr &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Don&amp;#39;t worry if the SHA of a patch changes since your original request for review. [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] is smart enough to handle this. &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Pull Changes down from Upstream&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] also helps you pull changes down from upstream so that you can integrate your local patches with the work that has recently been added to upstream.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is as simple as running&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git ps pull&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This facilitates fetching the changes from upstream and rebasing your stack of patches on top of them.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;*Note:*&lt;&#x2F;span&gt;&lt;span&gt; If one of your patches was integrated into upstream, it will simply collapse out of your stack of patches as Git sees that it is a duplicate of a change that is already integrated in upstream.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Publish a Commit Upstream&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Once a patch has been approved through the peer review process, you generally want to integrate it into the upstream branch. This can be done by using things like GitHub&amp;#39;s green button. However, this often creates useless noise in the Git tree, and also requires additional manual cleanup steps on your part to remove the no longer needed remote branches.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] provides the &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;**publish**&lt;&#x2F;span&gt;&lt;span&gt; command specifically to address publishing the local patch to the upstream branch without creating useless noise in the Git tree and cleaning up the no longer necessary remote branch. This can be done as follows.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git ps pub &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; See a particular Patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Another feature that [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] provides is the ability to quickly show the contents of a particular patch. This is as simple as the following.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git ps show &amp;lt;patch-index&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;###&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Reorder &amp;amp; Update your Patch Stack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;In this methodology one of the most common things you do is reorder and update your respective patches while you are iterating on things, and getting them to an acceptable state to request review. As we covered above, interactive rebase `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git rebase -i&lt;&#x2F;span&gt;&lt;span&gt;` is an extremely valuable tool that helps facilitate this.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Therefore, [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;][] simplifies the use of it by using the understanding of the stack of patches concept to automatically fill in the appropriate arguments for the `&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git rebase -i&lt;&#x2F;span&gt;&lt;span&gt;` command. In turn making an interactive rebase of your stack of patches as simple as&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git ps rebase&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; License&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;` is Copyright © 2020 UpTech Works, LLC. It is free software, and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;may be redistributed under the terms specified in the LICENSE file.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; About &lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;img&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; src&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;http:&#x2F;&#x2F;upte.ch&#x2F;img&#x2F;logo.png&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; alt&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;uptech&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; height&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;48&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;`&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;` is maintained and funded by [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;UpTech Works, LLC&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;uptech&lt;&#x2F;span&gt;&lt;span&gt;], a software&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;design &amp;amp; development agency &amp;amp; consultancy.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;We love open source software. See [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;our other projects&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;community&lt;&#x2F;span&gt;&lt;span&gt;] or&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;hire us&lt;&#x2F;span&gt;&lt;span&gt;][&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;hire&lt;&#x2F;span&gt;&lt;span&gt;] to design, develop, and grow your product.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;Git&lt;&#x2F;span&gt;&lt;span&gt;]: https:&#x2F;&#x2F;git-scm.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;GNU make&lt;&#x2F;span&gt;&lt;span&gt;]: https:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;make&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;community&lt;&#x2F;span&gt;&lt;span&gt;]: https:&#x2F;&#x2F;github.com&#x2F;uptech&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;hire&lt;&#x2F;span&gt;&lt;span&gt;]: http:&#x2F;&#x2F;upte.ch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;uptech&lt;&#x2F;span&gt;&lt;span&gt;]: http:&#x2F;&#x2F;upte.ch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;git-ps&lt;&#x2F;span&gt;&lt;span&gt;]: https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Releasing Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-releasing/"/>
        <id>https://drewdeponte.com/blog/uptech-releasing/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-releasing/">&lt;p&gt;Here at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; given that we use semantic versioning as our
&lt;a href=&quot;&#x2F;blog&#x2F;uptech-versioning&#x2F;&quot;&gt;standard for versioning&lt;&#x2F;a&gt; we can talk instead about the process of doing a
release.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;normal-release&quot;&gt;Normal release&lt;&#x2F;h2&gt;
&lt;p&gt;Cutting a release consists of the following steps.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;identify the commit in the Git history that is to be the release - generally this is &lt;code&gt;HEAD&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;tag the commit with the new release version number, e.g. &lt;code&gt;1.2.3&lt;&#x2F;code&gt; or &lt;code&gt;v1.2.3&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;push tags up to the remote, e.g. &lt;code&gt;git push --tags&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;update the &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; if not automatically handled by CI, e.g. &lt;code&gt;git cl full &amp;gt; CHANGELOG.md&lt;&#x2F;code&gt; - &lt;em&gt;Note:&lt;&#x2F;em&gt; if this was an app with build numbers in the version you would use &lt;code&gt;git cl full -p &amp;gt; CHANGELOG.md&lt;&#x2F;code&gt;.
&lt;ul&gt;
&lt;li&gt;commit and push the update &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; commit for that version release&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;avoid-hot-fix-release&quot;&gt;Avoid Hot-fix release&lt;&#x2F;h2&gt;
&lt;p&gt;We avoid &quot;hot-fix&quot; releases if we can. What this means in practice is that if we have a version that is released and we identify an issue with it. Instead of prepping a hot-fix release we just add the fix to the top of the tree and cut a new release including that fix as well as the other changes integrated into mainline.&lt;&#x2F;p&gt;
&lt;p&gt;This works because our &lt;a href=&quot;&#x2F;blog&#x2F;uptech-branching-strategies&#x2F;&quot;&gt;Branching Strategy&lt;&#x2F;a&gt; is based on Continous Integration and Trunk Based Development which keeps our mainline in a build &amp;amp; releasable state.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hot-fix-release&quot;&gt;Hot-fix release&lt;&#x2F;h2&gt;
&lt;p&gt;If for some reason we had to do a hot-fix release. There is nothing stopping us from being able to do it. We would have to simply perform the following steps.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;identify the tagged release that the issue is found on in our Git tree&lt;&#x2F;li&gt;
&lt;li&gt;create a new hot-fix branch based on that tagged commit&lt;&#x2F;li&gt;
&lt;li&gt;add a commit to that hot-fix branch to resolve the issue&lt;&#x2F;li&gt;
&lt;li&gt;tag that commit with the new release version number&lt;&#x2F;li&gt;
&lt;li&gt;backport that commit to mainline so the next release will also include it&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;automated-releases&quot;&gt;Automated Releases&lt;&#x2F;h2&gt;
&lt;p&gt;We do &lt;strong&gt;not&lt;&#x2F;strong&gt; setup automated releases for libraries. Apps and Services on the other hand we do generally in the lower environments. But with some projects even in the production environment.&lt;&#x2F;p&gt;
&lt;p&gt;In the App case the automated releases are only used for internal release, bumping build numbers, and getting feedback from stakeholders. We generally use MS AppCenter for this.&lt;&#x2F;p&gt;
&lt;p&gt;In the Services case the automated releases are fine as build numbers as the interfaces are versioned within the code base.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;marketing-releases&quot;&gt;Marketing Releases&lt;&#x2F;h2&gt;
&lt;p&gt;When we are doing a public Marketing Release of an application we go through the &lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;uptech-releasing&#x2F;#normal-release&quot;&gt;normal release&lt;&#x2F;a&gt; process with tags and changelog, etc.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Roles</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-studio-roles/"/>
        <id>https://drewdeponte.com/blog/uptech-studio-roles/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-studio-roles/">&lt;p&gt;Lets first understand exactly what a &lt;strong&gt;role&lt;&#x2F;strong&gt; is. According to the macOS Dictionary it is &quot;the function or part played by a person or thing&quot;. The distinction here is that a role is &lt;strong&gt;not a person or their title&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It is something a person takes on. For our discussion the role itself is a categorization of work that is to be performed or acted by a person. This means that a person could take on multiple roles potentially. As you can see below the roles of Staff Engineer &amp;amp; Engineering Manager are both played by our Partners.&lt;&#x2F;p&gt;
&lt;p&gt;The following are a breakdown of the Engineering roles at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Developers&lt;&#x2F;li&gt;
&lt;li&gt;Tech Lead&lt;&#x2F;li&gt;
&lt;li&gt;Staff Engineer (played by Partner)&lt;&#x2F;li&gt;
&lt;li&gt;Engineering Manager (played by Partner)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;client-focused&quot;&gt;Client Focused&lt;&#x2F;h3&gt;
&lt;p&gt;No matter what role(s) a person is playing it is crucial that they are client focused. We are all responsible for understanding the client&#x27;s business needs and helping to ensure we&#x27;re always doing what&#x27;s best for them.&lt;&#x2F;p&gt;
&lt;p&gt;For example critically thinking about feature requests and how those impact the user and presenting alternatives that may not be quite as effective, but much less costly in terms of development. This type of thinking and conversation is crucial to have with clients to make sure together we are doing what is best for their business at their current lifecycle stage.&lt;&#x2F;p&gt;
&lt;p&gt;We expect everyone within Engineering at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; to be able to mentally step back from their technical tasks and critically think about the client&#x27;s business.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;developers&quot;&gt;Developers&lt;&#x2F;h3&gt;
&lt;p&gt;The following are expectations we have of people playing the role of Senior Developer. These are intended to be used as a guiding light for the long term direction developers should be heading as they grow to play a Senior Developer within &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;client focused&lt;&#x2F;li&gt;
&lt;li&gt;deep experience in specific platform&#x2F;tech stack with broad experience in other areas (T shaped employee)&lt;&#x2F;li&gt;
&lt;li&gt;understanding of engineering processes and practices
&lt;ul&gt;
&lt;li&gt;having a good understanding of how we do engineering here at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;, agile processes, git processes, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;have sound understanding and usage of application architecture
&lt;ul&gt;
&lt;li&gt;architecting a solution within the scope of a framework&lt;&#x2F;li&gt;
&lt;li&gt;architecting a solution outside the scope of a framework&lt;&#x2F;li&gt;
&lt;li&gt;identifying framework architectural concepts and boundaries and where to apply framework architecture vs outside scoped architecture&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;break down problem space
&lt;ul&gt;
&lt;li&gt;ability to understand &amp;amp; collaborate with the Tech Lead around the system architecture, application architecture and further breakdown various libraries, components, services, etc.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;drive tasks&#x2F;components&#x2F;etc.
&lt;ul&gt;
&lt;li&gt;identifying broken down components, unknowns, etc. and being the driving force to get them prioritized and resolved to aid in accomplishing the primary goal&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;tech-lead&quot;&gt;Tech Lead&lt;&#x2F;h3&gt;
&lt;p&gt;Tech Leads have all the same expectations of a Senior Developer in addition to the following. Tech Leads high level focuses are around Architecture, Foundation, Mentorship, Development, and Process management.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;more client interactions because they are generally a &lt;strong&gt;Squad Representative&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;run tech meetings&lt;&#x2F;li&gt;
&lt;li&gt;primary point of contact for engineering questions &amp;amp; interactions&lt;&#x2F;li&gt;
&lt;li&gt;working with Product to do planning for Roadmap and tasks&lt;&#x2F;li&gt;
&lt;li&gt;architect, problem solve, etc.&lt;&#x2F;li&gt;
&lt;li&gt;drive the technical side of achieving the client&#x27;s goal
&lt;ul&gt;
&lt;li&gt;breaking down the problem space at each of the levels&lt;&#x2F;li&gt;
&lt;li&gt;monitoring progress&lt;&#x2F;li&gt;
&lt;li&gt;removing road blocks for team mates&lt;&#x2F;li&gt;
&lt;li&gt;course correcting&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;have sound understanding and usage of infrastructure (AWS, terraform, kubernetes)&lt;&#x2F;li&gt;
&lt;li&gt;have sound understanding and usage of backend &amp;amp; front-end development&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;partners&quot;&gt;Partners&lt;&#x2F;h3&gt;
&lt;p&gt;Due to the current size of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; there are a number of roles, &lt;strong&gt;Staff Engineer&lt;&#x2F;strong&gt; &amp;amp; &lt;strong&gt;Engineering Manager&lt;&#x2F;strong&gt;, that are strictly played by our Engineering Partners, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&quot;&gt;Drew De Ponte&lt;&#x2F;a&gt; &amp;amp; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;cciocan&#x2F;&quot;&gt;Claude Ciocan&lt;&#x2F;a&gt;. It is possible that as the company continues to grow we may decide to have other people take on these roles. However, for the moment they are handled by the Engineering Partners.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;staff-engineer&quot;&gt;Staff Engineer&lt;&#x2F;h4&gt;
&lt;p&gt;Staff Engineers are intended to be a resource shared across the organization to help with standardization, best practices, mentorship, and contribution. Staff Engineers are expected to have all the same expectations of a Tech Lead in addition to the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;shared across the engineering organization&lt;&#x2F;li&gt;
&lt;li&gt;advising tech leads and developers&lt;&#x2F;li&gt;
&lt;li&gt;advising on architecture&lt;&#x2F;li&gt;
&lt;li&gt;advising on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; process&lt;&#x2F;li&gt;
&lt;li&gt;advising on development process&#x2F;tooling&lt;&#x2F;li&gt;
&lt;li&gt;advising on coding best practices&lt;&#x2F;li&gt;
&lt;li&gt;helps on specific tasks&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h4 id=&quot;engineering-manager&quot;&gt;Engineering Manager&lt;&#x2F;h4&gt;
&lt;p&gt;The Engineering Manager role is responsible for being direct managers of the Developers &amp;amp; Tech Leads from an HR standpoint. We believe in servant leadership and the idea of trying to understand peoples interests so that we can find their best fit and growth path within &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt;. This involves working to try to align people with projects that would most interest them or aid in their growth in specific areas of interest. We have found that when people are aligned with their interests they tend to do their best work.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Testing Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-testing/"/>
        <id>https://drewdeponte.com/blog/uptech-testing/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-testing/">&lt;p&gt;We have always been big believers in automated testing and Test Driven Development (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Test-driven_development&quot;&gt;TDD&lt;&#x2F;a&gt;). Back in the day we were even big believers in Behavior Driven Development (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Behavior-driven_development&quot;&gt;BDD&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Over the many years we have learned that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cucumber.io&quot;&gt;Cucumber&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cucumber.io&#x2F;docs&#x2F;gherkin&#x2F;&quot;&gt;Gherkin&lt;&#x2F;a&gt; were nice ideas but we never really saw huge value and it required additional adoption from Product which was always a hurdle.&lt;&#x2F;p&gt;
&lt;p&gt;The concept of &lt;strong&gt;emergent design&lt;&#x2F;strong&gt;, the process of evolving application architecture from mocked tests, sounds great in theory. But in practice we didn&#x27;t see any real added value once you have written the non-mocked tests. This is because the mocked tests become brittle noise that isn&#x27;t worth maintaing and in fact interfere with the process of refactoring functionality. Even if you take the stance of removing these mocked tests, the development team has then taken on the burden of identifying which tests to remove and when to remove them. This is simply more overhead that doesn&#x27;t provide any real payout.&lt;&#x2F;p&gt;
&lt;p&gt;Now there is no reason to throw the baby out with the bath water. There were ideas in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Behavior-driven_development&quot;&gt;BDD&lt;&#x2F;a&gt; that we found to be extremely valuable. For example the concept of applying Outside-In Development as a way of making sure that what is being developed throughout the application architecture is actually necessary. We found this practice aids immensely with not only making sure the right software is built but also with the process of identifying architectural boundaries and doing application architecture.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore our current position on testing is a hybrid of the various methodologies we have used over the years. The principles we follow are listed below.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Outside-In&lt;&#x2F;li&gt;
&lt;li&gt;Test First&lt;&#x2F;li&gt;
&lt;li&gt;Small Tests&lt;&#x2F;li&gt;
&lt;li&gt;Red, Green, Refactor&lt;&#x2F;li&gt;
&lt;li&gt;State over Behavior&lt;&#x2F;li&gt;
&lt;li&gt;Unit &amp;amp; Integration&lt;&#x2F;li&gt;
&lt;li&gt;Setup in Test&lt;&#x2F;li&gt;
&lt;li&gt;Full-Stack Integration within Reason&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;outside-in&quot;&gt;Outside-In&lt;&#x2F;h2&gt;
&lt;p&gt;As described above we value Outside-In Development from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Behavior-driven_development&quot;&gt;BDD&lt;&#x2F;a&gt; as a way of making sure that what is being developed throughout the application architecture is actually necessary. Additionaly we value it as a tool for aiding with architecting an application as well as identifying application architecture boundaries. Which are both extremely useful when writing software in a fashion supporting collaboration. You can see more on Outside-In and how it relates to some of our other processes in our &lt;a href=&quot;&#x2F;blog&#x2F;journey-to-small-pull-requests&#x2F;&quot;&gt;Journy to Small Pull Requests&lt;&#x2F;a&gt; and &lt;a href=&quot;&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;&quot;&gt;How we should be using Git&lt;&#x2F;a&gt; posts.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;test-first&quot;&gt;Test First&lt;&#x2F;h2&gt;
&lt;p&gt;We also strongly abide by the concept of &quot;Test First&quot;, the practice of writing a failing test against a nonexistent idealized API and then following the Red, Green, Refactor process to iterate the test &amp;amp; implementation to its final state.&lt;&#x2F;p&gt;
&lt;p&gt;The primary reason we value &quot;Test First&quot; so much is because the practice of thinking about what the ideal API would look like and using the first iteration of writing the test as a tool for this has huge positive impacts in terms of the application architecture and its maintainability over time.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that it also benefits in helping to make sure that the tests fully cover the implemented code. If instead you were to for example to write a function first and then go back and write the test after the fact. You would discover over time that it is very easy to miss cases and end up with a test suite that doesn&#x27;t fully cover all the cases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;small-tests&quot;&gt;Small Tests&lt;&#x2F;h2&gt;
&lt;p&gt;As a general rule of thumb we stick to one conceptual assertion per test. What this means is that we effectively want to test and verify one thing. If we are testing say a function that returns an object that should have multiple attributes on it in a new state. Then we would have multiple assertions to verify those. But conceptually we are still verifying the resultant state of that one action.&lt;&#x2F;p&gt;
&lt;p&gt;There are cases, when doing higher level integration tests especially, where it may make sense to actually do multiple conceptual assertions. However, this is the exception not the rule.&lt;&#x2F;p&gt;
&lt;p&gt;Sticking to one conceptual assertion keeps our tests focused in such a manner that when one fails it is focused enough that we don&#x27;t have to do a ton of debugging to identify what the problem is. Generally the failing test immedietly tells us exactly what the problem is. This of course does not hold true for higher level integration tests, especially the ones that have multiple conceptual assertions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;red-green-refactor&quot;&gt;Red, Green, Refactor&lt;&#x2F;h2&gt;
&lt;p&gt;Red, Green, Refactor is really just a name for a process that occurs naturally when doing &quot;Test First&quot; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Test-driven_development&quot;&gt;TDD&lt;&#x2F;a&gt;. It simply communicates the enforcement of the sequence of the testing process.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;write a failing test - a.k.a. Red&lt;&#x2F;li&gt;
&lt;li&gt;write code that makes the test pass - a.k.a. Green&lt;&#x2F;li&gt;
&lt;li&gt;clean up the the implementation that makes the test pass by refactoring it - a.k.a. Refactor&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Over the years this naming has been overloaded by being utilized at a micro level to explain the iterative process of doing &quot;Test First&quot; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Test-driven_development&quot;&gt;TDD&lt;&#x2F;a&gt;. In this context is more along the lines of the following.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;write a failing test (in initial state, not final state) - a.k.a. Red&lt;&#x2F;li&gt;
&lt;li&gt;write code that makes the test pass - a.k.a. Green&lt;&#x2F;li&gt;
&lt;li&gt;evolve the test to test more of what it should, leaving you with a now failing test - a.k.a. Refactor, Red&lt;&#x2F;li&gt;
&lt;li&gt;write code that makes the test pass - a.k.a. Green&lt;&#x2F;li&gt;
&lt;li&gt;...&lt;&#x2F;li&gt;
&lt;li&gt;...&lt;&#x2F;li&gt;
&lt;li&gt;evolve the test to test to its final state, leaving you with a now failing test - a.k.a. Refactor, Red&lt;&#x2F;li&gt;
&lt;li&gt;write code that makes the test pass - a.k.a. Green&lt;&#x2F;li&gt;
&lt;li&gt;clean up the the implementation that makes the test pass by refactoring it - a.k.a. Refactor&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;I don&#x27;t think this overloaded adaption to this micro usecase is necessarily the cleanest mapping. But it is what a decent portion of the community has starting using it to refer two. So we might as well at least be clear about it.&lt;&#x2F;p&gt;
&lt;p&gt;As I stated before these are basically just the naturaly processes that occur when doing &quot;Test First&quot; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Test-driven_development&quot;&gt;TDD&lt;&#x2F;a&gt; so we naturally abide by them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state-over-behavior&quot;&gt;State over Behavior&lt;&#x2F;h2&gt;
&lt;p&gt;The concept of &lt;strong&gt;State over Behavior&lt;&#x2F;strong&gt; means that we ideally want to do &lt;strong&gt;State&lt;&#x2F;strong&gt; based testing whenever possible and only use &lt;strong&gt;Behavior&lt;&#x2F;strong&gt; testing when explicitly necessary.&lt;&#x2F;p&gt;
&lt;p&gt;We hold this stance because &lt;strong&gt;State&lt;&#x2F;strong&gt; based testing aids with application architecture design and is naturally long living as well as interface abiding. This means that once we have written a &lt;strong&gt;State&lt;&#x2F;strong&gt; based test it is useful when we go to refector the implementation of a function&#x2F;method. &lt;strong&gt;Behavior&lt;&#x2F;strong&gt; tests are &lt;strong&gt;not&lt;&#x2F;strong&gt; useful and have to be completely reworked when refactoring implementation of a function&#x2F;method.&lt;&#x2F;p&gt;
&lt;p&gt;This position does have implications. For example to support isolation (via stubs&#x2F;test doubles) in our tests we need to modify how we write our code to make sure we are using Dependency Injection. This is an implication we are more than happy to take on as we have found that classic Dependency Injection has aided massively in our application architectures over the years.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;unit-integration&quot;&gt;Unit &amp;amp; Integration&lt;&#x2F;h2&gt;
&lt;p&gt;There are two main categories of tests &lt;strong&gt;Unit&lt;&#x2F;strong&gt; and &lt;strong&gt;Integration&lt;&#x2F;strong&gt;. We are proponents of both of them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Unit&lt;&#x2F;strong&gt; tests are focused around validating a particular unit of code, generally a function&#x2F;method. Therefore, they isolate away collaborator objects. An example might look something like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;stub_shopping_cart = ShoppingCartTestDouble()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add_item(item, stub_shopping_cart)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert(shopping_cart.items.include(item))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above example we replaced the shopping cart by giving the &lt;code&gt;add_item&lt;&#x2F;code&gt; function the &lt;code&gt;stub_shopping_cart&lt;&#x2F;code&gt;. This isolates away any functionality that a real shopping cart whould have had and allows us to strictly test the functionality of just the &lt;code&gt;add_item&lt;&#x2F;code&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Integration&lt;&#x2F;strong&gt; tests are focused around validation of many units of code working together in an integrated fashion. An example might look as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;data_store = DataStore()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;real_shopping_cart = ShoppingCart(data_store)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;add_item(item, real_shopping_cart)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;assert(shopping_cart.items.include(item))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see in the above that it is using real objects rather than Test Doubles or Stub objects. The benefit of this is that it can be used to verify functionality of all those different units of code working together which is also important. Especially to make sure that integrated results are what we expect.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore we write both &lt;strong&gt;Unit&lt;&#x2F;strong&gt; and &lt;strong&gt;Integration&lt;&#x2F;strong&gt; tests.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;setup-in-test&quot;&gt;Setup in Test&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;strong&gt;Setup in Test&lt;&#x2F;strong&gt; is the concept of making sure that the &lt;strong&gt;setup&lt;&#x2F;strong&gt; portion of each test is included directly in the test itself and not in some &lt;code&gt;before each&lt;&#x2F;code&gt; or &lt;code&gt;describe&lt;&#x2F;code&gt; block or some parenting test framework concept that provides initial state setup across multiple tests.&lt;&#x2F;p&gt;
&lt;p&gt;You might be thinking to yourself well this concept goes against the DRY principle which we follow in implementation code. Shouldn&#x27;t we be following it in our tests as well? Technically it doesn&#x27;t go againts the DRY principle overall. It just goes against DRYing test setup up using framework concepts like &lt;code&gt;before each&lt;&#x2F;code&gt; and &lt;code&gt;describe&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The reason that &lt;strong&gt;Setup in Test&lt;&#x2F;strong&gt; exists as a concept is because extracting test setup into &lt;code&gt;before each&lt;&#x2F;code&gt; or &lt;code&gt;describe&lt;&#x2F;code&gt; blocks or other test framework constructs have massive negative implications when you are coming back to a test later on. They make it very difficult to understand what the exact test setup is for a particular test. You often have to go hunt to try and figure out what test setups are done earlier in the suite and even then there are likely test setup steps that aren&#x27;t needed in your particular test but exist earlier in the suite.&lt;&#x2F;p&gt;
&lt;p&gt;To get the best of both worlds, &lt;strong&gt;clarity of test setup&lt;&#x2F;strong&gt; and &lt;strong&gt;DRYing up test setup&lt;&#x2F;strong&gt; we follow the common strategy of extracting test setup into utility functions in the test suite. This enables us to have clear, concise, well named utility functions that we can use in each of the tests that clearly communicate the setup. Even in cases where the naming don&#x27;t clearly communicate the setup, it is easy enough for us to dive into any setup functions and see what is going. This is superior as there is a formal relationship and we don&#x27;t have to guess if setup is used or not.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;full-stack-integration-within-reason&quot;&gt;Full-Stack Integration within Reason&lt;&#x2F;h2&gt;
&lt;p&gt;Full-Stack integration testing is the same concept as &lt;strong&gt;integration&lt;&#x2F;strong&gt; testing from above. The difference is that it is generally at the highest level of the application and integrates through all the various layers of the application. We are big believers in this for the same reason we are &lt;strong&gt;integration&lt;&#x2F;strong&gt; testing.&lt;&#x2F;p&gt;
&lt;p&gt;However, when you are doing Full-Stack integration testing you often have to deal with things like a database or 3rd party APIs, etc. This is why we have the caveat of &quot;within Reason&quot;. Doing true Full-Stack integration testing is very difficult and not practical&#x2F;pragmatic in most cases. It often makes more sense to stub out 3rd party integrations and do some sort of datbase resetting&#x2F;transaction management, or maybe an in memory database substitution. In some cases maybe it even makes sense to start a layer lower in the architecture.&lt;&#x2F;p&gt;
&lt;p&gt;The point is that given the impracticality of doing true Full-Stack Integration Testing we instead figure out for each of the different projects we work on what we can do &quot;within reason&quot; to get as close to Full-Stack Integration as possible.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Uptech Studio Versioning Standards</title>
        <published>2021-05-01T00:00:00+00:00</published>
        <updated>2021-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/uptech-versioning/"/>
        <id>https://drewdeponte.com/blog/uptech-versioning/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/uptech-versioning/">&lt;h2 id=&quot;versioning-libraries&quot;&gt;Versioning Libraries&lt;&#x2F;h2&gt;
&lt;p&gt;We use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;semver.org&quot;&gt;Semantic Versioning&lt;&#x2F;a&gt; for our standard of choice for versioning libraries.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;versioning-apis&quot;&gt;Versioning APIs&lt;&#x2F;h2&gt;
&lt;p&gt;There are few options.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;URL based versioning, e.g. &lt;code&gt;&#x2F;api&#x2F;v1&#x2F;route&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;HTTP Header based versioning
&lt;ul&gt;
&lt;li&gt;use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;docs.github.com&#x2F;en&#x2F;rest&#x2F;overview&#x2F;media-types&quot;&gt;Media types&lt;&#x2F;a&gt;, e.g. &lt;code&gt;application&#x2F;vnd.github[.version].param[+json]&lt;&#x2F;code&gt; or &lt;code&gt;application&#x2F;vnd.github.v3+json&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;HTTP Custom Headers versioning (any header beginning with &lt;code&gt;X-&lt;&#x2F;code&gt;), e.g. &lt;code&gt;X-GitHub-Media-Type&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We prefer and will use &lt;strong&gt;HTTP Header based versioning with Media Types&lt;&#x2F;strong&gt; as it is the most robust solution that generally also has support built into libraries or frameworks.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;strong&gt;HTTP Custom Headers versioning&lt;&#x2F;strong&gt; is technically more robust as there are no standards around it. However, it then requires more custom work to do be done for clients interacting with it.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;strong&gt;URL based versioning&lt;&#x2F;strong&gt; is &lt;strong&gt;NOT&lt;&#x2F;strong&gt; robust because it requires either duplicating code, or implementing some sort proxying, etc. to deal with situations where you want to create another version of all the routes. It also makes it harder to mix them as well in terms of code management.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How we should be using Git</title>
        <published>2021-01-30T00:00:00+00:00</published>
        <updated>2021-01-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/how-we-should-be-using-git/"/>
        <id>https://drewdeponte.com/blog/how-we-should-be-using-git/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/how-we-should-be-using-git/">&lt;p&gt;Git was created by Linus Torvalds out of a need. At the time the Linux Kernel team was using a proprietary Distributed Source Control Management (DSCM) system. However, due to licensing issues the Linux Kernel team could no longer use this proprietary DSCM system. Therefore, Linus decided to build Git as the DSCM system he always wished they had.&lt;&#x2F;p&gt;
&lt;p&gt;You might also know Linus as the creator of Linux. In fact, Linus still manages the Linux Kernel today. As of 2020, the Linux kernel had over 27.8 million lines of code spread across ~66 thousand files from ~21 thousand different contributors. It has continued to be successfully developed, maintained, and extended since it was publicly announced in 1991. It is also worth noting that Git itself, another large, successful open source project, is managed in the same way.&lt;&#x2F;p&gt;
&lt;p&gt;So there must be some useful insights around long term software development and maintenance practices we can glean by looking at how Linus and his team use Git for their development and peer review workflows.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-the-linux-kernel-team-works&quot;&gt;How the Linux Kernel Team works?&lt;&#x2F;h2&gt;
&lt;p&gt;It may sound crazy but it turns out that the Linux Kernel and Git teams use email for both their code review process and their code submission process. They use a concept from the Unix days called a patch.&lt;&#x2F;p&gt;
&lt;p&gt;A patch is a simple text file that describes a change to another text file&#x27;s content. In Unix there exists a tool called &lt;strong&gt;diff&lt;&#x2F;strong&gt; that takes two files and produces a patch file. People often refer to these patch files as &lt;em&gt;diffs&lt;&#x2F;em&gt;. Another Unix tool called &lt;strong&gt;patch&lt;&#x2F;strong&gt; takes a patch file and applies it to another file.&lt;&#x2F;p&gt;
&lt;p&gt;Back in the day this Unix patch concept is actually how open source development was done. The contributor would make a change to some source code, produce a patch, and email that patch to the maintainers requesting feedback. The contributor would then take the feedback and make the adjustments to the code. Then they would produce a new patch and email it back to the maintainers for further review and possible integration.&lt;&#x2F;p&gt;
&lt;p&gt;Fundamentally this is how peer review is done with the Linux Kernel and Git teams today. The primary difference is that they use Git to manage changes locally and then use a number of Git commands to generate a patch or a sequences of patches and email them to the maintainers. They also use a number of Git commands to consume and apply patches from emails. See &lt;code&gt;git apply&lt;&#x2F;code&gt;, &lt;code&gt;git am&lt;&#x2F;code&gt;, &lt;code&gt;git format-patch&lt;&#x2F;code&gt;, &lt;code&gt;git imap-send&lt;&#x2F;code&gt;, and &lt;code&gt;git send-email&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In addition the team also requires that patches have certain characteristics.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a patch must be &lt;strong&gt;small&lt;&#x2F;strong&gt;, &lt;strong&gt;logical&lt;&#x2F;strong&gt;, &lt;strong&gt;independent&lt;&#x2F;strong&gt;, &lt;strong&gt;buildable&lt;&#x2F;strong&gt;, &amp;amp; &lt;strong&gt;testable&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;a patch must provide a clear description of what changed, why it was changed, and the necessary context of how it is or will be used&lt;&#x2F;li&gt;
&lt;li&gt;patches must be submitted individually for review&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If we dig a bit further into the Linux Kernel team&#x27;s process we find that they have integrators responsible for the various subsystems. These integrators receive numerous patches from various contributors and manage them locally as a series of patches (using &lt;strong&gt;quilt&lt;&#x2F;strong&gt;, another Unix command). This involves reordering, updating and dropping them on a regular basis. Linus then regularly pulls the changes from the various subsystem integrators into the upstream repository&#x27;s mainline.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-did-we-learn&quot;&gt;What did we learn?&lt;&#x2F;h2&gt;
&lt;p&gt;From a small dive into the Linux Kernel team&#x27;s development process we can make three important observations.&lt;&#x2F;p&gt;
&lt;p&gt;First, the process imposes a strict set of requirements for each patch before it may be sent for review or submission. Second, the team&#x27;s process works well over email, a very asynchronous communication mechanism. Finally, they locally use the concept of managing a series of patches while preparing changes for integration into upstream.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;so-what-s-the-magic&quot;&gt;So what&#x27;s the Magic?&lt;&#x2F;h2&gt;
&lt;p&gt;Is it the Kernel team&#x27;s avoidance of powerful peer review tools that makes them so successful? Or the fact that they do this all over email?&lt;&#x2F;p&gt;
&lt;p&gt;I think not. I believe their success is primarily due to their process. The specific requirements for patches are fundamentally in alignment with the core design principles of Git. They are also structured around the concepts of boundaries of the application architecture.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, it seems this mental model of locally managing a series of patches as they are prepared to be submitted for review or submission is key.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;outside-in&quot;&gt;Outside-In&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s assume for the time being I am correct and we trust that following these rules and this mental model will greatly benefit us. (Later we can explore the actual values we get from these rules and why they are so important.) How can we use this to benefit our own projects?&lt;&#x2F;p&gt;
&lt;p&gt;Before we can apply these rules we need to first understand how to break down our code changes into small logical independent chunks that are buildable and testable. To help us with this, let&#x27;s introduce a new mental model for thinking about application architecture in relation to boundaries, called &lt;em&gt;Outside-In&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;With Outside-In you begin your approach to code changes by starting from the outermost (UI&#x2F;UX) layer of the architecture, and drive layer-by-layer down into the architecture until you reach your core dependency, the inner most layer of the relevant architecture; you then reverse direction and work your way out again, wiring the layers together as you go.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;how-we-should-be-using-git&#x2F;outside-in.gif&quot; alt=&quot;Animation showing Outside-In development&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This method ensures that you are building exactly what you need-nothing more, nothing less. It also helps as a tool to recoognize different layers of abstraction within your application which aids massively in thinking about the overall application architecture. Last, it also drives the interfaces of your abstracitons so you end up with more clearly defined boundaries.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;sounds-great-in-theory&quot;&gt;Sounds great in theory&lt;&#x2F;h2&gt;
&lt;p&gt;But what does this actually look like?&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s say we are tasked with adding the ability to login to our mobile app. If we follow Outside-In this might look something like the following series of steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;add login view (incomplete because depends on a API client that doesn&#x27;t exist)&lt;&#x2F;li&gt;
&lt;li&gt;add login support to API client (incomplete because depends on REST API lib)&lt;&#x2F;li&gt;
&lt;li&gt;add lib to facilitate making REST API requests (our core dependency)&lt;&#x2F;li&gt;
&lt;li&gt;complete add login support to API client (wiring it up to the lib added in the prev step)&lt;&#x2F;li&gt;
&lt;li&gt;complete add login view (wiring it up to the API client login ability added in the prev step)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;If we created commits locally for each of these steps our local commit tree would look like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* complete add login view (HEAD, main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* complete add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* add lib to facilitate making REST API requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* WIP: add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* WIP: add login view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* ... (origin&#x2F;main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is fine, but these don&#x27;t look like logically chunked commits. They are also in the incorrect order based on dependencies.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily we are working in Git, which provides the interactive rebase (&lt;code&gt;git rebase -i&lt;&#x2F;code&gt;) command which facilitate reordering and squashing commits together, amongst other valuable things.&lt;&#x2F;p&gt;
&lt;p&gt;Before we fix these issues, let&#x27;s just look at what the tree would look like if we reordered it based on dependencies and didn&#x27;t squash the commits.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* WIP: add login view (HEAD, main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* complete add login view&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* WIP: add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* complete add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* add lib to facilitate making REST API requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* ... (origin&#x2F;main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From this ordering we can start to actually see the relation and the logical chunking. For example the &quot;WIP: add login view&quot; and the &quot;complete add login view&quot; are two commits that are part of the same logical chunk.&lt;&#x2F;p&gt;
&lt;p&gt;If we identify these commits and squash them together into their respective logical chunks we would end up with a local Git tree that looks as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* add login view (HEAD, main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* add login support to API client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* add lib to facilitate making REST API requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;* ... (origin&#x2F;main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Kernel team describes a series of patches as a &quot;proof of work&quot;. Think back to when you were a kid in school and your teacher required you show how you got to a solution for each problem. This concept is effectively the same thing. Each logical patch in the series is a step of you showing how you are solving the problem. This is a another great mental model and is useful for making sure your series of patches make sense.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-are-we-with-these-rules&quot;&gt;Where are we with these rules?&lt;&#x2F;h2&gt;
&lt;p&gt;At this point we have figured out how to locally iterate on commits to get them to a point where they effectively are a series of &lt;strong&gt;small&lt;&#x2F;strong&gt;, &lt;strong&gt;logical&lt;&#x2F;strong&gt;, &lt;strong&gt;independent&lt;&#x2F;strong&gt;, &lt;strong&gt;buildable&lt;&#x2F;strong&gt;, and &lt;strong&gt;testable&lt;&#x2F;strong&gt; patches.&lt;&#x2F;p&gt;
&lt;p&gt;That leaves us with the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a patch must provide clear description of what changed, why it was changed, and the necessary context of how it is or will be used&lt;&#x2F;li&gt;
&lt;li&gt;patches must be submitted individually for review&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Meeting the first of these is simply writing a good commit message. Check!&lt;&#x2F;p&gt;
&lt;p&gt;But how do we follow the second requirement to submit patches individually?&lt;&#x2F;p&gt;
&lt;h2 id=&quot;submit-for-review-or-integration&quot;&gt;Submit for Review or Integration&lt;&#x2F;h2&gt;
&lt;p&gt;We could, of course, setup a mailing list like the Linux Kernel team and use the same Git commands they do. However, this seems archaic when we have tools like GitHub, Bitbucket, Gitlab, etc. that provide the concept of a Pull Request, as well as code review tools that are much nicer than email. Not to mention the fact that the majority of the development community is already comfortable with these tools due to the unjust popularity of Feature Branch development.&lt;&#x2F;p&gt;
&lt;p&gt;So how do we create a pull request of an individual patch once it is ready for review?&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;create a branch based on the current branch&#x27;s upstream remote branch (e.g. &lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;cherry pick the patch you want reviewed to this new branch&lt;&#x2F;li&gt;
&lt;li&gt;push this branch up to the remote (e.g. &lt;code&gt;origin&#x2F;this-patches-branch&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;create a pull request from this new branch (&lt;code&gt;origin&#x2F;this-patches-branch&lt;&#x2F;code&gt;) into upstream mainline (&lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Now reviewers can review the changes as they normally would. They will have a clear description of what changed, why it was changed, and the necessary context of how it is or will be used, and will be able to easily review the actual code, testing them out, and providing feedback.&lt;&#x2F;p&gt;
&lt;p&gt;A little later we will introduce a tool that automates these steps for you, making this quick and easy.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;so-what-s-the-point&quot;&gt;So What&#x27;s the point?&lt;&#x2F;h2&gt;
&lt;p&gt;Interestingly, it turns out that structuring your patches (a.k.a. commits) logically around the concepts in your application architecture is a major part of the magic. This specifically aids with understanding concepts, how they are introduced, and how they are modified over time to support higher level concepts and features. This is what largely facilitates &lt;strong&gt;long term maintenance of software&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This method also facilitates &lt;strong&gt;requesting review for individual patches as soon as they are completed&lt;&#x2F;strong&gt;. I can&#x27;t emphasize how important this is. This enables us to basically develop Outside-In but request review Inside-Out. Meaning as soon as the inner most dependency is complete we can request review of that and get feedback all while we are still working on the layers above it.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that these small logical, buildable, testable patches result in &lt;strong&gt;a faster mean time to repair&lt;&#x2F;strong&gt;, &lt;strong&gt;extremely focused and valuable reviews&lt;&#x2F;strong&gt;, &lt;strong&gt;support for fault isolation&lt;&#x2F;strong&gt;, &lt;strong&gt;decreased code review time&lt;&#x2F;strong&gt;, and &lt;strong&gt;promote test reliability&lt;&#x2F;strong&gt;. They also facilitate &lt;strong&gt;integrating patches sooner&lt;&#x2F;strong&gt;, which in turn &lt;strong&gt;promotes sharing&lt;&#x2F;strong&gt;, &lt;strong&gt;refactoring&lt;&#x2F;strong&gt;, &lt;strong&gt;discovery&lt;&#x2F;strong&gt;, and &lt;strong&gt;natural evolution&lt;&#x2F;strong&gt; of application architecture concepts. Not to mention helping to &lt;strong&gt;prevent duplicate efforts&lt;&#x2F;strong&gt; and &lt;strong&gt;improve the overall release rate&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Again these small logical, buildable, testable patches fall in line with Git&#x27;s principles of design and in turn help to &lt;strong&gt;unlock the full powers of Git&lt;&#x2F;strong&gt;. Specifically in Git there are certain extremely powerful commands (e.g. &lt;code&gt;git bisect&lt;&#x2F;code&gt;) that only function well if your Git tree is composed of logical, buildable, testable commits.&lt;&#x2F;p&gt;
&lt;p&gt;The concept of a &lt;strong&gt;series of patches&lt;&#x2F;strong&gt; also ends up having a huge benefit of &lt;strong&gt;eliminating urgency around having one&#x27;s pull requests reviewed immediately&lt;&#x2F;strong&gt;. This is because even after you have submitted a patch for review, you still have that patch in your series of patches locally and can continue building on it without issue. This significantly aids in reducing interruptions between developers, breaking their focus, and inevitably making things take longer. This can&#x27;t be obtained using feature branches without huge overhead and it is a key differentiator in supporting asynchronous workflows.&lt;&#x2F;p&gt;
&lt;p&gt;How do you make sure people are aware of new pull requests without interrupting them? Don&#x27;t worry-this is a problem that all pre-review based development methodologies suffer from. To help address this issue we built &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pullwalla&lt;&#x2F;a&gt;, a unified pull request manager.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, following these rules also results in your Git commits and in turn your Git tree representing &quot;proofs of work&quot;, the mental construct the Kernel team uses to vet a series of patches. Turns out these &quot;proofs of work&quot; provide an immense amount of guidance and value in simply understanding a code base&#x27;s application architecture and the intentions behind the various logical changes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;patch-stack&quot;&gt;Patch Stack&lt;&#x2F;h2&gt;
&lt;p&gt;Given that we have found this development methodology to be unmatched in value, we decided we must formalize it a bit more. We decided to call this the &lt;strong&gt;Patch Stack&lt;&#x2F;strong&gt; methodology, as it resembles a stack of papers that can be reordered and modified.&lt;&#x2F;p&gt;
&lt;p&gt;Achieving the full value of the methodology requires that these rules are followed and that you locally manage your commits as if they are conceptually a stack of patches being reordered and modified in preparation for submitting for review or integration.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a patch must be &lt;strong&gt;small&lt;&#x2F;strong&gt;, &lt;strong&gt;logical&lt;&#x2F;strong&gt;, &lt;strong&gt;independent&lt;&#x2F;strong&gt;, &lt;strong&gt;buildable&lt;&#x2F;strong&gt;, &amp;amp; &lt;strong&gt;testable&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;a patch must provide a clear description of what changed, why it was changed, and the necessary context of how it is or will be used&lt;&#x2F;li&gt;
&lt;li&gt;patches must be submitted individually for review&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In addition to formally defining the rules, we have built &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&quot;&gt;git-ps-rs&lt;&#x2F;a&gt;, an OSS Git command line extension to facilitate making this workflow and methodology even easier to use.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-the-feel-for-it&quot;&gt;Getting the Feel for It&lt;&#x2F;h2&gt;
&lt;p&gt;To get a better feel for how this methodology works in real life let&#x27;s walk through our example from before. If you recall we are tasked with adding Login ability to a mobile app.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;where-do-we-start&quot;&gt;Where do we start?&lt;&#x2F;h3&gt;
&lt;p&gt;We take guidance from Outside-In and start at the outer most layer of our application architecture (UI&#x2F;UX). We first look at the existing UI layer of the application architecture to find out if it provides any support for login.&lt;&#x2F;p&gt;
&lt;p&gt;Turns out it doesn&#x27;t. So we are off to the races, building out a login screen and adding it to the flow of the app. We get to the point where we are attempting to wire up the submit button of the login screen and realize our client API for our backend doesn&#x27;t support login.&lt;&#x2F;p&gt;
&lt;p&gt;So we figure out the ideal interface that should get added to the our client API to facilitate login. We also implement code to use this imaginary interface. This code obviously won&#x27;t build and isn&#x27;t complete, but we include it anyways as it acts as a note to ourselves for what the ideal interface should be.&lt;&#x2F;p&gt;
&lt;p&gt;Given we are following Outside-In we also recognize that we are at a boundary between application architecture concepts, specifically the UI and the client API. This is our clue that we need a patch to house this logical (UI) piece of the puzzle.&lt;&#x2F;p&gt;
&lt;p&gt;So we add a patch on top of our stack by first staging the UI changes, &lt;code&gt;gps add .&lt;&#x2F;code&gt;, and then creating the patch.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps create-patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is an alias of &lt;code&gt;gps c&lt;&#x2F;code&gt; for short as this operation is so common.&lt;&#x2F;p&gt;
&lt;p&gt;When it prompts for the commit message we provide something like the following, making sure to provide a clear description of what changed, why it was changed, and the necessary context of how it is or will be used.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that users will be able to login to their account.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This interfaces with the client API to actually perform the login and get the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;authentication token.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We used the convention of prefixing our commit summary with &quot;WIP:&quot; as a reminder to us that this patch is still a Work In Progress.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;onto-the-client-api&quot;&gt;Onto the Client API&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we have created our WIP patch for the UI layer. We move onto to the next layer down, the client API.&lt;&#x2F;p&gt;
&lt;p&gt;So we extend the client API by adding our ideal interface and starting to implement the functionality behind it, making any necessary adjustments to the interface as we go.&lt;&#x2F;p&gt;
&lt;p&gt;Soon we realize that we don&#x27;t have a library to facilitate interacting with the REST API. We also recognize this as yet another boundary in the application architecture. Therefore, we create another patch on top of our stack by staging the changes, &lt;code&gt;gps add .&lt;&#x2F;code&gt; and then committing.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps create-patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We provide the following message with the patch.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that our application has the ability to make the login request to the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Backend REST API given the username and password.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;This is intended to be used by the login screen to help facilitate performing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the actual login. It will be interfacing with some REST API to actually make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;the REST call.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;what-s-our-patch-stack-look-like&quot;&gt;What&#x27;s our Patch Stack look like?&lt;&#x2F;h3&gt;
&lt;p&gt;We have added a couple patches to our Patch Stack and are ready to check where we are in our process. To do this we simply list our patch stack using the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An alias for this command is provided as well, &lt;code&gt;gps ls&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It outputs a view of all the patches on our stack.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Things look good and we are reminded that we just added the &lt;code&gt;BackendClient.login()&lt;&#x2F;code&gt; method and it is incomplete because of a missing dependency, the REST API library.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;onto-the-rest-api-library&quot;&gt;Onto the REST API library&lt;&#x2F;h3&gt;
&lt;p&gt;So we do some research and find what we think is the best REST API library and add it to our &lt;code&gt;Package.swift&lt;&#x2F;code&gt;, making it available to our app.&lt;&#x2F;p&gt;
&lt;p&gt;This is yet another boundary in our application architecture and therefore we create a new logical patch for it by staging the changes, &lt;code&gt;gps add .&lt;&#x2F;code&gt;, and committing.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps create-patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the following message:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that we can easily and most importantly make elegant REST requests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;We intend to use this inside of our BackendClient.login(username:password:)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;method to elegantly make the login REST API request.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It is worth noting that we do &lt;strong&gt;not&lt;&#x2F;strong&gt; use the &quot;WIP:&quot; prefix in our patch summary here. This is because it is a complete independent logical patch and happens to also be our core dependency in the context of Outside-In.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;where-is-our-stack-at&quot;&gt;Where is our Stack at?&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s check out our stack of patches now.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It outputs the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;reorder-our-patches-by-dependency&quot;&gt;Reorder our Patches by Dependency&lt;&#x2F;h3&gt;
&lt;p&gt;Things are looking pretty good but our patches are not ordered correctly based on dependencies. Let&#x27;s fix this by reordering them using &lt;code&gt;gps rebase&lt;&#x2F;code&gt; and changing them into the following order.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This order is correctly ordered by dependency, as &quot;Add Siesta...&quot; is the inner most core dependency, followed by &quot;WIP: Add BackendClient.login...&quot; being the layer that directly depends on &quot;Add Siesta...&quot;. Following that is the &quot;WIP: Add login screen&quot; patch which depends on &quot;WIP: Add BackendClient.login...&quot;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;pull-changes-from-upstream&quot;&gt;Pull Changes from Upstream&lt;&#x2F;h3&gt;
&lt;p&gt;At this point we have a logical, buildable, testable patch that is ready to be submitted for review. However, lets make sure that our patch stack is good with all the other work people have recently published to upstream. We do this as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps pull&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This takes the stack of patches and essentially lifts them up and replays them on top of the upstream changes.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;gps pull&lt;&#x2F;code&gt; ran successfully with no conflicts. So all the patches in our stack are good.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0     4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;request-review&quot;&gt;Request Review&lt;&#x2F;h3&gt;
&lt;p&gt;We now request review of our &quot;Add Siesta...&quot; patch as it is a complete logical patch and we want people to be able to review it while we are working on implementing the rest of our feature.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps request-review 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;An alias for this command is provided as well, &lt;code&gt;gps rr &amp;lt;patch-index&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For this example lets assume that we are using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt; and have installed the &lt;code&gt;request_review_post_sync&lt;&#x2F;code&gt; hook that integrates with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In the case where we initially request review of a patch it creates a pull request for us on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Getting feedback on this inner most dependency first is important as the architectural decisions around it can impact the work in the layers above.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;back-to-the-client-api&quot;&gt;Back to the Client API&lt;&#x2F;h3&gt;
&lt;p&gt;One of the benefits of working in a stack of patches is that we can continue building on top of our previous patches even after we have requested review of them.&lt;&#x2F;p&gt;
&lt;p&gt;Now that we have the Siesta library available to us, we go back to our &lt;code&gt;BackendClient.login(username:password:)&lt;&#x2F;code&gt; method and finish implementing it using the Siesta library.&lt;&#x2F;p&gt;
&lt;p&gt;Once we are done we create a new patch on our stack with the message, &quot;finish BackendClient.login(username:password:)&quot;, using &lt;code&gt;gps add&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;gps create-patch&lt;&#x2F;code&gt;. &lt;em&gt;Note&lt;&#x2F;em&gt;: We don&#x27;t care so much about this patch message as it is a temporary patch. We just need to know what it does in relation to the other patches in our stack.&lt;&#x2F;p&gt;
&lt;p&gt;If we checkout our stack of patches with &lt;code&gt;gps list&lt;&#x2F;code&gt; it looks something like this now.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  3     df71da finish BackendClient.login(username:password:)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr  4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;reorder-squash&quot;&gt;Reorder &amp;amp; Squash&lt;&#x2F;h3&gt;
&lt;p&gt;Looks like we have the makings of another logical patch. However, it is made up of two separate patches, the &quot;WIP: Add BackendClient.login...&quot; patch and the &quot;finish BackendClient.login...&quot; patch.&lt;&#x2F;p&gt;
&lt;p&gt;Lets reorder these patches and squash them together using &lt;code&gt;gps rebase&lt;&#x2F;code&gt; to turn them into a single logical patch.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 23d7a6 WIP: Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;s df71da finish BackendClient.login(username:password:)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When we save and quit the editor it will open the squashed patch descriptions up to create the singular patch message. We remove the temporary patch message and remove the &quot;WIP:&quot; prefix from the summary as this is now a complete, buildable, testable, logical patch.&lt;&#x2F;p&gt;
&lt;p&gt;If we list our patches with &lt;code&gt;gps list&lt;&#x2F;code&gt; again. Our patch stack now looks as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr+ 4387d1 Add Siesta, the elegant way to write REST clients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;review-feedback&quot;&gt;Review Feedback&lt;&#x2F;h3&gt;
&lt;p&gt;We just got a notification that someone reviewed our first patch and requested some changes. Instead of using &lt;em&gt;Siesta&lt;&#x2F;em&gt; as our REST library they want to use &lt;em&gt;Alamofire&lt;&#x2F;em&gt; and have some decent arguments for doing so.&lt;&#x2F;p&gt;
&lt;p&gt;So looking at our stack of patches we need to edit the &quot;Add Siesta...&quot; patch to change it to Alamofire.&lt;&#x2F;p&gt;
&lt;p&gt;We can accomplish this by using &lt;code&gt;gps rebase&lt;&#x2F;code&gt; and changing the &quot;Add Siesta...&quot; patches rebase command from &lt;code&gt;pick&lt;&#x2F;code&gt; to &lt;code&gt;edit&lt;&#x2F;code&gt;. When we save and quit the editor it will drop us into being able to edit the patch we marked with &lt;code&gt;edit&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So we make the necessary changes, removing Siesta from the &lt;code&gt;Package.swift&lt;&#x2F;code&gt; and adding Alamofire.&lt;&#x2F;p&gt;
&lt;p&gt;We then stage these changes with &lt;code&gt;gps add .&lt;&#x2F;code&gt; and amend them to the &quot;Add Siesta...&quot; patch using &lt;code&gt;gps amend-patch&lt;&#x2F;code&gt;. This in turn opens our editor with the patch message allowing us to update it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Add Alamofire as a REST client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;So that we can easily make REST requests.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;We intend to use this inside of our BackendClient.login(username:password:)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;method to make the login REST API request.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once we have saved and quit the editor the patch has been updated. However, we still need to complete the rebase which stopped in the middle.&lt;&#x2F;p&gt;
&lt;p&gt;To do this we simply run &lt;code&gt;gps rebase --continue&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;re-request-review&quot;&gt;Re-Request Review&lt;&#x2F;h3&gt;
&lt;p&gt;If we checkout our patch stack it should look something like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr+ 4387d1 Add Alamofire as a REST client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;rr+&lt;&#x2F;code&gt; is indicating that there have been changes made to that patch since we last requested review of it. So we need to re-request review so that the reviewer can see the recent changes we have made.&lt;&#x2F;p&gt;
&lt;p&gt;We accomplish this by simply running &lt;code&gt;gps request-review 0&lt;&#x2F;code&gt; again.&lt;&#x2F;p&gt;
&lt;p&gt;This will update the previously created pull request for this patch so that the reviewer and can re-review it.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;rework-backendclient&quot;&gt;Rework BackendClient&lt;&#x2F;h3&gt;
&lt;p&gt;Now that our core dependency is ready for review again we can focus on the layer above that again. Since our lower layer dependency changed we need to update our &quot;Add BackendClient.login...&quot; patch to use Alamofire instead of Siesta.&lt;&#x2F;p&gt;
&lt;p&gt;To do this we simply use &lt;code&gt;gps rebase&lt;&#x2F;code&gt; again and mark the &quot;Add BackendClient.login...&quot; patch for &lt;code&gt;edit&lt;&#x2F;code&gt;. It drops us back to the console waiting for us to edit that patch.&lt;&#x2F;p&gt;
&lt;p&gt;We do so by making the necessary changes, staging them with &lt;code&gt;gps add .&lt;&#x2F;code&gt;, and then amending them with &lt;code&gt;gps amend-patch&lt;&#x2F;code&gt;. When prompted to the update the message we simply save and quit the editor because the message is still correct.&lt;&#x2F;p&gt;
&lt;p&gt;Then we run &lt;code&gt;gps rebase --continue&lt;&#x2F;code&gt; to have it finish the rebase process.&lt;&#x2F;p&gt;
&lt;p&gt;Leaving our patch stack as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr+ 4387d1 Add Alamofire as a REST client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;request-review-of-the-2nd-patch&quot;&gt;Request Review of the 2nd patch&lt;&#x2F;h3&gt;
&lt;p&gt;Now that we have our second patch complete. We pull the upstream changes again with &lt;code&gt;gps pull&lt;&#x2F;code&gt; and then request review of our second patch with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps request-review 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Creating a pull request and leaving our stack of patches in the following state.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1 rr  23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr+ 4387d1 Add Alamofire as a REST client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;approval-arrives&quot;&gt;Approval Arrives&lt;&#x2F;h3&gt;
&lt;p&gt;Meanwhile the approval notice has come in for our &quot;Add Alamofire...&quot; patch.&lt;&#x2F;p&gt;
&lt;p&gt;So we integrate this patch upstream by running the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps integrate 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is an alias for this command as well, &lt;code&gt;gps int &amp;lt;patch-index&amp;gt;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This will push that patch up to the remote branch leaving our stack of patches in the following state.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  2     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1 rr  23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 int 4387d1 Add Alamofire as a REST client&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;pull-and-collapse&quot;&gt;Pull and Collapse&lt;&#x2F;h3&gt;
&lt;p&gt;We decided to pull in any changes from upstream with &lt;code&gt;gps pull&lt;&#x2F;code&gt; making our patch stack now look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     af73d2 WIP: Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr  23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will notice that the &quot;Add Alamofire...&quot; patch has left our patch stack. This is because it has conceptually moved from our stack of patches into its upstream branch.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;back-to-the-ui&quot;&gt;Back to the UI&lt;&#x2F;h3&gt;
&lt;p&gt;We have now worked our way back up to the outer most layer of our application architecture, the UI. Here we make changes to wire the submit button of the Login screen up to the &lt;code&gt;BackendClient.login(username:password:)&lt;&#x2F;code&gt; method completing this feature.&lt;&#x2F;p&gt;
&lt;p&gt;Since our &quot;WIP: Add login screen&quot; patch is the top most patch. We can simply amend these changes to that patch by staging the changes with &lt;code&gt;gps add .&lt;&#x2F;code&gt; and doing the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gps amend-patch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This opens the patch message in our editor and allows us to remove the &quot;WIP:&quot; prefix from the patch summary.&lt;&#x2F;p&gt;
&lt;p&gt;If we list our patch stack with &lt;code&gt;gps list&lt;&#x2F;code&gt; it should look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1     af73d2 Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr  23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then we integrate upstream changes with &lt;code&gt;gps pull&lt;&#x2F;code&gt; and request review of our final patch using &lt;code&gt;gps request-review 1&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Leaving our patch stack in the following state.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1 rr  af73d2 Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 rr+ 23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;onto-the-next&quot;&gt;Onto the Next&lt;&#x2F;h3&gt;
&lt;p&gt;At this point we have requested review of all our patches for this feature and are waiting for feedback. However, we don&#x27;t just sit idle, waiting for the feedback. We naturally start our next task in the same manner, Outside-In, and adding, reording, and updating patches on top of our stack.&lt;&#x2F;p&gt;
&lt;p&gt;You might be saying to yourself, &quot;Hey, but we have this other feature&#x27;s patches here.&quot; You are correct we do. This is fine and in lots of cases it is actually more beneficial to continue building new features on top of the ones you have locally. And if for some reason you find out that this new feature has priority over the one that was just completed. Simply reorder the patches in your stack to represent that.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;more-acceptance&quot;&gt;More Acceptance&lt;&#x2F;h3&gt;
&lt;p&gt;Over the next couple hours reviewers find time to review the other two patches and they are both approved.&lt;&#x2F;p&gt;
&lt;p&gt;We integrate them using &lt;code&gt;gps integrate 0&lt;&#x2F;code&gt; and &lt;code&gt;gps integrate 1&lt;&#x2F;code&gt; changing our patch stack state to the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  1 int af73d2 Add login screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  0 int 23d7a6 Add BackendClient.login(username:password:) method&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After integrating these patches we run &lt;code&gt;gps pull&lt;&#x2F;code&gt; to integrate any upstream changes. In this case it includes the two patches we just published. So when we run &lt;code&gt;gps list&lt;&#x2F;code&gt; now we see an empty patch stack.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;feature-complete&quot;&gt;Feature Complete&lt;&#x2F;h3&gt;
&lt;p&gt;At this point our feature has been developed, reviewed, and integrated. We are done with this task and can now move on to the next task.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;it-is-just-git&quot;&gt;It is just Git&lt;&#x2F;h2&gt;
&lt;p&gt;Fundamentally &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&quot;&gt;git-ps-rs&lt;&#x2F;a&gt; is just a light layer of automation of underlying Git commands. So it is &lt;strong&gt;very important&lt;&#x2F;strong&gt; to know Git. Especially in relation to this idea of iterating on your patches to a point where they are ready for review.&lt;&#x2F;p&gt;
&lt;p&gt;If we just look at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-rebase&quot;&gt;interactive rebases&lt;&#x2F;a&gt; in Git we see that there are many things you can do within an interactive rebase. For example you can squash commits, fixup commits, edit commits, reorder commits, reword commit descriptions, and many more. Also there are other Git commands that can aid in this evolution of your patches. For example &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-add-patch-wont-split&#x2F;&quot;&gt;&lt;code&gt;git add -p&lt;&#x2F;code&gt;&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;docs&#x2F;git-commit&quot;&gt;&lt;code&gt;git commit --amend&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;. We have provided some commands to help with these, &lt;code&gt;gps add -p&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;gps amend-patch&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, it is worth understanding how you can use these tools to do things like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;git-splitting-commits&#x2F;&quot;&gt;Split Commits Up&lt;&#x2F;a&gt;. Please take the time to make sure you understand these Git commands and how to use them. It will not only improve your workflow within this methodology but with using Git in general.&lt;&#x2F;p&gt;
&lt;p&gt;And remember, this is just Git. If we ever run into situations where we need to step outside this methodology-say, to use a branch-there is nothing preventing us from doing so. In fact &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps-rs&quot;&gt;git-ps-rs&lt;&#x2F;a&gt; sees any branch with a tracked upstream branch as a patch stack. So you can think of branches as separate stacks of patches.&lt;&#x2F;p&gt;
&lt;p&gt;We have found this flexibility to be useful when working with clients that don&#x27;t follow the Patch Stack methodology. It enables us to still follow the practices of Patch Stack locally despite our client using a different methodology, e.g. Feature Branch development. This enables us to get at least some of the beneficial values of the Patch Stack methodology while still playing nice with others.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pullwalla - A New Era</title>
        <published>2021-01-20T00:00:00+00:00</published>
        <updated>2021-01-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pullwalla-a-new-era/"/>
        <id>https://drewdeponte.com/blog/pullwalla-a-new-era/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pullwalla-a-new-era/">&lt;p&gt;Woot woot! The first couple releases of the year are out 🎉. These releases include major features as well as important bug fixes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ios&quot;&gt;iOS&lt;&#x2F;h2&gt;
&lt;p&gt;Pullwalla iOS has always helped you &lt;strong&gt;discover&lt;&#x2F;strong&gt; and &lt;strong&gt;examine&lt;&#x2F;strong&gt; pull requests you want to review across all your accounts &amp;amp; repositories.&lt;&#x2F;p&gt;
&lt;p&gt;This release marks the beginning of a new era where Pullwalla begins to achieve it&#x27;s true vision as &lt;strong&gt;the primary interface for Pull Request Management&lt;&#x2F;strong&gt;, regardless of platform or repository strategy.&lt;&#x2F;p&gt;
&lt;p&gt;One of the big pieces of the &lt;strong&gt;review&lt;&#x2F;strong&gt; and &lt;strong&gt;approve&lt;&#x2F;strong&gt; puzzle that was missing was the new Pull Request Diffs view. With Pullwalla iOS &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;&quot;&gt;v1.5.0&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;&quot;&gt;v1.5.1&lt;&#x2F;a&gt; you can now access it via the &quot;File Changes&quot; button on the Pull Request Details view. Below is a screenshot in it&#x27;s beautiful dark mode theme.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;files.pullwalla.com&#x2F;pullwalla-diffs-view-iphone-dark-mode@2x.png&quot; alt=&quot;Pullwalla iPhone Diffs View Dark Mode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This view presents all of the diffs associated with the given pull request and their associated hunks in horizontally scrollable panes. Letting you &lt;strong&gt;review&lt;&#x2F;strong&gt; every last change.&lt;&#x2F;p&gt;
&lt;p&gt;The Pull Request Diffs view also looks great in light mode.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;files.pullwalla.com&#x2F;pullwalla-diffs-view-ipad-light-mode@2x.png&quot; alt=&quot;Pullwalla iPad Diffs View Light Mode&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bug-fixes&quot;&gt;Bug Fixes&lt;&#x2F;h2&gt;
&lt;p&gt;In addition to bringing Pullwalla iOS into a state where it completes the natural chain of &lt;strong&gt;discover&lt;&#x2F;strong&gt;, &lt;strong&gt;examine&lt;&#x2F;strong&gt;, &lt;strong&gt;review&lt;&#x2F;strong&gt;, &lt;strong&gt;discuss&lt;&#x2F;strong&gt;, and &lt;strong&gt;approve&lt;&#x2F;strong&gt;, these releases also include a number of critical bug fixes to further stabilize support for Bitbucket Server in both Pullwalla iOS and macOS.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to see the nitty gritty details, check out the Pullwalla &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;&quot;&gt;iOS Changelog&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog&#x2F;&quot;&gt;macOS Changelog&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;developer-notes&quot;&gt;Developer Notes&lt;&#x2F;h3&gt;
&lt;p&gt;In this new era we are continuing our work to add support for other platforms (e.g. GitHub Enterprise), extend functionality to facilitate the peer review process, and bridge the gap between Pullwalla iOS &amp;amp; macOS with the use of shared &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;xcode&#x2F;swiftui&#x2F;&quot;&gt;SwiftUI&lt;&#x2F;a&gt; components, like our new Pull Request Diffs view.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thoughts-or-suggestions&quot;&gt;Thoughts or suggestions?&lt;&#x2F;h3&gt;
&lt;p&gt;As always, we’d love to hear from you.&lt;&#x2F;p&gt;
&lt;p&gt;Cheers,
The Pullwalla Team&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>git add -p won&#x27;t split</title>
        <published>2021-01-19T00:00:00+00:00</published>
        <updated>2021-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-add-patch-wont-split/"/>
        <id>https://drewdeponte.com/blog/git-add-patch-wont-split/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-add-patch-wont-split/">&lt;p&gt;It is amazing how many developers I run into that don&#x27;t seem to either know
about &lt;code&gt;git add -p&lt;&#x2F;code&gt; (a.k.a. git add patch), and ever fewer that know what to do
when &lt;code&gt;git add -p&lt;&#x2F;code&gt; won&#x27;t let you split your hunks up any further. Given how much
I use this command in my workflow to facilitate creating logically chunked,
buildable commits I figured I might as well make a post just touching on it.&lt;&#x2F;p&gt;
&lt;p&gt;Yes, this is something that less keyboard driven developers often ignore as
they use a GUI (ex: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt;) to stage things at a smaller
granularity. To be completely honest I use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sublimemerge.com&quot;&gt;Sublime Merge&lt;&#x2F;a&gt; to stage changes
myself sometimes. However, there are a large number of times where I am already
working on the command line with &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; and therefore it is quicker and easier
just to stay on the keyboard and use &lt;code&gt;git add -p&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So lets break things down a bit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;git-add&quot;&gt;git add&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;git add&lt;&#x2F;code&gt; is a command that allows you to take local changes and move them to
the staging area in preparation for making a commit. The idea is that you move
all the changes you want in your commit into the staging area and then turn the
changes in the staging area into your commit.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;git-add-p&quot;&gt;git add -p&lt;&#x2F;h2&gt;
&lt;p&gt;When &lt;code&gt;git add&lt;&#x2F;code&gt; is executed with the &lt;code&gt;-p&lt;&#x2F;code&gt; option it instructs &lt;code&gt;git add&lt;&#x2F;code&gt; to allow
you to select a portion of the changes in a local file for staging rather than
the entire set of changes in that local file.&lt;&#x2F;p&gt;
&lt;p&gt;Lets look at an example to see exactly how this works.&lt;&#x2F;p&gt;
&lt;p&gt;For sake of discussion lets say we have the following local, unstaged changes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git diff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index d325bcb..f8f8d46 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -5,3 +5,9 @@ Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Third paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Fourth paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given that we are following best practices because we want all the awesome Git
commands to be able to work on our repo and we want our Git history to be
useful we decide we want to create three separate commits, one to add each of
the paragraphs in the diff.&lt;&#x2F;p&gt;
&lt;p&gt;To do this we first start out by running the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git add -p README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This prompts us with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git add -p README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index d325bcb..f8f8d46 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -5,3 +5,9 @@ Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Third paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Fourth paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(1&#x2F;1) Stage this hunk [y,n,q,a,d,e,?]?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;oh-no-where-is-s&quot;&gt;Oh No! Where is s?&lt;&#x2F;h2&gt;
&lt;p&gt;Most of the time when you run &lt;code&gt;git add -p&lt;&#x2F;code&gt; it will present &lt;code&gt;s&lt;&#x2F;code&gt; as one of the
choices in the output. &lt;code&gt;s&lt;&#x2F;code&gt; stands for split and tells &lt;code&gt;git add -p&lt;&#x2F;code&gt; to split the
currently presented hunk into smaller hunks and then ask you if you want to
stage the smaller hunks.&lt;&#x2F;p&gt;
&lt;p&gt;But in this case and generally when you get your hunks small enough it won&#x27;t
split them any further. At this point you have use one of the other options it
provides.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;woot-woot-e-here-we-come&quot;&gt;Woot woot, e here we come!&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;e&lt;&#x2F;code&gt; option stands for edit and it puts us into manual hunk edit mode in our
editor. This looks like the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Manual hunk edit mode -- see bottom for a quick guide.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -5,3 +5,9 @@ Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Third paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Fourth paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# ---&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# To remove &amp;#39;-&amp;#39; lines, make them &amp;#39; &amp;#39; lines (context).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# To remove &amp;#39;+&amp;#39; lines, delete them.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Lines starting with # will be removed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# If the patch applies cleanly, the edited hunk will immediately be&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# marked for staging.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# If it does not apply cleanly, you will be given an opportunity to&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# edit again.  If all lines of the hunk are removed, then the edit is&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# aborted and the hunk is left unchanged.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see from the comments we can simply delete the &#x27;+&#x27; lines we don&#x27;t
want in this hunk. So in this case I edit the hunk to look as follows and save
and quit the editor.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -5,3 +5,9 @@ Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we run &lt;code&gt;git status&lt;&#x2F;code&gt; we can see it resulted in part of the changes be staged
and the other part not. Lets verify the parts are as we expect.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git diff --staged&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index d325bcb..8f6f97e 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -5,3 +5,5 @@ Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The staged changes are correct.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git diff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 8f6f97e..f8f8d46 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -7,3 +7,7 @@ Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Second paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Third paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Fourth paragraph&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the unstaged changes are correct.&lt;&#x2F;p&gt;
&lt;p&gt;So now we can make our first commit, &lt;code&gt;git commit -m &quot;first commit&quot;&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;From here we can simply rinse and repeat the process to end up with isolated
logically chunked commits.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git - Splitting Commits</title>
        <published>2021-01-19T00:00:00+00:00</published>
        <updated>2021-01-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-splitting-commits/"/>
        <id>https://drewdeponte.com/blog/git-splitting-commits/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-splitting-commits/">&lt;p&gt;When you first discover the importance of logically structured &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; commits,
which is by the way a core fundamental expectation &amp;amp; design characteristic of
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; and how it is intended to be used. You are probably still following
your bad habits and creating commits that aren&#x27;t logical commits.&lt;&#x2F;p&gt;
&lt;p&gt;This naturally leads to the question, &quot;How do I split a commit up into multiple
commits?&quot; Below I present a simple contrived example so that you can learn the
mechanics and process of doing this, as the mechanics &amp;amp; process don&#x27;t change.&lt;&#x2F;p&gt;
&lt;p&gt;The other topic related to this which this post &lt;strong&gt;does not&lt;&#x2F;strong&gt; cover is the
process of taking code and splitting it up into logical chunks. This generally
takes an understanding of the application architecture involved &amp;amp; the
dependency relationship between the various elements.&lt;&#x2F;p&gt;
&lt;p&gt;So lets get to it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;tldr&quot;&gt;TLDR&lt;&#x2F;h2&gt;
&lt;p&gt;For those who just want a quick reminder reference here is the TLDR. For those
who need a bit more context and detail through the walk through read the
sections below.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git rebase -i&lt;&#x2F;code&gt; - do an interactive rebase &amp;amp; mark the commit you want to
split for &lt;code&gt;edit&lt;&#x2F;code&gt;, it will drop you out into the shell at that commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git reset HEAD^&lt;&#x2F;code&gt; - soft reset the commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git add -p&lt;&#x2F;code&gt; - stage just the parts you want in the first commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt; - commit the first commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git add -p&lt;&#x2F;code&gt; - stage just the parts you want in the next commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git commit&lt;&#x2F;code&gt; - commit the next commit&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;git rebase --continue&lt;&#x2F;code&gt; - continue the rebase to play the other commits on
top of the new commits you created&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;initial-state&quot;&gt;Initial State&lt;&#x2F;h2&gt;
&lt;p&gt;For this example lets assume that we have a Git tree that has the following
commits.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;49d9eb4 - (HEAD -&amp;gt; main) Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;d3e4eee - Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;56fa164 - Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8da3dd9 - (base) Initial commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see from the first commit on &lt;code&gt;base&lt;&#x2F;code&gt;, &lt;code&gt;8da3dd9 - (base) Initial commit&lt;&#x2F;code&gt;, it adds the title to the README.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git show 56fa164&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit 56fa1649afa886c309ce8e83c5518b48c8600b6f&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Tue Jan 19 23:48:13 2021 -0500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index e79c5e8..4b3b7a8 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1 +1,2 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The second commit, &lt;code&gt;d3e4eee - Add Subtitle &amp;amp; Description of README&lt;&#x2F;code&gt;, adds the
subtitle and the description as seen in the diff below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git show d3e4eee&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit d3e4eeec96f9c3cd3eadeb4d95256a6326485ed4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Tue Jan 19 23:48:52 2021 -0500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 4b3b7a8..cf3aba6 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1,2 +1,5 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The third commit, &lt;code&gt;49d9eb4 - (HEAD -&amp;gt; main) Add first paragraph of the README&lt;&#x2F;code&gt;
adds the first paragraph in the diff below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git show 49d9eb4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit 49d9eb41bd3a0031f537b3865f6c90329f173bc4 (HEAD -&amp;gt; main)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Tue Jan 19 23:49:51 2021 -0500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index cf3aba6..d325bcb 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -3,3 +3,5 @@ Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+First paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;non-logically-structured-commit&quot;&gt;Non-Logically Structured Commit&lt;&#x2F;h2&gt;
&lt;p&gt;Looking at the commit summaries &amp;amp; the diffs themselves we can see that the
second commit, &lt;code&gt;d3e4eee - Add Subtitle &amp;amp; Description of README&lt;&#x2F;code&gt; is actually
doing two logical things. First it is adding the subtitle. Secondly it is
adding the description to the README.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git show d3e4eee&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit d3e4eeec96f9c3cd3eadeb4d95256a6326485ed4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Tue Jan 19 23:48:52 2021 -0500&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 4b3b7a8..cf3aba6 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1,2 +1,5 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Instead of the above what we really wanted to have was one commit that adds
the subtitle and a separate commit that adds the description as two isolated
logical chunks.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;edit-mode&quot;&gt;Edit Mode&lt;&#x2F;h3&gt;
&lt;p&gt;To accomplish this we need to utilize an interactive rebase to enter &quot;edit&quot;
mode in the correct place in the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; history. In this particular case we
want to rebase the 3 commits we looked at onto &lt;code&gt;base&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git rebase -i base&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will bring up the following in your editor.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 56fa164 Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick d3e4eee Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 49d9eb4 Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the interactive rebase buffer we can change the action for the middle commit
to &lt;code&gt;edit&lt;&#x2F;code&gt; so it as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 56fa164 Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;edit d3e4eee Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pick 49d9eb4 Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When you save &amp;amp; quit the editor it will run the specified interactive rebase
commands. In this case pick (meaning keep) the first commit and then stop on
the second commit allowing for editing because we specified, &lt;code&gt;edit&lt;&#x2F;code&gt;. When it
does this will drop you back to the console with a message similar to the
following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Stopped at d3e4eee...  Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;You can amend the commit now, with&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git commit --amend &amp;#39;-S&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Once you are satisfied with your changes, run&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	git rebase --continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;split-the-commit&quot;&gt;Split the Commit&lt;&#x2F;h3&gt;
&lt;p&gt;We want to split the changes currently held in this commit into multiple
commits. To do this we need to reset the commit that we are currently on and
then partially stage the changes back commit, then stage the other part and
commit, and then continue the rebase.&lt;&#x2F;p&gt;
&lt;p&gt;So first we have to reset just the commit that we are checked out on and we
want to do a soft reset. So we do the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git reset HEAD^&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now if we run &lt;code&gt;git diff&lt;&#x2F;code&gt; to see the now local ustagged changes we see the
following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git di&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 4b3b7a8..cf3aba6 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1,2 +1,5 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As we can see we now have the changes that add both the subtitle &amp;amp; the
description locally.&lt;&#x2F;p&gt;
&lt;p&gt;So we first want to stage a commit with just the &lt;code&gt;Subtitle of README&lt;&#x2F;code&gt; portion.
To do this we need to use &lt;code&gt;git add -p README&lt;&#x2F;code&gt; to do a partial stage of the
README files changes to just stage the &lt;code&gt;Subtitle of README&lt;&#x2F;code&gt; portion. See my
post, &lt;a href=&quot;&#x2F;blog&#x2F;git-add-patch-wont-split&#x2F;&quot;&gt;git add patch won&#x27;t split&lt;&#x2F;a&gt; for details
on how to accomplish this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you run &lt;code&gt;git status&lt;&#x2F;code&gt; to check on things at this point it should look like this.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;interactive rebase in progress; onto 8da3dd9&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Last commands done (2 commands done):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	 pick 56fa164 Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	 edit d3e4eee Add Subtitle &amp;amp; Description of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Next command to do (1 remaining command):&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	 pick 49d9eb4 Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	(use &amp;quot;git rebase --edit-todo&amp;quot; to view and edit)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;You are currently splitting a commit while rebasing branch &amp;#39;main&amp;#39; on &amp;#39;8da3dd9&amp;#39;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	(Once your working directory is clean, run &amp;quot;git rebase --continue&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Changes to be committed:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	(use &amp;quot;git restore --staged &amp;lt;file&amp;gt;...&amp;quot; to unstage)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				modified:   README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Changes not staged for commit:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	(use &amp;quot;git add &amp;lt;file&amp;gt;...&amp;quot; to update what will be committed)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	(use &amp;quot;git restore &amp;lt;file&amp;gt;...&amp;quot; to discard changes in working directory)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				modified:   README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If we specifically check out the staged changes with &lt;code&gt;git diff --staged&lt;&#x2F;code&gt; we get
the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git diff --staged&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 4b3b7a8..70e7d0a 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1,2 +1,3 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is exactly what we wanted. But lets make sure the unstaged changes also
represent what we want by running &lt;code&gt;git diff&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git diff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;diff --git a&#x2F;README b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;index 70e7d0a..cf3aba6 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;--- a&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+++ b&#x2F;README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@@ -1,3 +1,5 @@&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; initial&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; Subtitle of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;+Description of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Yep looks like they do. So now we just need create the first of the two commits
that will replace the commit we marked for edit. This can be done as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git commit -m &amp;quot;Add Subtitle to README&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From there we can stage the rest of the changes with &lt;code&gt;git add README&lt;&#x2F;code&gt; and
create the second commit with the following.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git commit -m &amp;quot;Add Description to README&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;finish-the-rebase&quot;&gt;Finish the Rebase&lt;&#x2F;h3&gt;
&lt;p&gt;Now that the changes have been split up into separate commits like we wanted we
now need to instruct it to finish the interactive rebase that we started with
the edit. This is done as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git rebase --continue&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once it is complete if we checkout our tree it will look as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;fe12bd6 - (HEAD -&amp;gt; main) Add first paragraph of the README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;3566dec - Add Description to README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;f676187 - Add Subtitle to README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;56fa164 - Add title of README&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;8da3dd9 - (base) Initial commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Exactly what we wanted!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Understanding zsh Startup &amp; Configuration</title>
        <published>2021-01-18T00:00:00+00:00</published>
        <updated>2021-01-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/understanding-zsh-startup-configuration/"/>
        <id>https://drewdeponte.com/blog/understanding-zsh-startup-configuration/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/understanding-zsh-startup-configuration/">&lt;p&gt;This is a little diagram I put together years ago when macOS El Capitan came
out and I ran into issues with how it was impacting my &lt;code&gt;PATH&lt;&#x2F;code&gt; environment
variable. It ends up that every so often I need to reference it.&lt;&#x2F;p&gt;
&lt;p&gt;Today was one of those days. However, I couldn&#x27;t remember where I put it. The
first place I looked was my blog. But it wasn&#x27;t there. Therefore once I found
it it I decided it was finally time to put it up on my blog. I hope it ends up
being as useful for you as it has been for me over the years.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;understanding-zsh-startup-configuration&#x2F;understanding_zsh_startup_on_mac_os_x.png&quot; alt=&quot;Understanding zsh Startup Diagram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; This diagram was built with a tool that I very much enjoy using when
it makes sense, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;monodraw.helftone.com&quot;&gt;Monodraw&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Changelog v3.3.2</title>
        <published>2021-01-11T00:00:00+00:00</published>
        <updated>2021-01-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-cl-v3-3-2-released/"/>
        <id>https://drewdeponte.com/blog/git-cl-v3-3-2-released/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-cl-v3-3-2-released/">&lt;p&gt;I just released &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-cl&quot;&gt;Git Changelog&lt;&#x2F;a&gt; v3.3.2. To update simply run the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew update &amp;amp;&amp;amp; brew upgrade git-cl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-s-changed&quot;&gt;What&#x27;s Changed?&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;support-any-branch&quot;&gt;Support any Branch&lt;&#x2F;h3&gt;
&lt;p&gt;It used to be that prior to this release that it would only work on the &lt;code&gt;master&lt;&#x2F;code&gt; branch. However with this release it now functions properly when currently checked out on any branch. It walks the Git tree from where you are currently checked out on and builds the history of the changelog. So you generally probably want to be checked out on your mainline branch when running it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;availability&quot;&gt;Availability&lt;&#x2F;h2&gt;
&lt;p&gt;This release of [Git Patch Stack][] is available via our Homebrew tap for both macOS Big Sur &amp;amp; macOS Catalina. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-cl&quot;&gt;README&lt;&#x2F;a&gt; for details this method and others.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Patch Stack v0.5.0</title>
        <published>2020-12-10T00:00:00+00:00</published>
        <updated>2020-12-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-ps-v0-5-0-released/"/>
        <id>https://drewdeponte.com/blog/git-ps-v0-5-0-released/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-ps-v0-5-0-released/">&lt;p&gt;I just released &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; v0.5.0. To update simply run the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew update &amp;amp;&amp;amp; brew upgrade git-ps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;what-s-changed&quot;&gt;What&#x27;s Changed?&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;multiple-stacks-of-patches&quot;&gt;Multiple Stacks of Patches?&lt;&#x2F;h3&gt;
&lt;p&gt;This release makes it so that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; now works with any branch that has an upstream branch, instead of having the patch stack be limited to the previously hard coded &lt;code&gt;master&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;origin&#x2F;master&lt;&#x2F;code&gt; upstream branch.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;other-mainlines&quot;&gt;Other Mainlines&lt;&#x2F;h4&gt;
&lt;p&gt;This is useful for making &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; work with repositories that have other mainlines, e.g. &lt;code&gt;main&lt;&#x2F;code&gt; &amp;amp; &lt;code&gt;origin&#x2F;main&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;stuck-in-feature-branches&quot;&gt;Stuck in Feature Branches&lt;&#x2F;h4&gt;
&lt;p&gt;It is also useful for managing branches that have upstreams in general. Lets say you are working with a client that doesn’t allow for individual patch pull requests but instead wants a feature branch with a series of logically chunked commits (a.k.a. patches, 😜). &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; can now be used to manage the patch stack within that feature branch.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;removed-explicit-base-branch&quot;&gt;Removed Explicit Base Branch&lt;&#x2F;h3&gt;
&lt;p&gt;This release removes the explicit base branch option from the &lt;code&gt;rr&lt;&#x2F;code&gt; and &lt;code&gt;pub&lt;&#x2F;code&gt; subcommands because I don&#x27;t think it is needed now that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; has dynamic upstream branch detection. Also, the explicit base branch option was confusing as it existed. If we find the need in the future to facilitate cross-upstream &lt;code&gt;rr&lt;&#x2F;code&gt;s or &lt;code&gt;pub&lt;&#x2F;code&gt;s we will add it back in a better way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;availability&quot;&gt;Availability&lt;&#x2F;h2&gt;
&lt;p&gt;This release of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; is available via our Homebrew tap for both macOS Big Sur &amp;amp; macOS Catalina. See the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;README&lt;&#x2F;a&gt; for details this method and others.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pullwalla - Big Sur &amp; The Future</title>
        <published>2020-11-18T00:00:00+00:00</published>
        <updated>2020-11-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pullwalla-macos-big-sur-bitbucket-server/"/>
        <id>https://drewdeponte.com/blog/pullwalla-macos-big-sur-bitbucket-server/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pullwalla-macos-big-sur-bitbucket-server/">&lt;p&gt;Hello!&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to clue you into some details around a few recent releases.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;macos&quot;&gt;macOS&lt;&#x2F;h2&gt;
&lt;p&gt;Pullwalla macOS &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog&#x2F;v2-6-0-30&#x2F;&quot;&gt;v2.6.0&lt;&#x2F;a&gt; &amp;amp; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog&#x2F;v2-6-1-31&#x2F;&quot;&gt;v2.6.1&lt;&#x2F;a&gt; both address the following items.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;macos-big-sur-support&quot;&gt;macOS Big Sur Support&lt;&#x2F;h4&gt;
&lt;p&gt;As I am sure you already know. macOS Big Sur was officially released. With it comes a completely new style that makes macOS Apps feel a little more like iPad apps. Which &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pullwalla macOS&lt;&#x2F;a&gt; now supports.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;files.pullwalla.com&#x2F;pullwalla-macos-2-6-1-31-on-big-sur.png&quot; alt=&quot;Pullwalla on Big Sur&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h4 id=&quot;missing-pull-requests&quot;&gt;Missing Pull Requests&lt;&#x2F;h4&gt;
&lt;p&gt;One of the ongoing challenges that we have had all along is the lack of documentation across the various platforms we support.  This results in JSON decoding failures on our end, in turn causing a PR or two to not show up every once and a blue moon.&lt;&#x2F;p&gt;
&lt;p&gt;We are constantly addressing these issues as we discover them to make sure you never miss a PR. These releases are no different. Combined we addressed five such issues making sure Pullwalla never misses a PR.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ios&quot;&gt;iOS&lt;&#x2F;h2&gt;
&lt;p&gt;Pullwalla iOS &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;v1-3-2-9&#x2F;&quot;&gt;v1.3.2&lt;&#x2F;a&gt; &amp;amp; &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;v1-3-1-8&#x2F;&quot;&gt;v1.3.1&lt;&#x2F;a&gt; were released addressing the same missing pull requests issues as above in the macOS release.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;bridging-the-gap-swiftui&quot;&gt;Bridging the Gap (SwiftUI)&lt;&#x2F;h3&gt;
&lt;p&gt;These Pullwalla releases on both macOS &amp;amp; iOS mark the beginning of a new age where we have started building cross-platform UI components using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;xcode&#x2F;swiftui&#x2F;&quot;&gt;SwiftUI&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;These releases now use a shared SwiftUI View between both Pullwalla macOS &amp;amp; iOS for adding a Bitbucket Server Account.&lt;&#x2F;p&gt;
&lt;p&gt;This is just the beginning as all the new features &amp;amp; UIs we are building are being done with SwiftUI. Also any views that we have to adjust or rework are being done in SwiftUI. This will help us bring the same set of features to both Pullwalla macOS &amp;amp; iOS.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thoughts-or-suggestions&quot;&gt;Thoughts or suggestions?&lt;&#x2F;h3&gt;
&lt;p&gt;As always, we’d love to hear from you.&lt;&#x2F;p&gt;
&lt;p&gt;Cheers,
The Pullwalla team&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Keep a Changelog without Conflicts</title>
        <published>2020-05-11T00:00:00+00:00</published>
        <updated>2020-05-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/keep-a-changelog-without-conflicts/"/>
        <id>https://drewdeponte.com/blog/keep-a-changelog-without-conflicts/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/keep-a-changelog-without-conflicts/">&lt;p&gt;For years, like many others, we have maintained &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; files inside our
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; repositories for our apps and libraries. We have followed the standards
outlined at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;keepachangelog.com&quot;&gt;keepachangelog.com&lt;&#x2F;a&gt; and we have appreciated the benefits it has
provided us for preparing releases and for maintaining a clear record of
changes included in each release while still being targeted at the appropriate
audience.&lt;&#x2F;p&gt;
&lt;p&gt;However, these benefits didn&#x27;t come without drawbacks. The biggest being that
while working on a repo with multiple people or developing locally using a
patch stack workflow you continually run into &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; conflicts solely with the
&lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; file. These conflicts aren&#x27;t meaningful in anyway. They are just
an impedance to our development flow and process, both as a team and as
individual contributors.&lt;&#x2F;p&gt;
&lt;p&gt;Well a few weeks ago &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;anthonycastelli.me&quot;&gt;Anthony Castelli&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;drewdeponte.com&quot;&gt;I&lt;&#x2F;a&gt; decided it was time to
remove this impedance not only for our local workflows but for the development
workflow the team. We started out by analyzing the characteristics of the
&lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; approach that we valued and the characteristics that were
causing the issues. The biggest turned out to be one and the same, the tight
coupling of the source code change to the &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; entry. This tight
coupling is what made it easy to prep releases of libs&#x2F;apps because the
developer that made the change, the person with context, also created the
associated &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt; entry. However, this was also the practice that was
triggering the useless conflicts in the &lt;code&gt;CHANGELOG.md&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So we hashed this out and eventually came to the realization
that we could have the tight coupling of the Changelog entry and the code while
avoiding the conflicts all together. We just had to lift the Changelog entry out
to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; commit message. After contemplating implementation approaches
and realizing at the core it would be similar to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-ps&quot;&gt;Git Patch Stack&lt;&#x2F;a&gt; we
immediately jumped into building a proof of concept &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; command line tool
extension to facilitate building a Changelog from entries in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt;
commits.&lt;&#x2F;p&gt;
&lt;p&gt;Over the last few weeks we have been using it in our workflows and iterating on
it to make sure it meets everyones needs. This work has resulted in our latest
open source project, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;git-cl&quot;&gt;Git Changelog&lt;&#x2F;a&gt;. Below is a ~15 min video where I
introduce the concepts, values, the &lt;code&gt;git-cl&lt;&#x2F;code&gt; tool, as well as it&#x27;s best
practices.&lt;&#x2F;p&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; style=&quot;margin: 0 auto;&quot; src=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;embed&#x2F;4JKs2761UuY&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen&gt;&lt;&#x2F;iframe&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pullwalla - Keepin&#x27; it Going</title>
        <published>2020-03-18T00:00:00+00:00</published>
        <updated>2020-03-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pullwalla-keepin-it-going/"/>
        <id>https://drewdeponte.com/blog/pullwalla-keepin-it-going/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pullwalla-keepin-it-going/">&lt;p&gt;Hello!&lt;&#x2F;p&gt;
&lt;p&gt;You&#x27;re receiving this email because you subscribed to updates for Pullwalla. Your unified pull request manager.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;where-are-we-at&quot;&gt;Where are we at?&lt;&#x2F;h4&gt;
&lt;p&gt;We are happy to share with you that since the last email update we have made some &lt;strong&gt;very significant&lt;&#x2F;strong&gt; changes. These are all available now in the releases in the App Stores.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;now-on-ios-ipad-macos&quot;&gt;Now on iOS, iPad &amp;amp; macOS&lt;&#x2F;h5&gt;
&lt;p&gt;One of these changes is that we have ported Pullwalla macOS over to work on iOS and iPad.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-keepin-it-going&#x2F;hero-v2.4.1-23.png&quot; alt=&quot;Pullwalla Hero&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Now you can enjoy managing pull requests on your Apple devices whether you are on the couch with your iPad and just need to make a quick response or at your computer and doing a deep review.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;bitbucket&quot;&gt;Bitbucket&lt;&#x2F;h5&gt;
&lt;p&gt;We have also added support to manage pull requests from Bitbucket Cloud and are in the process of adding support for Bitbucket Server &amp;amp; Data Center.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-keepin-it-going&#x2F;bitbucket-atlassian-logo-1.png&quot; alt=&quot;Bitbucket Logo&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This enables you to manage pull requests across all your GitHub &amp;amp; Bitbucket accounts whether you are a consultant with client repos spread across multiple accounts or just a dev on a team that uses Bitbucket for hosting their library, service, and app repositories.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;diff-stats-feature&quot;&gt;Diff Stats Feature&lt;&#x2F;h5&gt;
&lt;p&gt;Let&#x27;s say you are leaving for lunch in 15 mins and want to jump on a quick PR. How do you find a bite-sized PR to review without digging through repos and wasting those precious minutes?&lt;&#x2F;p&gt;
&lt;p&gt;Diff Stats is a new addition to the Pull Request Characteristics that solves this problem by facilitating visual scanning of PR size while also exposing details of additions, removals, and changes when you want them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-keepin-it-going&#x2F;characteristics-v2.2.0-18.png&quot; alt=&quot;Screenshot of Characteristics Feature&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If there is a PR that has 1000 additions and 1 removal, the PR will show a large green segment for the additions and a small red segment for the removals. Combined these provide you with a quick visual indication of size.&lt;&#x2F;p&gt;
&lt;h5 id=&quot;improvements-bug-fixes&quot;&gt;Improvements &amp;amp; Bug Fixes&lt;&#x2F;h5&gt;
&lt;p&gt;Beyond the above feature additions we have made numerous improvements and bug fixes. The following are some highlights.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;showing window when dock icon is clicked on macOS&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;notifications&lt;&#x2F;strong&gt; for new&#x2F;updated pull requests for Pro users&lt;&#x2F;li&gt;
&lt;li&gt;a &lt;strong&gt;compact view&lt;&#x2F;strong&gt; mode that limits pull request description body to only one line of text&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To get a full breakdown checkout the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog&#x2F;&quot;&gt;Pullwalla macOS Change Log&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog-ios&#x2F;&quot;&gt;Pullwalla iOS Change Log&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;where-to-next&quot;&gt;Where to next?&lt;&#x2F;h4&gt;
&lt;p&gt;At a high level next steps are as follow to start.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;add &lt;strong&gt;Shared Subscriptions across Devices&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;add &lt;strong&gt;iCloud Sync of Accounts&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;add &lt;strong&gt;Enterprise Integration&lt;&#x2F;strong&gt; with both GitHub and Bitbucket&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Beyond that we are also working on implementing PR interactions, &lt;strong&gt;Details View&lt;&#x2F;strong&gt;, &lt;strong&gt;PR Comments&lt;&#x2F;strong&gt;, &lt;strong&gt;Approve&#x2F;Reject&lt;&#x2F;strong&gt;, etc. To keep tabs on where we are going you can always check out our public &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;roadmap&#x2F;&quot;&gt;Roadmap&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;thoughts-or-suggestions&quot;&gt;Thoughts or suggestions?&lt;&#x2F;h4&gt;
&lt;p&gt;As always, we’d love to hear from you.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;keepin-it-going&quot;&gt;Keepin&#x27; it Going&lt;&#x2F;h4&gt;
&lt;p&gt;Our thoughts and prayers are with all those dealing with COVID-19. With the onslaught of the virus, we have been lucky enough to be a company that is able to shift to fully remote work and stay productive. To help us remain connected with our team, we built &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;apps.apple.com&#x2F;us&#x2F;app&#x2F;teamsmash&#x2F;id1487662886?mt=12&quot;&gt;TeamSmash&lt;&#x2F;a&gt;, a visual presence tool for remote teams that integrates with Slack. We find it very helpful, so we wanted to share in case it could help your team with the adjustment to remote work. It is a completely free app.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-keepin-it-going&#x2F;teamsmash-screenshot-001.png&quot; alt=&quot;Screenshot of TeamSmash in action&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Stay safe, stay positive, and keep it going!&lt;&#x2F;p&gt;
&lt;p&gt;The Pullwalla team&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Constraid v7.1.0</title>
        <published>2020-01-09T00:00:00+00:00</published>
        <updated>2020-01-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/constraid-v7-1-0/"/>
        <id>https://drewdeponte.com/blog/constraid-v7-1-0/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/constraid-v7-1-0/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;Constraid&quot;&gt;Constraid&lt;&#x2F;a&gt; v7.1.0 is available and includes a new API.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;api-layers&quot;&gt;API Layers&lt;&#x2F;h2&gt;
&lt;p&gt;In this release we provide a higher level API based on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Proxy_pattern&quot;&gt;Proxy pattern&lt;&#x2F;a&gt; to make things nicer. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;Constraid&quot;&gt;Constraid&lt;&#x2F;a&gt; effectively provides two &lt;strong&gt;public&lt;&#x2F;strong&gt; API layers now.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;high level &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Proxy_pattern&quot;&gt;Proxy pattern&lt;&#x2F;a&gt; based API&lt;&#x2F;li&gt;
&lt;li&gt;low level function API&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;Don&#x27;t worry this new API layer is strictly a convenience API layer. So this release is &lt;strong&gt;100% backwards compatible&lt;&#x2F;strong&gt; and all the low level function API will continue to work. In fact the new convenience API layer is actually built on top of the lower level function API.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;syntactic-sugar-chaining&quot;&gt;Syntactic Sugar &amp;amp; Chaining&lt;&#x2F;h2&gt;
&lt;p&gt;This new API layer is all about providing a nicer, more convenient API. It does so by utilizing the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Proxy_pattern&quot;&gt;Proxy pattern&lt;&#x2F;a&gt; to support chaining. In turn providing a much nicer API.&lt;&#x2F;p&gt;
&lt;p&gt;The original API layer is effectively a set of functions that create and return Autolayout Constraint Collections which can be combined together to make larger constraint collections. An example of this is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;flush&lt;&#x2F;span&gt;&lt;span&gt;(childView, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;withVerticalEdgesOf&lt;&#x2F;span&gt;&lt;span&gt;: parentView)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;  center&lt;&#x2F;span&gt;&lt;span&gt;(childView, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;verticallyWithin&lt;&#x2F;span&gt;&lt;span&gt;: parentView)).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Well, dealing with the &lt;code&gt;+&lt;&#x2F;code&gt; operator and the parens is no longer necessary. As the above can now be implemented using the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Proxy_pattern&quot;&gt;Proxy pattern&lt;&#x2F;a&gt; API as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;childView.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;constraid&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;flush&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;withVerticalEdgesOf&lt;&#x2F;span&gt;&lt;span&gt;: parentView)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;center&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;verticallyWithin&lt;&#x2F;span&gt;&lt;span&gt;: parentView)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I hope you can agree this is an easier to read API style and it still provides all the important features and functionality of the lower level API.&lt;&#x2F;p&gt;
&lt;p&gt;But don&#x27;t worry. If we somehow accidentally missed something you can always fall back to using the lower level function API we all used before.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pullwalla is now in the App Store</title>
        <published>2019-11-18T00:00:00+00:00</published>
        <updated>2019-11-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pullwalla-is-now-in-the-app-store/"/>
        <id>https://drewdeponte.com/blog/pullwalla-is-now-in-the-app-store/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pullwalla-is-now-in-the-app-store/">&lt;h2 id=&quot;pra-is-now-pullwalla&quot;&gt;Pra is now Pullwalla!&lt;&#x2F;h2&gt;
&lt;p&gt;The app that began as a command line tool named Pra has made the next step in its journey with a new name and new features.&lt;&#x2F;p&gt;
&lt;p&gt;The goal remains the same: Pullwalla is designed to be a single, unified interface that allows you to easily manage all the pull requests you care about.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-name-and-logo&quot;&gt;New Name and Logo&lt;&#x2F;h2&gt;
&lt;p&gt;The new name reflects a change in focus from a minimal, text-based list of pull requests to a full-featured, modern client that is both informative and a pleasure to use.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-is-now-in-the-app-store&#x2F;dock.png&quot; alt=&quot;Pullwalla - Screenshot of the Pullwalla icon in the macOS dock&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The roots of the app haven’t changed—it aims to be simple, helpful, and unobtrusive. Pullwalla, just like its namesake wallaby, takes advantage of its diminutive size to remain fast, nimble, and quiet.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-features&quot;&gt;New Features&lt;&#x2F;h2&gt;
&lt;p&gt;This release features more than just a makeover. We have added characteristics to help you quickly identify the state of your pull requests. New quick filters help you quickly drill down to exactly what you need. Bugs have been squashed.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-is-now-in-the-app-store&#x2F;characteristics.png&quot; alt=&quot;Pullwalla - Screenshot of the app highlighting pull request characteristics&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;And that’s not all—plenty more features are in the works.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;new-website&quot;&gt;New Website&lt;&#x2F;h2&gt;
&lt;p&gt;A new name deserves a fresh &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;?utm_source=uptech&amp;amp;utm_medium=blog-post&amp;amp;utm_campaign=uptech-blog-pullwalla-launch&quot;&gt;website&lt;&#x2F;a&gt;. We have created a landing page to highlight features.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pullwalla-is-now-in-the-app-store&#x2F;website.png&quot; alt=&quot;Screenshot of pullwalla.com landing page&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;support&#x2F;?utm_source=uptech&amp;amp;utm_medium=blog-post&amp;amp;utm_campaign=uptech-blog-pullwalla-launch&quot;&gt;support page&lt;&#x2F;a&gt; with frequently asked questions will help you get started quickly. A &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;changelog&#x2F;?utm_source=uptech&amp;amp;utm_medium=blog-post&amp;amp;utm_campaign=uptech-blog-pullwalla-launch&quot;&gt;change log&lt;&#x2F;a&gt; lets you know what we’ve been working on in the past, while the new &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&#x2F;roadmap&#x2F;?utm_source=uptech&amp;amp;utm_medium=blog-post&amp;amp;utm_campaign=uptech-blog-pullwalla-launch&quot;&gt;roadmap&lt;&#x2F;a&gt; allows us to highlight what we’re working on now and what we have planned for the future.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;more-to-come&quot;&gt;More to come...&lt;&#x2F;h2&gt;
&lt;p&gt;We’re excited about all the changes we have in store! We hope you find Pullwalla as useful and pleasurable as we do.&lt;&#x2F;p&gt;
&lt;p&gt;Please &lt;a href=&quot;mailto:pullwalla@uptechstudio.com&quot;&gt;drop us a line&lt;&#x2F;a&gt; if you have any questions, comments, or suggestions.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Constraid v7.0.0</title>
        <published>2019-10-08T00:00:00+00:00</published>
        <updated>2019-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/constraid-v7-0-0/"/>
        <id>https://drewdeponte.com/blog/constraid-v7-0-0/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/constraid-v7-0-0/">&lt;p&gt;I just released v7.0.0 of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;Constraid&quot;&gt;Constraid&lt;&#x2F;a&gt;. This release is small in terms of features however is quite significant.&lt;&#x2F;p&gt;
&lt;p&gt;In this release we now provide support for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;swift.org&#x2F;package-manager&#x2F;&quot;&gt;Swift Package Manager&lt;&#x2F;a&gt; (SPM). This is a huge improvement with the recent support for SPM in Xcode. It already seems to be a superior experience to CocoaPods or even Carthage with a few more edge cases that need to be ironed out. But, hopefully those edge cases will be resolved in the near future.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Constraid v6.0.0</title>
        <published>2019-09-12T00:00:00+00:00</published>
        <updated>2019-09-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/constraid-v6-0-0-released/"/>
        <id>https://drewdeponte.com/blog/constraid-v6-0-0-released/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/constraid-v6-0-0-released/">&lt;p&gt;I just released v6.0.0 of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;Constraid&quot;&gt;Constraid&lt;&#x2F;a&gt;, your favorite iOS &amp;amp; macOS Auto Layout framework, 😉.&lt;&#x2F;p&gt;
&lt;p&gt;This release is a &lt;strong&gt;major version bump&lt;&#x2F;strong&gt; because I included a breaking change, though relatively minor. I strictly follow &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;semver.org&quot;&gt;Semantic Versioning&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;discardableresult&quot;&gt;@discardableResult&lt;&#x2F;h3&gt;
&lt;p&gt;In this release I removed the &lt;code&gt;@discardableResult&lt;&#x2F;code&gt; declaration attribute which is a &lt;strong&gt;breaking change&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I did this because I came to the realization that ever since we removed the automatic constraint activation to better support Auto Layout animations we haven&#x27;t needed the &lt;code&gt;@discardableResult&lt;&#x2F;code&gt; attribute. In fact when I was pairing with one of our engineers and he forgot to activate a returned constraint collection, I realized it was actually hindering users.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, I removed the &lt;code&gt;@discardableResult&lt;&#x2F;code&gt; declaration attributes. This now causes the compiler to remind you to do something with the returned constraint collection from any of the functions. Hopefully, this will help keep people from running into, &quot;Oh crap, I forgot to activate the constaints&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Having the compiler require you to do something with the results shouldn&#x27;t be a problem as you will either be.&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;activating the constraint collection immediately, ex: &lt;code&gt;Constraid.flush(viewA, withEdgesOf: viewB).activate()&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;storing constraint collection for later use&lt;&#x2F;li&gt;
&lt;li&gt;using the constraint collection in an expression&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;All of which satisify the compilers requirement.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;relative-position-to-center&quot;&gt;Relative Position to Center&lt;&#x2F;h3&gt;
&lt;p&gt;The other item included in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;Constraid&quot;&gt;Constraid&lt;&#x2F;a&gt; v6.0.0 is the addition of the following methods:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;follow(theCenterOf:with:)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;precede(theCenterOf:with:)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;set(viewA, aboveTheCenterOf:)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;set(viewA, beloweTheCenterOf:)&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Lets take the first two and look at an example of where they would come in useful. To, start lets look at the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bear.app&quot;&gt;Bear&lt;&#x2F;a&gt; app&#x27;s subscriptions view.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;constraid-v6-0-0-released&#x2F;bear_subscription.png&quot; alt=&quot;Bear.app Subscriptions View&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If we imagine a dashed line going down the middle of the view you can see what elements are naturally related to the center of the view.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;constraid-v6-0-0-released&#x2F;bear_subscription_marked_up.png&quot; alt=&quot;Bear.app Subscriptions View Marked Up&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this particular case both the &lt;em&gt;Terms of Service&lt;&#x2F;em&gt; and &lt;em&gt;Privacy Policy&lt;&#x2F;em&gt; links at the bottom of the view are relative to the center.&lt;&#x2F;p&gt;
&lt;p&gt;To replicate the layout of the &lt;em&gt;Terms of Service&lt;&#x2F;em&gt; and &lt;em&gt;Privacy Policy&lt;&#x2F;em&gt; buttons using Constraid we would do the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Constraid.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;follow&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;theCenterOf&lt;&#x2F;span&gt;&lt;span&gt;: view, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;: privacyPolicyButton, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Constraid.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;flush&lt;&#x2F;span&gt;&lt;span&gt;(privacyPolicyButton, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;withBottomEdgeOf&lt;&#x2F;span&gt;&lt;span&gt;: view, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;insetBy&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Constraid.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;precede&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;theCenterOf&lt;&#x2F;span&gt;&lt;span&gt;: view, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;with&lt;&#x2F;span&gt;&lt;span&gt;: termsOfServiceButton, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;by&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Constraid.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;flush&lt;&#x2F;span&gt;&lt;span&gt;(termsOfServiceButton, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;withBottomEdgeOf&lt;&#x2F;span&gt;&lt;span&gt;: view, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;insetBy&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;activate&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From here you can see that you could handle the subscribe buttons in a similar fashion. Or, if you wanted to do something around the vertical center you can do so using &lt;code&gt;set(viewA, aboveTheCenterOf:)&lt;&#x2F;code&gt; or &lt;code&gt;set(viewA, belowTheCenterOf:)&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;That about covers it. If you found this valuable or interesting please subscribe to my mailing list using the form below.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Swift Failable Decodable</title>
        <published>2019-08-30T00:00:00+00:00</published>
        <updated>2019-08-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/swift-failable-decodable/"/>
        <id>https://drewdeponte.com/blog/swift-failable-decodable/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/swift-failable-decodable/">&lt;h2 id=&quot;problem&quot;&gt;Problem&lt;&#x2F;h2&gt;
&lt;p&gt;First things first. Lets understand the problem. To do this lets look at situation based on the real world issue that drove me to tackle this.&lt;&#x2F;p&gt;
&lt;p&gt;Recently while working on &lt;a rel=&quot;external&quot; title=&quot;Pra - App Store Page&quot; href=&quot;https:&#x2F;&#x2F;itunes.apple.com&#x2F;us&#x2F;app&#x2F;pra&#x2F;id1447158795?mt=12&quot;&gt;Pra&lt;&#x2F;a&gt; I ran into a situation where it was fetching pull requests from GitHub and then failing to decode the JSON payload response containing the collection of pull requests, resulting in getting back zero pull requests. This is an unacceptable experience.&lt;&#x2F;p&gt;
&lt;p&gt;The decoding was implemented in the default fashion as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PullRequestSearchResponseNode&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; author: PullRequestSearchResponseAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; title:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; body:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; closedAt: Date&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; permalink: URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PullRequestSearchResponseDataSearch&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; nodes: [PullRequestSearchResponseNode]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; pageInfo: PullRequestSearchResponsePageInfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After some investigation I came to understand that it was failing due to not being able to properly decode one specific pull request because of effectively a type miss-match. For simplicity sake lets say the miss-match is happening because the &lt;code&gt;PullRequestSearchResponseNode.closedAt&lt;&#x2F;code&gt; property has a value in some pull request payloads but is &lt;code&gt;null&lt;&#x2F;code&gt; in others. This is a problem because our &lt;code&gt;struct&lt;&#x2F;code&gt; that we are trying to decode into states that it is expecting &lt;code&gt;closedAt&lt;&#x2F;code&gt; to always have a value.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;optionals&quot;&gt;Optionals&lt;&#x2F;h2&gt;
&lt;p&gt;The correct, easiest, and most direct answer in the case of &lt;code&gt;closedAt&lt;&#x2F;code&gt; is to adjust the &lt;code&gt;PullRequestSearchResponseNode&lt;&#x2F;code&gt; struct so that the &lt;code&gt;closedAt&lt;&#x2F;code&gt; property is an &lt;code&gt;Optional&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PullRequestSearchResponseNode&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; author: PullRequestSearchResponseAccount&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; title:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; body:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; String&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; closedAt: Date&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; permalink: URL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-catch&quot;&gt;The Catch&lt;&#x2F;h2&gt;
&lt;p&gt;Using an &lt;code&gt;Optional&lt;&#x2F;code&gt; is great. It fixes the problem and &lt;a rel=&quot;external&quot; title=&quot;Pra - App Store Page&quot; href=&quot;https:&#x2F;&#x2F;itunes.apple.com&#x2F;us&#x2F;app&#x2F;pra&#x2F;id1447158795?mt=12&quot;&gt;Pra&lt;&#x2F;a&gt; is able to successfully decode all the pull requests again. However, there is one major catch. Sadly as much as we feel we know the specifications for a JSON payload it is likely we will miss something or maybe the JSON payload will change over time. Given this will inevitably happen we can&#x27;t have that breaking our applications.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;possible-paths&quot;&gt;Possible Paths&lt;&#x2F;h2&gt;
&lt;p&gt;So we need to come up with some way of handling the fact that we will miss something in the specification or that the specification will change.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;all-properties-optional&quot;&gt;All Properties Optional&lt;&#x2F;h3&gt;
&lt;p&gt;One approach, not that I recommend it, is to make every property on the decodable struct an &lt;code&gt;Optional&lt;&#x2F;code&gt;. This would address a chunk of possible issues in decoding but &lt;strong&gt;not&lt;&#x2F;strong&gt; all possible issues. Also, it has the massive downside of then forcing the rest of the app to deal with both &lt;code&gt;Optional&lt;&#x2F;code&gt; paths everywhere in the code. Even if it is a property that will always be present.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optional-wrapper&quot;&gt;Optional Wrapper&lt;&#x2F;h3&gt;
&lt;p&gt;Another approach is to create a generic struct around &lt;code&gt;T&lt;&#x2F;code&gt; that wraps an option property of type &lt;code&gt;T&lt;&#x2F;code&gt; and provides decoding implementation. This could look something like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Failable&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;T&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span&gt; wrappedValue:T&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; decoder&lt;&#x2F;span&gt;&lt;span&gt;: Decoder)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; throws&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; container &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= try&lt;&#x2F;span&gt;&lt;span&gt; decoder.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;singleValueContainer&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;wrappedValue&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = try?&lt;&#x2F;span&gt;&lt;span&gt; container.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;decode&lt;&#x2F;span&gt;&lt;span&gt;(T.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We would use this as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PullRequestSearchResponseDataSearch&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; nodes: [Failable&amp;lt;PullRequestSearchResponseNode&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; pageInfo: PullRequestSearchResponsePageInfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is nice as it effectively makes it so that we can make decoding failable at any of the various object boundaries. In the scenarios where decoding fails for some reason our &lt;code&gt;wrappedValue&lt;&#x2F;code&gt; would simply be &lt;code&gt;null&lt;&#x2F;code&gt;. This is definitely a step in the right direction. However, it has one major drawback. We have no idea why the decoding failed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;result-based-failable-decodable&quot;&gt;Result based Failable Decodable&lt;&#x2F;h3&gt;
&lt;p&gt;Enter the &lt;code&gt;Result&lt;&#x2F;code&gt; type. This is exactly it&#x27;s purpose, to manage optionality while also maintaining an associated error. So, instead of building a wrapper struct we can simply extend &lt;code&gt;Result&lt;&#x2F;code&gt; to implement the &lt;code&gt;Decodable&lt;&#x2F;code&gt; protocol and implement the constructor to handle appropriately assigning the &lt;code&gt;success&lt;&#x2F;code&gt; state in successful decodes, and assigning the &lt;code&gt;failure&lt;&#x2F;code&gt; state when decoding fails. This looks as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Result&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; where&lt;&#x2F;span&gt;&lt;span&gt; Success&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt;, Failure &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;==&lt;&#x2F;span&gt;&lt;span&gt; DecodingError {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; decoder&lt;&#x2F;span&gt;&lt;span&gt;: Decoder)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; throws&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    do&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      let&lt;&#x2F;span&gt;&lt;span&gt; container &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= try&lt;&#x2F;span&gt;&lt;span&gt; decoder.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;singleValueContainer&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      self =&lt;&#x2F;span&gt;&lt;span&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;success&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;try&lt;&#x2F;span&gt;&lt;span&gt; container.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;decode&lt;&#x2F;span&gt;&lt;span&gt;(Success.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; catch let&lt;&#x2F;span&gt;&lt;span&gt; err &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Failure&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;      self =&lt;&#x2F;span&gt;&lt;span&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;failure&lt;&#x2F;span&gt;&lt;span&gt;(err)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is used as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; struct&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; PullRequestSearchResponseDataSearch&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; Decodable&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; nodes: [Result&amp;lt;PullRequestSearchResponseNode, DecodingError&amp;gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;  public let&lt;&#x2F;span&gt;&lt;span&gt; pageInfo: PullRequestSearchResponsePageInfo&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is great as we get the same ability to make objects failable decodables at any of the object boundaries but we also maintain all of the decoding errors to let us know why decoding failed for a given node.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If you are dealing with this situation you probably want to use the &lt;strong&gt;Result based Failable Decodable&lt;&#x2F;strong&gt; approach. I used this technique to solve the problems described in the &lt;a href=&quot;&#x2F;blog&#x2F;pra-v1-4-0-released&#x2F;&quot;&gt;Pra v1.4.0 Announcement&lt;&#x2F;a&gt;. It facilitated collecting the decode failures and building the debug report so users can send them back to us.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pra v1.4.0</title>
        <published>2019-08-21T00:00:00+00:00</published>
        <updated>2019-08-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pra-v1-4-0-released/"/>
        <id>https://drewdeponte.com/blog/pra-v1-4-0-released/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pra-v1-4-0-released/">&lt;p&gt;Version v1.4.0 of Pra just made it to the App Store.&lt;&#x2F;p&gt;
&lt;p&gt;This release was focused on reliability and robustness. The last release was focused more heavily on new features. If you missed that checkout the &lt;a href=&quot;&#x2F;blog&#x2F;pra-v1-3-0-released&quot;&gt;Pra v1.3.0&lt;&#x2F;a&gt; post.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;reliability&quot;&gt;Reliability&lt;&#x2F;h3&gt;
&lt;p&gt;After the &lt;a href=&quot;&#x2F;blog&#x2F;pra-v1-3-0-released&quot;&gt;v1.3.0 release&lt;&#x2F;a&gt; I quickly got feedback that there were some reliability issues. First there were reports of an infinite loading spinner. After some investigation we discovered it was a side effect of JSON decoding failing in the scenario where a pull request has a requested reviewer that is a GitHub team. So, we resolved both of these bugs in this release.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;robustness&quot;&gt;Robustness&lt;&#x2F;h3&gt;
&lt;p&gt;We also realized while digging into the above mentioned reliability issues that we had the following robustness issues.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The existing logging wasn’t generally valuable&lt;&#x2F;li&gt;
&lt;li&gt;The decoding of the fetched pull requests would fail if any of the decoding failed. So, if it couldn’t decode 1 out of 20 pull requests the user would still get 0 pull requests back.&lt;&#x2F;li&gt;
&lt;li&gt;When JSON decoding failures happened we had no way of easily finding out or getting useful information that would help us resolve them in the future.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To address these robustness issues I made tho following changes:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Migrated logging from mix of &lt;code&gt;NSLog&lt;&#x2F;code&gt; and &lt;code&gt;print&lt;&#x2F;code&gt; calls over to the newer standard &lt;code&gt;OSLog&lt;&#x2F;code&gt; interface.&lt;&#x2F;li&gt;
&lt;li&gt;Eliminated useless logging, cleaned up and categorized the logging I kept so that users would have a much easier time finding valuable logs.&lt;&#x2F;li&gt;
&lt;li&gt;Added more detailed error logging when JSON decoding fails happen in the hopes that it is more helpful in identifying &amp;amp; fixing issues.&lt;&#x2F;li&gt;
&lt;li&gt;Added fail-able Pull Request decoding so that successfully decoded pull requests are presented to the user and unsuccessful pull request decodings are logged.&lt;&#x2F;li&gt;
&lt;li&gt;Added a flash notice system to be able to inform the user in-app about things. Specifically, I used this to inform the user of pull request decode failures and provide a call to action enabling them to send a debug report so that we might address the issue.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;img src=&quot;decoding_failure_flash_dark_mode.png&quot; alt=&quot;Pra - Decoding Failure Flash Dark Mode&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
&lt;img src=&quot;decoding_failure_flash_light_mode.png&quot; alt=&quot;Pra - Decoding Failure Flash Light Mode&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pra v1.3.0</title>
        <published>2019-07-18T00:00:00+00:00</published>
        <updated>2019-07-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pra-v1-3-0-released/"/>
        <id>https://drewdeponte.com/blog/pra-v1-3-0-released/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pra-v1-3-0-released/">&lt;p&gt;This release includes a mix of foundational features, small improvement features, as well as some bug fixes, performance improvements, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ignore-organizations&quot;&gt;Ignore Organizations&lt;&#x2F;h2&gt;
&lt;p&gt;We added the ability to &lt;strong&gt;Ignore Organizations&lt;&#x2F;strong&gt; in addition to already being able to ignore a repository. This is an extemely useful feature that can help you gain focus by ignoring pull requests that belong to organizations you are a member of but aren&#x27;t interested in reviewing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pra-v1-3-0-released&#x2F;ignore-organization.png&quot; alt=&quot;Pra - Ignore Organizations&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;quick-filters&quot;&gt;Quick Filters&lt;&#x2F;h2&gt;
&lt;p&gt;We also added a foundational feature, Quick Filters, in this release. It includes the &lt;em&gt;Created&lt;&#x2F;em&gt;, &lt;em&gt;Assigned&lt;&#x2F;em&gt;, &lt;em&gt;Mentioned&lt;&#x2F;em&gt;, and &lt;em&gt;Review Requests&lt;&#x2F;em&gt; quick filters while also laying the foundation for the future. Quick Filters enable quickly filtering the set of pull requests down based on a particular mindset. Below are a few mindsets and their associated quick filters.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Trying to catch up on what last happened on one of your pull requests? Use the &lt;strong&gt;Created&lt;&#x2F;strong&gt; quick filter.&lt;&#x2F;li&gt;
&lt;li&gt;Trying to remember what pull requests you are responsible for? Use the &lt;strong&gt;Assigned&lt;&#x2F;strong&gt; quick filter.&lt;&#x2F;li&gt;
&lt;li&gt;Want to know who is talking about you? Use the &lt;strong&gt;Mentioned&lt;&#x2F;strong&gt; quick filter and see the pull requests that mention you.&lt;&#x2F;li&gt;
&lt;li&gt;Can&#x27;t keep track of all the requests for reviews? No, problem see them with the &lt;strong&gt;Review Requests&lt;&#x2F;strong&gt; quick filter.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;pra-v1-3-0-released&#x2F;quick-filters.png&quot; alt=&quot;Pra - Quick Filters&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bug-fixes-performance-improvements-etc&quot;&gt;Bug Fixes, Performance Improvements, etc.&lt;&#x2F;h2&gt;
&lt;p&gt;In addition to the above changes we also did the following.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;fixed a small layout issue in Preferences&lt;&#x2F;li&gt;
&lt;li&gt;switched from GitHub v3 REST API to GitHub v4 GraphQL API&lt;&#x2F;li&gt;
&lt;li&gt;made some performance improvements&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The most significant of these changes was switch to GitHub v4 GraphQL API as it facilitates getting the right data out of GitHub in a more efficient fashion. It also puts us on their latest API so that we don&#x27;t have to be worried about the API being deprecated out from under us.&lt;&#x2F;p&gt;
&lt;p&gt;Overall we think this release was an excellent step in the right direction and hope you enjoy the new features. As always we love hearing from you. So, don&#x27;t hesitate ping us on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;uptechstudio&quot;&gt;Twitter&lt;&#x2F;a&gt; or &lt;a href=&quot;mailto:pullwalla@uptechstudio.com&quot;&gt;email&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pra - The App Store Audible</title>
        <published>2019-02-22T00:00:00+00:00</published>
        <updated>2019-02-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pra-the-app-store-audible/"/>
        <id>https://drewdeponte.com/blog/pra-the-app-store-audible/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pra-the-app-store-audible/">&lt;p&gt;It is Sunday, Feb 17th, 2019 at 10:58 pm and I have just submitted the &lt;strong&gt;Minimal Free Version&lt;&#x2F;strong&gt; of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pra&lt;&#x2F;a&gt; to the Apple App Store for review. I post in our team Slack channel that I&#x27;ve submitted and I cross my fingers as we wait for Apple to respond.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;minimal-free-version&quot;&gt;Minimal Free Version&lt;&#x2F;h2&gt;
&lt;p&gt;It is probably worth explaining that our &lt;strong&gt;Minimal Free Version&lt;&#x2F;strong&gt; is pretty small in terms of functionality. It lets you do the following things:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Manage an Account&lt;&#x2F;strong&gt; - Add or remove your GitHub account.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;See a Feed of Pull Requests&lt;&#x2F;strong&gt; - See a continuously updating feed of pull requests you potentially want to review, aggregated across all repos you have access to, with the necessary data to quickly assess if you want to review one of them.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;View a Pull Request&lt;&#x2F;strong&gt; - As you&#x27;re looking through open requests, if you see one you want to review, you can quickly view the pull request details in your default browser.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Ignore Repositories&lt;&#x2F;strong&gt; - Select a pull request in the feed and ignore&#x2F;hide the repository it&#x27;s in from the feed of pull requests. Extremely helpful in reducing noise in your pull request feed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;We thought that the tool was already valuable in this state and we just wanted to get it in the hands of users to validate our assumptions. Would other people find this minimal state of the product valuable? If they don’t, it would be extremely useful to learn why not. If they do find it valuable, that is reassurance we are on the right path. Either way, we&#x27;re interested in feedback that will help us decide which features to focus on and when, including what should be in the paid version and what should be in the free version.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-app-store-response&quot;&gt;The App Store Response&lt;&#x2F;h2&gt;
&lt;p&gt;It is now Feb 18, 2019 at 7:22 PM and we just received a rejection response from Apple.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Guideline 4.2.2 - Design&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The experience that your app provides is not sufficiently different from browsing a content aggregator web site.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Next Steps&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;While your app may facilitate access to content from a range of web sites, even when including native macOS features, the experience it provides is not significantly different from using Safari. Such apps do not include enough native macOS functionality to be appropriate for the App Store.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;headspace&quot;&gt;Headspace&lt;&#x2F;h2&gt;
&lt;p&gt;To be honest, getting this response was frustrating and a little disheartening. Part of why I feel that way I think is because Apple&#x27;s response is so generic and unclear. What do they consider native macOS functionality? The app is 100% written in Swift, doesn’t use any web views, and integrates with macOS Keychain and UIKit. There are also plenty of apps on the App Store that don&#x27;t seem to include any more native macOS functionality than &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pra&lt;&#x2F;a&gt;, even in its current, minimal state. Somehow those apps were allowed on the App Store. So a few of us (mostly me) start venting a bit about this in Slack, while we slowly start to calm down.&lt;&#x2F;p&gt;
&lt;p&gt;Once I calmed down, we started throwing out ideas about what &quot;enough native macOS functionality&quot; could mean to Apple. We look at RSS Feed Reader apps because they are &quot;content aggregators&quot; and there are a ton of them in the App Store. Most of them provide a viewer interface for the posts, so we think maybe we need to add a &lt;em&gt;pull request viewer&lt;&#x2F;em&gt; in the app rather than just open the PR in the default browser. This is already in our idea backlog, so it&#x27;s not out of left field.&lt;&#x2F;p&gt;
&lt;p&gt;Adam suggested trying to find one or two features that would take minimal effort to build, but be unique to the desktop, to see if Apple would then accept the app as having &quot;enough&quot; native functionality. He threw out a few ideas:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Some sort of notifications&lt;&#x2F;li&gt;
&lt;li&gt;Badge on dock icon&lt;&#x2F;li&gt;
&lt;li&gt;Banners&#x2F;alerts&lt;&#x2F;li&gt;
&lt;li&gt;Menu bar icon&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Another thought I had rolling around in my head was how much of the rejection was a side effect of our App Store copy not explaining the true value of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pra&lt;&#x2F;a&gt;?&lt;&#x2F;p&gt;
&lt;p&gt;I was having a hard time homing in on exactly what we should do. So I went back to why we were trying to launch the app in the first place: to get crucial feedback and find out if other people find it valuable in its current state. At this stage, we&#x27;re more interested in getting an idea of whether or not we are on the right track and gathering some feedback than we are interested in wide distribution.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-audible&quot;&gt;The Audible&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, I started thinking maybe we should just launch via direct download from our website rather than via the App Store. This would allow us to get versions out quickly and gather feedback while we continue the review process with Apple.&lt;&#x2F;p&gt;
&lt;p&gt;So, we hashed it out as a team in Slack and decided to put the download on our site (and start to gather feedback and iterate on the &lt;strong&gt;Minimal Free Version&lt;&#x2F;strong&gt;) while we continue to work with Apple to get clarification and get the app ready to resubmit to the App Store.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-non-app-store-launch&quot;&gt;The Non-App Store Launch&lt;&#x2F;h2&gt;
&lt;p&gt;Feb 21st, 2019 at 1:39 PM we launched a landing page with the direct download button to get the app, and shared it with small group of colleagues in another Slack team.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sam-s-feedback&quot;&gt;Sam’s Feedback&lt;&#x2F;h3&gt;
&lt;p&gt;That afternoon I got feedback from a friend named Sam now using it and asking the following questions:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;How do I add more than one account?&lt;&#x2F;strong&gt; - We realized this was an indicator that our communication via Tooltip on the add account button was too subtle to properly communicate that the free version only supports one account. Also, it made us think we should probably have a mechanism at that point to allow people to submit their email address to join the mailing list to find out about releases and when multi-account support is added.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;How do I connect to my Enterprise GitHub account?&lt;&#x2F;strong&gt; - This is a feature we talked about being part of the paid features previously as well. So, we took this as reassurance that there is at least some need for this feature.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;nico-s-feedback&quot;&gt;Nico’s Feedback&lt;&#x2F;h3&gt;
&lt;p&gt;Later that evening I got feedback from another friend asking about what PRs are included in the feed. He wasn’t seeing a PR that he knew he could see in the &lt;em&gt;Created at&lt;&#x2F;em&gt; filter on GitHub. He thought it was because he is an External Collaborator on the repository, and it turns out he was right that that functionality was missing. So, I quickly made a ticket to resolve the bug and started working on a fix. I shipped the fix to Nico so he could test it and find out if it resolved his issue.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, the new version still didn’t show the PR Nico was missing, but it did add the missing functionality of showing pull requests from repositories that you are an external collaborator of. Digging a little deeper with Nico, we eventually figured out that his missing PR was from a fork of a repository he no longer had access to.&lt;&#x2F;p&gt;
&lt;p&gt;He thought it might not be worth the effort to fix (maybe this is just an edge case?). I responded that we probably wouldn&#x27;t add this to the main feed view (because the main purpose of the feed is to show pull requests you might be interested in reviewing, not necessarily all the pull requests you can access). But, I also let him know that we were contemplating adding other feed views via quick filters, including a “Created” filter which would show this pull request. This would support a different user goal of checking in on the status of their own PRs, and if there is anything they can do to move them forward. Our conversation and interaction gave me reassurance that what we are thinking in terms of features, contexts&#x2F;modes, etc. were right on track at least with Nico.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-high&quot;&gt;The High&lt;&#x2F;h3&gt;
&lt;p&gt;Both of these interactions gave us a ton of value and amped me up.  This completely made up for the feelings I had around the App Store rejection.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-second-app-store-response&quot;&gt;The Second App Store Response&lt;&#x2F;h2&gt;
&lt;p&gt;Back to Apple — we decided to try and get clarification. So, Matt and Adam put together a response to Apple.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there a way that we can get clarification on this rejection? Our app provides a significantly better experience than Safari, because it stores your GitHub credentials so that you can have a persistent and live-updating view of pull requests in your GitHub account on your desktop, without having to open a browser and log into your account.&lt;&#x2F;p&gt;
&lt;p&gt;This view of pull requests isn’t available anywhere on the web today and having it persistently available via a desktop app provides unique value that you couldn’t create with just a web site. To do this in Safari would require going into each team in Github and going to each repository for each team to see what Pull Requests are open. This is a massive headache for a developer that is working in multiple teams with multiple repos per team.&lt;&#x2F;p&gt;
&lt;p&gt;Happy to get on a call with you guys and walk you through how it works and what our roadmap is for enhancements to the desktop experience.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Apple came back with the following response:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;4.2 Design: Minimum Functionality (macOS)&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Hello,&lt;&#x2F;p&gt;
&lt;p&gt;Thank you for your response. It would be appropriate to add native macOS functionality to be appropriate for the App Store.&lt;&#x2F;p&gt;
&lt;p&gt;Regards,&lt;&#x2F;p&gt;
&lt;p&gt;App Store Review&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;h2 id=&quot;what-s-next&quot;&gt;What’s Next?&lt;&#x2F;h2&gt;
&lt;p&gt;Well, Apple&#x27;s response didn&#x27;t give us much to go on. So, we just need to put some thought into what “macOS Features” we can easily add (and that make sense), then submit to the App Store again.&lt;&#x2F;p&gt;
&lt;p&gt;Meanwhile, we continue to tell more people about the &lt;strong&gt;Minimum Free Version,&lt;&#x2F;strong&gt; collect feedback, and iterate along. From this initial round of feedback, we&#x27;ve identified a few tasks:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;add pull requests for External Collaborator repositories to the feed&lt;&#x2F;li&gt;
&lt;li&gt;add support for joining a mailing list in the Account Preferences&lt;&#x2F;li&gt;
&lt;li&gt;add processing of pagination to GitHub API requests&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;From the App Store rejection we&#x27;re planning to:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;review the App Store messaging and see if we can communicate the value better&lt;&#x2F;li&gt;
&lt;li&gt;figure out what native macOS features we think make sense to add in order to get it approved for the App Store&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Overall, I feel very confident that the decision to release the app outside of the App Store this early in its lifespan was one of the best things we could have done. The feedback is invaluable and each iteration we make improves the app. In retrospect this really cost about a day&#x27;s worth of work to research (and implement) the proper way to package and release the app outside of the store. In the scheme of things, a relatively small price to pay for the feedback we obtained in the first round.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Create macOS SideBar in Swift</title>
        <published>2019-01-10T00:00:00+00:00</published>
        <updated>2019-01-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/create-macos-sidebar-in-swift/"/>
        <id>https://drewdeponte.com/blog/create-macos-sidebar-in-swift/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/create-macos-sidebar-in-swift/">&lt;p&gt;Last night I started digging into building a SideBar for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pullwalla.com&quot;&gt;Pra&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;create-macos-sidebar-in-swift&#x2F;finder-screenshot.png&quot; alt=&quot;Finder Screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Sadly, I struggled to find a decent example of how to programmatically create a SideBar in Swift for macOS.&lt;&#x2F;p&gt;
&lt;p&gt;After a little bit of trial and error the following is the working solution I came up with.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Cocoa&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;extension&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; NSSplitViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;  convenience init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;sideBarViewController&lt;&#x2F;span&gt;&lt;span&gt;: NSViewController, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;contentViewController&lt;&#x2F;span&gt;&lt;span&gt;: NSViewController) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;nibName&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; sideBarSplitViewItem &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSSplitViewItem&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;sidebarWithViewController&lt;&#x2F;span&gt;&lt;span&gt;: sideBarViewController)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    let&lt;&#x2F;span&gt;&lt;span&gt; contentSplitViewItem &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSSplitViewItem&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;viewController&lt;&#x2F;span&gt;&lt;span&gt;: contentViewController)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addSplitViewItem&lt;&#x2F;span&gt;&lt;span&gt;(sideBarSplitViewItem)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;    self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addSplitViewItem&lt;&#x2F;span&gt;&lt;span&gt;(contentSplitViewItem)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;create-macos-sidebar-in-swift&#x2F;pra-with-sidebar.png&quot; alt=&quot;Pra with SideBar&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pra: Status Update 001</title>
        <published>2019-01-07T00:00:00+00:00</published>
        <updated>2019-01-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pra-status-update-001/"/>
        <id>https://drewdeponte.com/blog/pra-status-update-001/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pra-status-update-001/">&lt;p&gt;This is the first status update of the Pra macOS application. I figured what better time to do this than right after 2018 ends and 2019 begins. My goal with this is to give you an idea of where I am with the development, give you some insight into the things I am doing and some of the decisions I am making along the way. If you would like a more real-time feed of what is happening and want to provide feedback you can always follow me on Twitter &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;drewdeponte&quot;&gt;@drewdeponte&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;initial-setup&quot;&gt;Initial Setup&lt;&#x2F;h2&gt;
&lt;p&gt;The first step I took with this application was to start a basic macOS application. Immediately following that I:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;replaced all the Interface Builder xib stuff with straight up source code because I prefer to develop apps without Interface Builder or xibs&lt;&#x2F;li&gt;
&lt;li&gt;built out the Main Menu, Main Window, Preferences Window, and the Preferences Window’s tab interface&lt;&#x2F;li&gt;
&lt;li&gt;built out the Account Management Interface&lt;&#x2F;li&gt;
&lt;li&gt;built out Main Window for Pull Request list&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Building out the basic skeleton of App in terms of flow is part of the outside-in approach I like to take when developing applications.&lt;&#x2F;p&gt;
&lt;figure&gt;
	&lt;img src=&quot;basic_skeleton_of_app.png&quot; alt=&quot;Pra Basic Skeleton&quot; style=&quot;&quot; class=&quot;img-fluid&quot;&gt;
	&lt;figcaption&gt;Basic App Skeleton&lt;&#x2F;figcaption&gt;	
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;making-account-management-real&quot;&gt;Making Account Management Real&lt;&#x2F;h2&gt;
&lt;p&gt;Once I had the skeleton of the macOS App together in terms of windows, etc. It was time to make adding GitHub accounts and the persistence of them and their associated API keys a thing. I also built out a very basic stubbed out pull request list view in the main window as I knew that the next step would be to actually add fetching and displaying of pull requests.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; I decided to implement GitHub integration initially because it is what I primarily use and I believe it has the largest user base.&lt;&#x2F;p&gt;
&lt;figure&gt;
	&lt;img src=&quot;stubbed_pull_request_list_and_account_management.png&quot; alt=&quot;Pra Stubbed Pull Request List &amp; Account Management&quot; style=&quot;&quot; class=&quot;img-fluid&quot;&gt;
	&lt;figcaption&gt;Now with some content&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;div class=&quot;row&quot;&gt;
	&lt;figure class=&quot;col&quot;&gt;
		&lt;img src=&quot;add_account_sheet.png&quot; alt=&quot;Add Account Sheet&quot; style=&quot;&quot; class=&quot;img-fluid&quot;&gt;
		&lt;figcaption&gt;Account selection&lt;&#x2F;figcaption&gt;
	&lt;&#x2F;figure&gt;
	&lt;figure class=&quot;col&quot;&gt;
		&lt;img src=&quot;github_oauth_screen.png&quot; alt=&quot;GitHub OAuth Screen&quot; style=&quot;&quot; class=&quot;img-fluid&quot;&gt;
		&lt;figcaption&gt;Real GitHub integration&lt;&#x2F;figcaption&gt;
	&lt;&#x2F;figure&gt;
&lt;&#x2F;div&gt;
&lt;h2 id=&quot;making-pull-requests-real&quot;&gt;Making Pull Requests Real&lt;&#x2F;h2&gt;
&lt;p&gt;After adding basic Account Management I proceeded to drive toward making it so the App could fetch, present, and support basic interaction with Pull Requests. My goal with this phase of development was to get the minimal aggregation functional, interaction and UI implemented so that we could try it out and see if we felt it was functional at all in this rough state.&lt;&#x2F;p&gt;
&lt;p&gt;So, I implemented the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Fetching &amp;amp; aggregating Pull Requests from accounts&lt;&#x2F;li&gt;
&lt;li&gt;Scheduling of Pull Requests refresh at 5 mins&lt;&#x2F;li&gt;
&lt;li&gt;Open Pull Request by double clicking&lt;&#x2F;li&gt;
&lt;li&gt;Refresh Pull Requests on account addition&#x2F;removal so user doesn’t have to wait ~5 mins after adding an account to see their PRs&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
	&lt;img src=&quot;initial_pull_request_list_and_account_management.png&quot; alt=&quot;Initial Pull Request List &amp; Account Management&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;The most basic list of pull requests&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;making-things-functional-round-1&quot;&gt;Making Things Functional - Round 1&lt;&#x2F;h2&gt;
&lt;p&gt;At this point I distributed it to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;Ryan_Hedges&quot;&gt;Ryan&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mdnew&#x2F;&quot;&gt;Matt&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;adamkorman&quot;&gt;Adam&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;cciocan&quot;&gt;Claude&lt;&#x2F;a&gt; so they could start running it to see how functional&#x2F;useful it was at this point. We decided that it was functional, supporting our theory that we believe there is value in this App. However, there were some immediate things that we thought would make it easily more valuable. So, I added:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Displaying Repository name into the pull request list&lt;&#x2F;li&gt;
&lt;li&gt;Ability to ignore Pull Requests from repositories by right clicking on a pull request and selecting &lt;em&gt;ignore repository&lt;&#x2F;em&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Adding organization, description &amp;amp; avatar to Pull Request list - &lt;em&gt;Note:&lt;&#x2F;em&gt; I did this without caching of avatar images, etc. so that I could get feedback quicker, with and with less investment.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;figure&gt;
	&lt;img src=&quot;non_markdown_pull_request_list_and_repository_ignores.png&quot; alt=&quot;Non-Markdown Pull Request List &amp; Repository Ignores&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;It&#x27;s starting to look like a real app now&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;some-polish-round-1&quot;&gt;Some Polish - Round 1&lt;&#x2F;h2&gt;
&lt;p&gt;I sent the latest build to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;Ryan_Hedges&quot;&gt;Ryan&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mdnew&#x2F;&quot;&gt;Matt&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;adamkorman&quot;&gt;Adam&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;cciocan&quot;&gt;Claude&lt;&#x2F;a&gt; and we started using it again. After a day or so of use the feedback was pretty unanimous. The added features aided significantly and we felt we were on the right path.  However, we did identify a number of small things that just didn’t make it feel polished enough or didn’t make it feel like a real product. I like to tackle these types of issues as I develop an application for two main reasons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;it is a pain to have to worry about them all at the end&lt;&#x2F;li&gt;
&lt;li&gt;it is hard sometimes to not have feedback swayed by some of these polish things&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This lead me to start designing an icon for the App. It is weird how much of mental game not having an icon for your App is. But, once you have one (even if it isn’t the greatest final version) it does a huge amount to make you feel like you are moving forward and that your app is becoming a real thing. So, I designed the first draft of the icon. I took ideas from both the Pull Request Icon that GitHub uses and the Git logo, threw them in a blender and came up with the following to get started.&lt;&#x2F;p&gt;
&lt;figure&gt;
	&lt;img src=&quot;pra_icon_first_draft.jpg&quot; alt=&quot;Pra Icon First Draft&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;App icon, v1&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I also added Microsoft App Center integration for Analytics Tracking and Crash reporting. These are crucial as a feedback mechanism as I distribute the app internally and as I prepare to distribute the free version publicly.&lt;&#x2F;p&gt;
&lt;p&gt;Beyond that, I made cut, copy, paste, undo &amp;amp; redo work. This was especially important in the OAuth WebView because when you would try to fill out the OAuth form you were not able to paste your password from a password manager. Extremely annoying to say the least. So I had to fix that one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;adamkorman&quot;&gt;Adam Korman&lt;&#x2F;a&gt; had some time to catch up with me and work off of the various draft variations of the app icon I did, this time taking Apple macOS App Icon guidelines into account (which I completely ignored, whoops) and we ended up with the second draft of the Pra macOS App Icon.&lt;&#x2F;p&gt;
&lt;figure&gt;
	&lt;img src=&quot;pra_icon_second_draft.jpg&quot; alt=&quot;Pra Icon Second Draft&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;App icon, v2&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;making-things-functional-round-2&quot;&gt;Making Things Functional Round 2&lt;&#x2F;h2&gt;
&lt;p&gt;After adding some polish and sharing the build with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;Ryan_Hedges&quot;&gt;Ryan&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;mdnew&#x2F;&quot;&gt;Matt&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;adamkorman&quot;&gt;Adam&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;cciocan&quot;&gt;Claude&lt;&#x2F;a&gt; and using the app for a bit we quickly identified a few other changes that we thought would help improve the value of the core functionality.&lt;&#x2F;p&gt;
&lt;p&gt;So I added assignees to the Pull Request view when they exist for a given Pull Request. This gives people the ability to quickly determine from the list of Pull Requests which PRs have assignees and who they are. This aids with the user deciding if it is a PR they need to review and provide input on or not.&lt;&#x2F;p&gt;
&lt;figure class=&quot;dropshaddow-screenshot&quot;&gt;
	&lt;img src=&quot;non_markdown_pull_request_list_with_assignees.png&quot; alt=&quot;Pra Non-Markdown Pull Request List with Assignees&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;More polish&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;p&gt;I also added Pull Request body Markdown rendering. I did this for two reasons.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the bodies of GitHub pull requests are often written in Markdown as GitHub supports Markdown rendering.&lt;&#x2F;li&gt;
&lt;li&gt;the Pull Request bodies were coming back with hard breaks, and this made word wrapping look weird.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Markdown rendering allows us to interpret paragraphs, ignoring hard breaks, making word wrap work as expected as well as support Markdown formatting used in Pull Request bodies.&lt;&#x2F;p&gt;
&lt;figure class=&quot;dropshaddow-screenshot&quot;&gt;
	&lt;img src=&quot;markdown_pull_request_list.png&quot; alt=&quot;Markdown Pull Request List&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
	&lt;figcaption&gt;Now with Markdown rendering&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;We have been using the app in this state for a little bit now and have some more polish changes I need to make. For instance:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;use slightly smaller fonts&lt;&#x2F;li&gt;
&lt;li&gt;support dark mode&#x2F;light mode explicitly so that we have better control of color and theming&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I also have a number of features I need to add before I feel the initial free version will be ready:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;figure out a good in-app feedback mechanism and make sure people can trivially find it and know we want feedback (feedback is key to success)&lt;&#x2F;li&gt;
&lt;li&gt;add welcome tutorial that walks user through initial setup and educates them on how it is intended to be used&lt;&#x2F;li&gt;
&lt;li&gt;add buttons to the UI to support interactions with pull requests so that the interactions are more discoverable than mysterious right clicks, etc.&lt;&#x2F;li&gt;
&lt;li&gt;add relative time to the pull requests so the user can see how old PRs are&lt;&#x2F;li&gt;
&lt;li&gt;add avatar caching to make the app feel more responsive&lt;&#x2F;li&gt;
&lt;li&gt;restrict the account management to 1 account and provide in-app education about why user can only have 1 account in the free version&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Outside of that I have to do the following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;build out a landing page&lt;&#x2F;li&gt;
&lt;li&gt;get our Privacy Policy together&lt;&#x2F;li&gt;
&lt;li&gt;get our Support page together&lt;&#x2F;li&gt;
&lt;li&gt;write up all the App Store marketing material&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This will get us to an initial App Store launch at which point we can start promoting the app and talking about the app to get more users and get more feedback while we start working on the premium tier of the application. At least that is the high level plan as of right now.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pra: Thinking about Money</title>
        <published>2018-12-19T00:00:00+00:00</published>
        <updated>2018-12-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pra-thinking-about-money/"/>
        <id>https://drewdeponte.com/blog/pra-thinking-about-money/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pra-thinking-about-money/">&lt;p&gt;While I am waiting to collect information from the &lt;a href=&quot;&#x2F;writing&#x2F;pull-request-notifications-an-anti-pattern&#x2F;&quot;&gt;survey&lt;&#x2F;a&gt;, I started thinking about how I could make money with Pra. I thought about it before at a high level. But now I have started thinking about it in more depth.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;expectations&quot;&gt;Expectations&lt;&#x2F;h2&gt;
&lt;p&gt;It is important to understand that my expectations aren&#x27;t that this product be some sort of unicorn. I share the mindset of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;pjrvs.com&quot;&gt;Paul Jarvis&lt;&#x2F;a&gt; — I want to build a successful, sustainable business rather than shoot for explosive growth — and we largely operate our current boutique consulting&#x2F;contracting business that way. Paul just launched a book titled &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;ofone.co&quot;&gt;Company of One&lt;&#x2F;a&gt; where he talks about this mindset. If I boil it down, my expectations for Pra are to be something that:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;actually helps people&lt;&#x2F;li&gt;
&lt;li&gt;I can be proud of&lt;&#x2F;li&gt;
&lt;li&gt;isn&#x27;t overly complex or requires massive amount of effort to develop&lt;&#x2F;li&gt;
&lt;li&gt;I can sell and make a relatively small amount of money from&lt;&#x2F;li&gt;
&lt;li&gt;I can use to provide content to start building an audience&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;how-do-i-make-money&quot;&gt;How Do I Make Money?&lt;&#x2F;h2&gt;
&lt;p&gt;After talking in depth about this with my co-workers, Ryan and Adam, it seems like I want to have a free tier that provides &quot;real&quot; value. Ideally I want people to find enough value in the free version that they use it over GitHub (or any of the other providers) directly and are willing to tell other people about it.&lt;&#x2F;p&gt;
&lt;p&gt;Then, to make money, I need to find compelling additional features that at least some people would be willing to pay for.&lt;&#x2F;p&gt;
&lt;p&gt;The natural organizational entities are &lt;em&gt;accounts&lt;&#x2F;em&gt;, &lt;em&gt;organizations&lt;&#x2F;em&gt;, and &lt;em&gt;repositories&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;stances&quot;&gt;Stances&lt;&#x2F;h3&gt;
&lt;p&gt;There are two main stances I have thought of related to this product that I could take:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Core Value Paywalled.&lt;&#x2F;strong&gt; - In this stance, I would provide a free version of the app that wouldn’t do any aggregation. For this to work, I think it would have to be an app that works similar to GitHub, where you get access to the repos belonging to a single account and the ability to click on one and see the pull request for that specific repository. I believe it would also need to have some additional (free) features that make it more useful than just using Github itself. Then, I would have a paywall gating access to the aggregation feature. I would then have to provide some sort of trial experience to let the user experience the value of aggregation. The concern with this stance is that it would reduce the number of people willing to try the product out because they are hit with a paywall&#x2F;trial right off the bat.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Core Value Free&lt;&#x2F;strong&gt; - In the &lt;em&gt;core value free&lt;&#x2F;em&gt; stance, I would provide the aggregation for free within a single account. Then the stuff behind the paywall would be &lt;em&gt;N&lt;&#x2F;em&gt; accounts, as well as the set of tertiary features that make the overall experience better. The high-level thinking about this strategy is that if it is valuable enough, I may be able to get a larger number of people using the free version (since they get the core value for free). I would then have a channel through paywalled tertiary features that I would communicate on a personal level about who I am, what our mission is, what they get, and talk about it in terms of supporting our mission. The thinking is I could get a much wider net of free users to build our following for communicating other maker tools, etc. in the future, and some subset of people will pay for a Pro version. The concern with this approach is that if I provide the core value for free, there&#x27;s less additional value (that people would pay for) in the Pro version.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;My current stance is that I am not 100% sure which route to take. My instinct is that I should take the &lt;em&gt;Core Value Free&lt;&#x2F;em&gt; stance as it facilitates growing a potentially larger following for other products in the future, and I can envision how to make it happen. Also, in the &lt;em&gt;Core Value Paywalled&lt;&#x2F;em&gt; stance I would potentially have to build out a larger more complicated version of the app prior to the paywall being a thing, as it wouldn’t make much sense for people to use it if it was a worse tool than what GitHub already provides.&lt;&#x2F;p&gt;
&lt;p&gt;The above leads us to the following questions:&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-i-charge-by-the-repository-and-limit-the-free-version-to-1-repo-or-maybe-some-fixed-number-of-repositories-like-3&quot;&gt;Do I charge by the repository and limit the free version to 1 repo, or maybe some fixed number of repositories like 3?&lt;&#x2F;h4&gt;
&lt;p&gt;After hashing it out I think the answer to this question is &lt;strong&gt;no&lt;&#x2F;strong&gt;. I don’t think it provides&#x2F;communicates&#x2F;shows the value of aggregation when it is limited to simply 3 repositories.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-i-charge-by-the-organization&quot;&gt;Do I charge by the organization?&lt;&#x2F;h4&gt;
&lt;p&gt;Well, I could. However, the largest use case of people are probably people that have one primary Organization (the org of the company they work for), and their personal organization. The question then becomes is there enough value of aggregation seen for them to then purchase a subscription just to get their personal org added in, or would they just deal with the annoyance? After talking about it with Adam and Ryan I think most people would just deal with the annoyance. So, the answer is no.&lt;&#x2F;p&gt;
&lt;p&gt;I also need to keep in mind that I want the largest possible group of people using and finding the free version valuable so that I can convince them to pay for even more great value.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;do-i-charge-for-multiple-accounts&quot;&gt;Do I charge for multiple accounts?&lt;&#x2F;h4&gt;
&lt;p&gt;Initially the thinking around this was that I charge for multiple accounts, as it is probably a niche subset of the market (consultants&#x2F;contractors). However, I know personal developers who have their personal repos in BitBucket and their company repos in GitHub. So, I am not sure where I net on this at the moment. It still needs some consideration.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;so-where-am-i&quot;&gt;So Where am I?&lt;&#x2F;h3&gt;
&lt;p&gt;If I don’t charge based on core organizing principles what do I charge for? Right now the thinking is that I would charge for features. For instance, provide some of the Quick Filters for free and some of them would require you to be a subscriber. I could also make the search functionality, keyboard shortcuts, enriched PRs, etc. paid features.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;principles-of-purchase&quot;&gt;Principles of Purchase&lt;&#x2F;h3&gt;
&lt;p&gt;One thing I don’t like is the complexity around purchases and nickel and diming people. So I think it should basically be two tiers:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Free – Roughly feature parity with seeing PRs in GitHub, with the added value of the aggregated views and some other nice to have features&lt;&#x2F;li&gt;
&lt;li&gt;Pro (probably a monthly subscription) - All The Features. I think that getting people to pay is as much about access to the features as it is finding supporters around our mission of helping makers, and who we are. So they aren’t just buying &lt;em&gt;a thing,&lt;&#x2F;em&gt; they are supporting a small boutique group of real people they can identify with.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;One thing I have talked about as a possible 3rd tier would be Enterprise, which would potentially get you integrations with GitHub Enterprise, etc. The thinking around this is some individuals might pay for it because they have become dependent on Pra and love it. But I think the real money with that is in group licensing to companies that use Enterprise GitHub, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;Although I don&#x27;t have all the answers, my instinct is still to take the &lt;strong&gt;Core Value Free&lt;&#x2F;strong&gt; stance. I do believe thinking through some of this prior to getting the results from the survey back is a good thing. It helps me look at the data I get back in ways I may not have looked at it originally. Hopefully, the results of the survey will help clarify answers to some of these questions.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Pull Request Notifications: an Anti-Pattern</title>
        <published>2018-12-11T00:00:00+00:00</published>
        <updated>2018-12-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/pull-request-notifications-an-anti-pattern/"/>
        <id>https://drewdeponte.com/blog/pull-request-notifications-an-anti-pattern/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/pull-request-notifications-an-anti-pattern/">&lt;p&gt;Back in 2013, I was lead of a software development team at ReachLocal, Inc. At the time we were using GitHub for open source projects and Atlassian Stash for our private Git repositories.&lt;&#x2F;p&gt;
&lt;p&gt;We required at least one reviewer to review each pull request before it could be merged into the mainline. We also generally didn’t assign specific people to pull requests as reviewers because we wanted to promote knowledge sharing throughout the company. So, people had to go grab a pull request or two every once in a while and review them.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;problems&quot;&gt;Problems&lt;&#x2F;h2&gt;
&lt;p&gt;Email notifications didn&#x27;t really work well in this scenario and they have a tendency to get lost in peoples’ inboxes. So naturally we progressed to annoying our teammates via our company chat system (Slack, now) until someone eventually reviewed the pull requests.&lt;&#x2F;p&gt;
&lt;p&gt;It didn’t take me long to realize that we had fallen into a communication anti-pattern — people didn’t need instant feedback on their pull requests. Also, the chat messages announcing pull requests ready for review generally got lost in the mix of the other chat messages, and the author would end up posting a message again and again to get peoples’ attention and hopefully get a review. This was also having the negative impact of breaking the developers on the team out of “deep work” and costing a huge amount in terms of context switching.&lt;&#x2F;p&gt;
&lt;p&gt;At the same time, we were having problems losing track of pull requests across a number of repositories (and across different Git repository management systems). This would happen all the time, as we had different repositories for various libraries, services, and micro-services we had built out for the systems my team was responsible for. Since the only way to proactively check for pull requests to review was to go to each individual repository and check the pull request tab, it&#x27;s not surprising that they would fall through the cracks.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;baby-step&quot;&gt;Baby Step&lt;&#x2F;h2&gt;
&lt;p&gt;The culmination of these problems drove me to try and come up with a solution. Something that would ideally &lt;strong&gt;show me all of the pull requests that I cared about seeing, none of the ones I didn’t, and exactly when I wanted to see them&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;As a developer, my natural tendency is to build a software application to solve my problems. So that is exactly what I did. I created an open source terminal based curses application in Ruby called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;pra&quot;&gt;pra&lt;&#x2F;a&gt; (Pull Request Aggregator).&lt;&#x2F;p&gt;
&lt;img src=&quot;pra-cli-screenshot.png&quot; alt=&quot;Pra cli&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
&lt;p&gt;This app was a great step in the right direction and many people continued to use it as we went on to work at other companies. But, it was definitely lacking in certain areas largely due to the limitations of curses. For instance, if it had GUI then it could provide more information in a more concise view as well as provide other functionality around viewing specific types of pull requests, etc.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;state-of-the-world&quot;&gt;State of the World&lt;&#x2F;h2&gt;
&lt;p&gt;Jump forward about 5 years to December 2018 and sadly not much has changed in the pull request world. On my front, I am the co-founder &amp;amp; co-owner of a very small (&lt;a href=&quot;&#x2F;about&quot;&gt;5 of us in total&lt;&#x2F;a&gt;) boutique Software Product, Design, and Development Consultancy, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; where our mission is to provide services and tools to Makers that help them bring their dreams to life.&lt;&#x2F;p&gt;
&lt;p&gt;The team here at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;uptechstudio.com&quot;&gt;Uptech Studio&lt;&#x2F;a&gt; was going through a list of potential products we could build. Looking at pull requests and the space around them, we still believe there is a gap in the workflows and the lack of tooling around them. Therefore we have decided to tackle this problem space. We believe building a GUI version of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;pra&quot;&gt;pra&lt;&#x2F;a&gt; is a great place to start and iterate from. Although we have envisioned a much more feature rich application that we think will solve other problems, we are approaching a point where we plan to release a free version that even in an early form would be useful and valuable. To get a taste, below is a snapshot of a very early, very rough internal build.&lt;&#x2F;p&gt;
&lt;img src=&quot;pra-macos-screenshot.png&quot; alt=&quot;Pra macOS&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
&lt;h2 id=&quot;the-future&quot;&gt;The Future&lt;&#x2F;h2&gt;
&lt;p&gt;Being a very small boutique (yet experienced) product, design, and development team, we know better than to just build something and hope that our vision is right. We need to vet our theories before we invest lots of time and money into making them a reality.&lt;&#x2F;p&gt;
&lt;p&gt;This is where you come in. I know it is a lot to ask, but we need help vetting some directions we are thinking about taking the product. So, we have put together a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;goo.gl&#x2F;forms&#x2F;otHy58AVGkRvbZMm1&quot;&gt;small single page survey&lt;&#x2F;a&gt; to help guide us on some of these decisions.&lt;&#x2F;p&gt;
&lt;div class=&quot;text-center my-4&quot;&gt;&lt;a class=&quot;btn btn-lg btn-outline-dark text-center&quot; href=&quot;https:&#x2F;&#x2F;goo.gl&#x2F;forms&#x2F;otHy58AVGkRvbZMm1&quot;&gt;Fill Out the Survey&lt;&#x2F;a&gt;&lt;&#x2F;div&gt;
&lt;p&gt;If you have read this and have experienced some of these issues and would value a product focused on solving problems in this space please provide your email below showing your support for this product. We promise we won’t spam you. We will provide you with details about launches, ask for feedback about certain features, and invite some of you to alpha or beta releases.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sizing and Optimizing Images for iOS</title>
        <published>2018-11-09T00:00:00+00:00</published>
        <updated>2018-11-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sizing-and-optimizing-images-for-ios/"/>
        <id>https://drewdeponte.com/blog/sizing-and-optimizing-images-for-ios/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sizing-and-optimizing-images-for-ios/">&lt;h2 id=&quot;why&quot;&gt;Why?&lt;&#x2F;h2&gt;
&lt;p&gt;Sizing and Optimizing images for iOS can have a huge impact on performance of your app and the overall user experience. Therefore, it is important to take the time to figure out the proper sizing for your images and to make sure that they get appropriately resized and optimized for your needs.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;understanding-your-constraints&quot;&gt;Understanding your constraints&lt;&#x2F;h2&gt;
&lt;p&gt;I like to start by figuring out the devices that I am interested in supporting. I was recently working on an app where we wanted to support the iPhone 6 all the way up to the latest iPhone Xs Max. So to figure out the sizes of the images I needed some context as to what size in points the screens on those devices are and at what resolution they get rendered. I use &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.paintcodeapp.com&#x2F;news&#x2F;ultimate-guide-to-iphone-resolutions&quot;&gt;The Ultimate Guide To iPhone Resolutions&lt;&#x2F;a&gt; all the time for this type of reference.&lt;&#x2F;p&gt;
&lt;p&gt;In this case since I am supporting iPhone 6 as the lowest size which is &lt;strong&gt;375 x 667&lt;&#x2F;strong&gt; points and the iPhone Xs Max as the largest size, &lt;strong&gt;414 x 896&lt;&#x2F;strong&gt; points. If you look at all the point sizes between that range of phones. There are really two different aspect ratios I need to support &lt;strong&gt;0.46&lt;&#x2F;strong&gt; for the iPhone Xs Max, iPhone Xr, iPhone X, iPhone Xs, and &lt;strong&gt;0.56&lt;&#x2F;strong&gt; for the iPhone 6+, 6s+, 7+, 8+, 6, 6s, 7, and 8.&lt;&#x2F;p&gt;
&lt;p&gt;This means that I am most likely going to have to do some cropping depending on which device the images are loaded on.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;image-space-in-points&quot;&gt;Image space in points&lt;&#x2F;h3&gt;
&lt;p&gt;Now that I have some context in terms of max size and min size. I need to figure out what the point size of the actual image space is going to be.
I approached this in this scenario by adding a log line to the app that logged point size of the frame of the image area.&lt;&#x2F;p&gt;
&lt;p&gt;For &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;itunes.apple.com&#x2F;us&#x2F;app&#x2F;odyssey-3d&#x2F;id1435538334?&amp;amp;mt=8&quot;&gt;this particular app&lt;&#x2F;a&gt; I am implementing a carousel of profile pics of people participating in the application. At the moment I had an iPhone X and a iPhone 7+ with me. So, I built the app and ran it on both the iPhone 7+ and the iPhone X to get the point size of the profile cards on those devices from the logs.&lt;&#x2F;p&gt;
&lt;br&#x2F;&gt;
&lt;table style=&quot;width: 300px;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;
      Device
    &lt;&#x2F;th&gt;
    &lt;th&gt;
      Size in Points
    &lt;&#x2F;th&gt;
    &lt;th&gt;
      Aspect Ratio
    &lt;&#x2F;th&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      iPhone 7+
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      254 x 416
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      0.61
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      iPhone X
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      215 x 434
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      0.49
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;br&#x2F;&gt;
&lt;p&gt;From there I could deduce what the point size of the Profile Card would be on the iPhone 6 and the iPhone Xs Max by looking at the difference in points between the screen sizes. For example the iPhone 6 screen size is &lt;strong&gt;375 x 667&lt;&#x2F;strong&gt; and the test device I had was an iPhone 7+ at &lt;strong&gt;414 x 736&lt;&#x2F;strong&gt; which is &lt;strong&gt;39&lt;&#x2F;strong&gt; points wider and &lt;strong&gt;69&lt;&#x2F;strong&gt; points taller. Knowing that, I can apply those difference to the iPhone 7+&#x27;s Profile card point size of &lt;strong&gt;254 x 416&lt;&#x2F;strong&gt; resulting in the Profile Card being &lt;strong&gt;215 x 347&lt;&#x2F;strong&gt; points on iPhone 6.&lt;&#x2F;p&gt;
&lt;p&gt;The same concept can be applied going from The iPhone X Profile Card point size to the iPhone Xs Max Profile Card point size. In this case the iPhone X Profile Card point size is &lt;strong&gt;215 x 434&lt;&#x2F;strong&gt; and the there is a difference of &lt;strong&gt;39 x 84&lt;&#x2F;strong&gt; between iPhone X and iPhone Xs Max point sizes. When applied this results in the Profile Card being &lt;strong&gt;254 x 518&lt;&#x2F;strong&gt; points on iPhone Xs Max.&lt;&#x2F;p&gt;
&lt;br&#x2F;&gt;
&lt;table style=&quot;width: 300px;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;
      Device
    &lt;&#x2F;th&gt;
    &lt;th&gt;
      Size in Points
    &lt;&#x2F;th&gt;
    &lt;th&gt;
      Aspect Ratio
    &lt;&#x2F;th&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      iPhone 6
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      215 x 347
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      0.619
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      iPhone Xs Max
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      254 x 518
    &lt;&#x2F;td&gt;
    &lt;td&gt;
      0.490
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;br&#x2F;&gt;
&lt;p&gt;All of that was to understand the point size dimensions of the smallest image and largest image spaces that I want to support and make sure they look beautiful. From this data I see one very important thing. The aspect ratios are not the same. This means that there is going to be some cropping happening.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;where-to-crop&quot;&gt;Where to crop&lt;&#x2F;h3&gt;
&lt;img src=&quot;head_cropped.png&quot; alt=&quot;Headshot Cropped&quot; style=&quot;height: 250px; float: right; border-radius: 12px; margin: 16px;&quot; &#x2F;&gt;
&lt;p&gt;In this case I was prepping these images for profile pictures of people and they were sending their headshots to us. Most of these headshots had one thing in common, the persons face was toward the top of the image and relatively centered horizontally. For this particular type of content it is safer to crop off the sides of the images generally, rather than cropping off the top as I don&#x27;t want an image to crop someones face.&lt;&#x2F;p&gt;
&lt;p&gt;If I were for example to make the size of the images match the largest devices height, on the smaller devices with the different aspect ratios peoples heads would get chopped off like you see in the example.&lt;&#x2F;p&gt;
&lt;img src=&quot;head_not_cropped.png&quot; alt=&quot;Headshot Not Cropped&quot; style=&quot;height: 250px; float: left; border-radius: 12px; margin: 16px;&quot; &#x2F;&gt;
&lt;p&gt;Because I don&#x27;t want to lose any of the tops of the images. I needed to use the smallest height and the widest width from our device extremes for the image. This covers me in all the sizes between and will make it so only the sides get cropped. Yes, it does mean that I have some upscaling happening on the larger devices. But, in this case we did this optimization and tested it and found the upscaling looks fine as it is relatively minimal.&lt;&#x2F;p&gt;
&lt;p&gt;In my case that meant that the image size in terms of points that I wanted to produce for these profile cards was:&lt;&#x2F;p&gt;
&lt;br&#x2F;&gt;
&lt;table style=&quot;width: 300px;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;
      Universal Image Size (points)
    &lt;&#x2F;th&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      (Longest Width) x (Shortest Height)
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      (iPhone Xs Max Width) x (iPhone 6 Height)
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;td&gt;
      254 x 347
    &lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
&lt;br&#x2F;&gt;
&lt;h3 id=&quot;getting-the-resolution-right&quot;&gt;Getting the Resolution Right&lt;&#x2F;h3&gt;
&lt;p&gt;Now that I have an understanding of the image space I need to worry about in points for the image. I need to figure out what size the actual image should be in pixels. Given that points are the representation in iOS land when you are developing and pixels are what points get translated into and rendered out to on the screen. We need to have an understanding of how these devices render pixels out. Luckily &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.paintcodeapp.com&#x2F;news&#x2F;ultimate-guide-to-iphone-resolutions&quot;&gt;The Ultimate Guide To iPhone Resolutions&lt;&#x2F;a&gt; provides this information for us as well.&lt;&#x2F;p&gt;
&lt;p&gt;If we look at the iPhone Xs Max we can see that it renders to the screen at &lt;strong&gt;3x&lt;&#x2F;strong&gt;. This means at a value of it&#x27;s screen&#x27;s point size multiplied by 3. The iPhone 6 on the other hand looks to only render at 2x. Meaning 2 times it&#x27;s point size. So, I am now presented with a choice. Option one, pick the 2x rendering of the iPhone 6. This would result in a pixel size of &lt;strong&gt;508 x 694&lt;&#x2F;strong&gt;. This size would leave a pretty big gap for the larger devices to fill with upscaling. The other option is to use 3x rendering of the iPhone Xs Max which would result in a pixel size of &lt;strong&gt;762 x 1041&lt;&#x2F;strong&gt;. This seems like a much more reasonable size for the larger devices and it will just be scaled down to fit on the smaller screen devices like the iPhone 6.&lt;&#x2F;p&gt;
&lt;p&gt;Therefore, I opted for the later option of a pixel size of &lt;strong&gt;762 x 1041&lt;&#x2F;strong&gt;. I took this size and added an extra 30 pixels to both the width and the height as I am planning on using some image techniques later on in the app that would require having that overage. So I really resulted in wanting images at &lt;strong&gt;792 x 1071&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;batch-scaling-images&quot;&gt;Batch Scaling Images&lt;&#x2F;h3&gt;
&lt;p&gt;Now, that the hard part of figuring out what the best size for the image is. The easy part can begin. I found this wonderful little app named &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;veprit.com&#x2F;resizesense&quot;&gt;Resize Sense&lt;&#x2F;a&gt;. It provides the ability to batch apply various transformations to images. In this particular case it will help me fit, scale, and crop the images that people sent me to the appropriate size. It is worth noting that it isn&#x27;t the most intuitive app but it does work well. So, experiment with it a bit and it will be well worth it.&lt;&#x2F;p&gt;
&lt;img src=&quot;resize_sense_main_screen.png&quot; alt=&quot;Resize Sense - Custom Preset&quot; class=&quot;img-fluid&quot; style=&quot;&quot; &#x2F;&gt;
&lt;p&gt;The first thing I did after launching the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;veprit.com&#x2F;resizesense&quot;&gt;Resize Sense&lt;&#x2F;a&gt; was to check out the &lt;strong&gt;Preferences&lt;&#x2F;strong&gt;. I quickly noticed that it has a &lt;strong&gt;Default image resolution:&lt;&#x2F;strong&gt; option which is defaulted to 300 pixels per inch. This got me wondering what the pixels per inch on the iPhones where. A little googling lead me to &lt;strong&gt;458&lt;&#x2F;strong&gt; pixels per inch so I updated that preference. I am not sure why this is a global setting. It seems like it should be a setting in the presets but I haven&#x27;t seen it in there so I just went with it as a global setting.&lt;&#x2F;p&gt;
&lt;img src=&quot;resize_sense_preferences.png&quot; alt=&quot;Resize Sense - Custom Preset&quot; class=&quot;img-fluid&quot; style=&quot;&quot; &#x2F;&gt;
&lt;p&gt;After that I discovered that I need to build what they call a Custom Preset. I did this by clicking the &lt;strong&gt;Manage Presets&lt;&#x2F;strong&gt; button and defining a preset as follows. &lt;em&gt;Note&lt;&#x2F;em&gt;: According to their documentation it is important that presets have unique names. You will notice that the pixel dimensions of the image preset are the same ones we determined above.&lt;&#x2F;p&gt;
&lt;img src=&quot;resize_sense_custom_preset.png&quot; alt=&quot;Resize Sense - Custom Preset&quot; class=&quot;img-fluid&quot; style=&quot;&quot; &#x2F;&gt;
&lt;p&gt;After creating the preset I needed to select it and click the &lt;strong&gt;Apply selected preset&lt;&#x2F;strong&gt; button which then moved it to the applied presents list. And then I went and selected the first batch of headshot images people sent me and dragged them into the lower right pane of the app and selected one of the images. This applied the transformations and showed me a preview of the resulting image in the upper right pane.&lt;&#x2F;p&gt;
&lt;img src=&quot;resize_sense_apply_preset_load_images.png&quot; alt=&quot;Resize Sense - Custom Preset&quot; class=&quot;img-fluid&quot; style=&quot;&quot; &#x2F;&gt;
&lt;p&gt;From there I simply selected &lt;strong&gt;Save All images&lt;&#x2F;strong&gt; from the &lt;strong&gt;File&lt;&#x2F;strong&gt; menu and selected a destination for the files, loaded the saving preset from the custom preset I made earlier and clicked &lt;strong&gt;Save images&lt;&#x2F;strong&gt;. This batch processes all the images I gave it and produced a resulting set of images that had been sized appropriately, cropped, etc.&lt;&#x2F;p&gt;
&lt;img src=&quot;resize_sense_save_all.png&quot; alt=&quot;Resize Sense - Custom Preset&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
&lt;p&gt;The only issue was that the JPEG image optimization in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;veprit.com&#x2F;resizesense&quot;&gt;Resize Sense&lt;&#x2F;a&gt; isn&#x27;t very good. This isn&#x27;t actually a huge problem as there is a community defacto standard that is used which is easy and we know is good. Therefore, I ran the batch scaling, etc. to output at 100% JPG quality as I knew that it would be optimized later.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimization&quot;&gt;Optimization&lt;&#x2F;h3&gt;
&lt;p&gt;Now, that I had a batch of appropriately sized images for the App&#x27;s Profile Pictures I wanted to compress and optimize them to try and reduce their file size even further. It is worth noting that when I started this process I was dealing with multi-megabyte file sizes for these images.  So, next I opened &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;imageoptim.com&#x2F;mac&quot;&gt;ImageOptim&lt;&#x2F;a&gt;, a wonderful little macOS application that is as simple as they come, and I configured the preferences to be as follows by clicking the little gear icon.&lt;&#x2F;p&gt;
&lt;img src=&quot;image_optim_preferences.png&quot; alt=&quot;ImageOptim - Preferencs&quot; style=&quot;&quot; class=&quot;img-fluid&quot; &#x2F;&gt;
&lt;p&gt;Then, I dragged all the image files that were output by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;veprit.com&#x2F;resizesense&quot;&gt;Resize Sense&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;imageoptim.com&#x2F;mac&quot;&gt;ImageOptim&lt;&#x2F;a&gt; did it&#x27;s thing and I ended up with great looking images that were now sub 100kb.&lt;&#x2F;p&gt;
&lt;p&gt;This is a huge game changer for the performance of the application as these images are downloaded over often slow cellular networks.&lt;&#x2F;p&gt;
&lt;p&gt;So, please make sure you take the time to properly figure out the right image sizes for your app and please optimize them.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Inline Links in Text in iOS Apps</title>
        <published>2018-10-19T00:00:00+00:00</published>
        <updated>2018-10-19T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/inline-links-in-text-in-ios-apps/"/>
        <id>https://drewdeponte.com/blog/inline-links-in-text-in-ios-apps/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/inline-links-in-text-in-ios-apps/">&lt;p&gt;Today, I was working on a client project. As usual a couple of  designers had done some high fidelity designs in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.sketchapp.com&quot;&gt;Sketch&lt;&#x2F;a&gt; that I was riffing off. In the designs on the Sign Up screen near the bottom there was the classic notice stating that by signing up you are agreeing to the &lt;strong&gt;User Agreement&lt;&#x2F;strong&gt; and &lt;strong&gt;Privacy Policy&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;img src=&quot;user_agreement_notice_screenshot.jpg&quot; alt=&quot;User Agreement Notice&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 50%;&quot; &#x2F;&gt;
&lt;p&gt;There are two interesting things about this. First and foremost the phrases &lt;strong&gt;User Agreement&lt;&#x2F;strong&gt; and &lt;strong&gt;Privacy Policy&lt;&#x2F;strong&gt; are visually called out using blue like they would be if they were anchor tags (a.k.a. links) in a website. Secondly, both these phrases are inline with other text. If I was doing this on a website this would be trivial as I would just put two anchor tags inline in a paragraph tag with the rest of  the text. However, on iOS things aren’t so straight forward.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;assumptions&quot;&gt;Assumptions&lt;&#x2F;h2&gt;
&lt;p&gt;My assumptions going into this were that I was going to have to somehow detect a tap on each of  those phrases and then present a new modal View Controller containing a web view that loads the &lt;strong&gt;User Agreement&lt;&#x2F;strong&gt; or &lt;strong&gt;Privacy Policy&lt;&#x2F;strong&gt; respectively.  I knew off hand how to do all of these things except for the detection of the phrases being tapped. Though, I did have enough knowledge to know that with some work it could be done.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;research&quot;&gt;Research&lt;&#x2F;h2&gt;
&lt;p&gt;I started out searching for “UILabel tappable text”. It led me to a variety of half baked attempts at solving this with code that seemed way more complicated then it should need to be in my mind. I am talking like 60+ line solutions. So, I kept digging and stumbled across a post referencing the existence of some sort of &lt;code&gt;NSAttributedString&lt;&#x2F;code&gt; link feature. I thought this was interesting but sadly the post did not give me much direction in terms of actually making it happens. So, I searched a bit more and found an example of applying the &lt;code&gt;NSAttributedString.Key.link&lt;&#x2F;code&gt; attribute to an &lt;code&gt;NSMutableAttributedString&lt;&#x2F;code&gt;. An example is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; attributedString &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSMutableAttributedString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;: “by signing up, you are agreeing to &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Float&lt;&#x2F;span&gt;&lt;span&gt;’s User Agreement and Privacy Policy.”)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;attributedString.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addAttribute&lt;&#x2F;span&gt;&lt;span&gt;(NSAttributeString.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Key&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;link&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: “https&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;example.com&#x2F;policy”, range: NSRange(location: 43, length: 14)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When I applied the above and then assigned it to the &lt;code&gt;UILabel&lt;&#x2F;code&gt; ‘s &lt;code&gt;attributedText&lt;&#x2F;code&gt; property I got excited because it resulted in the &lt;strong&gt;User Agreement&lt;&#x2F;strong&gt; phrase showing up as blue with an underline. This was close to what I wanted design wise and gave me hope that it might actually do a thing. Sadly, tapping on what I believed was a link had no impact. So, I dug further and tried a number of various properties on &lt;code&gt;UILabel&lt;&#x2F;code&gt; such as &lt;code&gt;isUserInteractionEnabled&lt;&#x2F;code&gt; but no luck.&lt;&#x2F;p&gt;
&lt;p&gt;After searching a bit more I stumbled upon an article that referenced further some delegate methods from &lt;code&gt;UITextViewDelegate&lt;&#x2F;code&gt; that people were using with the &lt;code&gt;NSAttributedString.Key.link&lt;&#x2F;code&gt; to handle opening them in a browser. This gave me a new path to explore.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;uitextview&quot;&gt;UITextView&lt;&#x2F;h2&gt;
&lt;p&gt;So, step one I converted my &lt;code&gt;UILabel&lt;&#x2F;code&gt; to a &lt;code&gt;UITextView&lt;&#x2F;code&gt;. When I initially did this the view was &lt;code&gt;UITextView&lt;&#x2F;code&gt; was not visible and inspecting the view I could see that there was layout constraint issues. So, I gave it a hard coded height using auto layout constraints. Magically, it was visible and the layout constraint issue went away. So, now I knew that it was not being sized based on it’s content. After a quick search I was able to find out it is because it has a &lt;code&gt;isScrollEnabled&lt;&#x2F;code&gt; property that is by default set to &lt;code&gt;true&lt;&#x2F;code&gt;. So, I flipped it to &lt;code&gt;false&lt;&#x2F;code&gt; and got rid of the explicit height constraint. Like magic it was there and visible just liked I wanted with the correct styling.&lt;&#x2F;p&gt;
&lt;p&gt;Next I attempted to tap the link. But, to my surprise the keyboard popped up. Of course that is because there is another property &lt;code&gt;isEditable&lt;&#x2F;code&gt; that is by default &lt;code&gt;true&lt;&#x2F;code&gt;. So, after flipping that to &lt;code&gt;false&lt;&#x2F;code&gt; when I tapped the link it actually opened Safari to the URL of the link.&lt;&#x2F;p&gt;
&lt;p&gt;Finally some success! At this point my &lt;code&gt;UITextView&lt;&#x2F;code&gt; was configured as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;textView.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isEditable&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;textView.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isScrollEnabled&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;textView.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; UIColor.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;clear&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;breaking-assumptions&quot;&gt;Breaking Assumptions&lt;&#x2F;h2&gt;
&lt;p&gt;At this point it was actually functioning though in a different fashion than I had originally assumed it would. This made me question my initial assumptions of the need for having a separate view be presented modally containing a web view that would load the content.&lt;&#x2F;p&gt;
&lt;p&gt;The default behavior I was seeing is actually pretty much inline with those concepts. It is basically modally presenting Safari with the content loaded in Safari. My immediate next thought was well how easy is it for the user to get back to the app where they left off in either scenario. In the separate view scenario they would have to hit a close button to dismiss the modal view and go back to the Sign Up view. In the Safari scenario the user simply hits the back to last app button in the upper left.&lt;&#x2F;p&gt;
&lt;p&gt;So, turns out that the default behavior experience feels great, is minimal effort and models how most apps on macOS handle links as well. At this point I am pretty confident this the ideal path and I am driving full force ahead.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;another-problem&quot;&gt;Another Problem&lt;&#x2F;h2&gt;
&lt;p&gt;Turns out there is one problem. I have been localizing this application up to this point using &lt;code&gt;NSLocalizedString&lt;&#x2F;code&gt;. Looking at the example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; attributedString &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSMutableAttributedString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;string&lt;&#x2F;span&gt;&lt;span&gt;: “by signing up, you are agreeing to &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Float&lt;&#x2F;span&gt;&lt;span&gt;’s User Agreement and Privacy Policy.”)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;attributedString.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addAttribute&lt;&#x2F;span&gt;&lt;span&gt;(NSAttributeString.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Key&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;link&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;value&lt;&#x2F;span&gt;&lt;span&gt;: “https&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&#x2F;&#x2F;example.com&#x2F;policy”, range: NSRange(location: 43, length: 14)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We are clearly coupling the link to a specific starting location and length within the string. So, sadly this breaks localization because different languages will have different starting locations and different lengths, and with some googling there is no built in way for localization to support &lt;code&gt;NSAttributedString&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;&#x2F;h2&gt;
&lt;p&gt;But, wait there is still hope. At least in my opinion the above linking strategy is by far the best solution I have been able to find. So, if your app does not need localization you can use it straight away. If on the other hand your app does need localization. Don’t worry I have an idea.&lt;&#x2F;p&gt;
&lt;p&gt;The thought is to actually use a subset of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;daringfireball.net&#x2F;projects&#x2F;markdown&#x2F;syntax&quot;&gt;Markdown&lt;&#x2F;a&gt; in the localized string content and then write a method that will fetch a &lt;code&gt;NSLocalizedString&lt;&#x2F;code&gt; and parse the subset of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;daringfireball.net&#x2F;projects&#x2F;markdown&#x2F;syntax&quot;&gt;Markdown&lt;&#x2F;a&gt; into an &lt;code&gt;NSAttributedString&lt;&#x2F;code&gt;. This would in theory resolve the localization issue and potentially give localization a decent bit more functionality in terms of representing text.&lt;&#x2F;p&gt;
&lt;p&gt;In fact this can trivially be done with existing Markdown parsing libraries such as &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;iwasrobbed&#x2F;Down&quot;&gt;iwasrobbed&#x2F;Down&lt;&#x2F;a&gt;. You could use it as follows to get your attributed string with links.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; down &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Down&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;markdownString&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSLocalizedString&lt;&#x2F;span&gt;&lt;span&gt;(“USER_AGREEMENT_NOTICE”, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;comment&lt;&#x2F;span&gt;&lt;span&gt;: “User Agreement Notice”))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; attributedString &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= try?&lt;&#x2F;span&gt;&lt;span&gt; down.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toAttributedString&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The only down side to this approach, at least with this Markdown library, is that the &lt;code&gt;NSAttributedString&lt;&#x2F;code&gt; it produces has the links styled with the &lt;code&gt;NSAttributedString.Key.link&lt;&#x2F;code&gt; attribute as well as the underline style. This makes it look different than the designs.  With a quick read of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;iwasrobbed&#x2F;Down&quot;&gt;iwasrobbed&#x2F;Down&lt;&#x2F;a&gt; README.md and some spelunking of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;iwasrobbed&#x2F;Down&#x2F;blob&#x2F;master&#x2F;Source&#x2F;Renderers&#x2F;DownAttributedStringRenderable.swift&quot;&gt;DownAttributedStringRenderable.swift&lt;&#x2F;a&gt; file I quickly discovered that the &lt;code&gt;toAttributedString()&lt;&#x2F;code&gt; method has a &lt;code&gt;toAttriubtedString(stylesheet:)&lt;&#x2F;code&gt; variant that allows passing a &lt;code&gt;String&lt;&#x2F;code&gt; of CSS in to control the styling. In my case this just meant that I need to remove the &lt;code&gt;text-decoration&lt;&#x2F;code&gt; on anchor tags.&lt;&#x2F;p&gt;
&lt;p&gt;I thought about making a library to support this. However, now that I have seen how trivial it is to implement I decided I would just implement a helper method to do this. The helper I now write looks as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; localizedMarkdownString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; key&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;comment&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; NSAttributedString&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span&gt; down &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; Down&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;markdownString&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; NSLocalizedString&lt;&#x2F;span&gt;&lt;span&gt;(key, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;comment&lt;&#x2F;span&gt;&lt;span&gt;: comment))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	return try?&lt;&#x2F;span&gt;&lt;span&gt; Down.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toAttributedString&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;stylesheet&lt;&#x2F;span&gt;&lt;span&gt;: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;a { text-decoration: none; }&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That’s it! Relish in the beauty of localized Markdown and &lt;code&gt;NSAttributedString&lt;&#x2F;code&gt; coming together so harmoniously to solve this problem.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Decided what to Build</title>
        <published>2018-03-11T00:00:00+00:00</published>
        <updated>2018-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/decided-what-to-build/"/>
        <id>https://drewdeponte.com/blog/decided-what-to-build/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/decided-what-to-build/">&lt;p&gt;We were struggling to sell one of our side projects &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;orangecal.com&quot;&gt;OrangeCal&lt;&#x2F;a&gt; while also selling our consulting services as they were for completely different audiences. So, we decided to build and sell products that fit with our clients (software product makers) in the hope that we would find some overlap in sales and at least streamline mental focus for us in terms of sales.&lt;&#x2F;p&gt;
&lt;p&gt;So we looked at the various product spikes we had created as side projects &#x2F; open source projects and laid them all out on the whiteboard and had a team discussion to weigh pros &amp;amp; cons of each one.&lt;&#x2F;p&gt;
&lt;p&gt;We ended up netting on building a product based on an open source project I built as a ruby command line tool called &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;pra&quot;&gt;Pra CLI&lt;&#x2F;a&gt; (Pull Request Aggregator). At the time it had approx &lt;strong&gt;15,419 downloads&lt;&#x2F;strong&gt;. We also knew that some of the developers on our teams at the last few companies had used it and others didn&#x27;t specifically because it was a command line tool.&lt;&#x2F;p&gt;
&lt;p&gt;So we decided that was enough interest for us to build a macOS Desktop MVP and see if we could get some traction with it. The plan was to essentially provide the same core functionality in a nice macOS Desktop app and solve some of the problems that prevented people from using the command line version. We figured we could expand on it with other features and figure out the paid product beyond that. I had written down a small list of possible features that the guys seemed to think were good. So, I started coding.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Commit and Tag Signing</title>
        <published>2017-08-04T00:00:00+00:00</published>
        <updated>2017-08-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-commit-and-tag-signing/"/>
        <id>https://drewdeponte.com/blog/git-commit-and-tag-signing/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-commit-and-tag-signing/">&lt;p&gt;I believe that there is a large gap in current development practices in terms of association of identity and source code. This is something that a large percentage of people have been ignoring for quite some time. I was one of those people until recently. I started asking myself the question: How hard would it be for someone to write code and claim me as the author, basically forging code in my name? I realized that it was as simple as someone setting their authorship email and name in their &lt;code&gt;.gitconfig&lt;&#x2F;code&gt; to the values of my email address and name.&lt;&#x2F;p&gt;
&lt;p&gt;The more I thought about this, the more it concerned me, and the more it seemed there must be a solution to this problem. This especially becomes a problem when you start talking about regulations around software development and the legal responsibility involved with software that is tightly coupled to human life and well-being, for example software in self-driving cars.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The Solution&lt;&#x2F;h2&gt;
&lt;p&gt;Coming from a security background, I knew that a digital signature could solve this problem. So, being familar with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt;, an encryption and digital signing tool that is often used to digitally sign and encrypt emails, I decided to search and see if &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; supported integration with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt;. Sure enough it does, specifically for signing commits and tags. Knowing this, the next step was to setup and configure my machine, which is running macOS Ventura Version 13.0.1.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-i-did-it&quot;&gt;How I Did It&lt;&#x2F;h2&gt;
&lt;p&gt;The following is a breakdown of the final set of steps I took to get &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; functioning together. It took me a number of tries to get to this point, as numerous articles didn&#x27;t seem to work for me with version 2.3.8 of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt;, which is what I am using. It is also probably worth mentionining that I am using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; version 2.38.1.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;install-dependencies&quot;&gt;Install Dependencies&lt;&#x2F;h3&gt;
&lt;p&gt;The first thing is to make sure that you have the necessary dependencies installed. I did this via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;brew.sh&quot;&gt;Homebrew&lt;&#x2F;a&gt;, and recommend the same.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew install gnupg pinentry-mac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above installs &lt;code&gt;gnupg&lt;&#x2F;code&gt; (a.k.a. &lt;code&gt;gpg&lt;&#x2F;code&gt;) the tool set for digital signing, and &lt;code&gt;pinentry-mac&lt;&#x2F;code&gt;, a tool to securely prompt and manage password&#x2F;pin entry.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gnupg-key-pair-generation&quot;&gt;GnuPG Key Pair Generation&lt;&#x2F;h3&gt;
&lt;p&gt;Once you have the dependencies installed, assuming you don&#x27;t have a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; key pair already, you need to create one. This is done by running the following command and following the on screen instructions.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg --gen-key&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, I recommend backing up your key pair. This is important, as you probably won&#x27;t want to create a new identity if you get a new computer. I recommend backing it up in a physically secured space, like a safe. Given the depth and size of debate around proper key management, I will simply point you to the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;csrc.nist.gov&#x2F;publications&#x2F;nistpubs&#x2F;800-57&#x2F;sp800-57_part1_rev3_general.pdf&quot;&gt;NIST Recommendation for Key Management&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The crucial thing is that you &lt;strong&gt;never ever&lt;&#x2F;strong&gt; share your private key, otherwise all this effort is pointless, as they would be able to forge your commits and tags.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;get-your-gpg-key-identifier&quot;&gt;Get your GPG Key Identifier&lt;&#x2F;h3&gt;
&lt;p&gt;Once you have your key, the next step is getting your key identifer. This is needed to configure &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; properly later.&lt;&#x2F;p&gt;
&lt;p&gt;The key id is actually a component of the fingerprent of the public key certificate, the thing holding all your subkeys and meta data that are used for signing and encryption. Specifically, the &quot;Key ID&quot; (a.k.a. Long Key ID) is the last 16 characters of the fingerprint. You can get it by running the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg --fingerprint &amp;lt;email you tied to the key during generation&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output should look something like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pub   rsa2048 2017-07-28 [SC] [expires: 2019-07-28]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            678A A67F A701 CFA7 D666  BCE8 41C5 D2C6 E5AF 944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;uid           [ultimate] Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sub   rsa2048 2017-07-28 [E] [expires: 2019-07-28]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above output the following is the fingerprint:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;678A A67F A701 CFA7 D666  BCE8 41C5 D2C6 E5AF 944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The last 16 characters are:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;41C5 D2C6 E5AF 944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If you remove the spaces you have the Key ID, which you will need very shortly:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;41C5D2C6E5AF944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; It is ok to expose your fingerprint. It is part of the public key certificate and is something that you would share with someone to prove that the public key they have for you is actually your public key.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tell-git-about-your-gpg-key&quot;&gt;Tell Git about your GPG Key&lt;&#x2F;h3&gt;
&lt;p&gt;Next you need to tell &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; that you have a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; key and to use it to sign your commits and tags. This is done by running the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git config --global user.signingkey &amp;lt;your gpg key id&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git config --global commit.gpgsign true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git config --global tag.gpgsign true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;configure-gpg&quot;&gt;Configure GPG&lt;&#x2F;h3&gt;
&lt;p&gt;Then you need to configure &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; appropriately to work on macOS. In order to do this you need to create the &lt;code&gt;~&#x2F;.gnupg&#x2F;gpg-agent.conf&lt;&#x2F;code&gt; file, with the following content:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;pinentry-program &#x2F;usr&#x2F;local&#x2F;bin&#x2F;pinentry-mac&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The the above config tells &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; to work with the &lt;code&gt;pinentry-mac&lt;&#x2F;code&gt; program we installed at the beginning, allowing it to properly prompt us for the password when needed.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;testing-it-out&quot;&gt;Testing It Out&lt;&#x2F;h3&gt;
&lt;p&gt;Now that everything should be set up, you need to test it out and verify that everything is working properly. Below are the steps I took to create a test repository with an initial signed commit.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ mkdir -p &#x2F;tmp&#x2F;test-git-signing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ cd &#x2F;tmp&#x2F;test-git-signing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git init .&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ echo &amp;quot;Hello&amp;quot; &amp;gt; README.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git add README.md&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git commit -m &amp;quot;Initial signed commit&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will probably be prompted by &lt;code&gt;pinentry-mac&lt;&#x2F;code&gt; to enter your &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; key password. &lt;strong&gt;Note:&lt;&#x2F;strong&gt; You can check the box to have it store and manage your password in Apple Keychain. This will make it so you don&#x27;t have to enter your password all the time.&lt;&#x2F;p&gt;
&lt;p&gt;Now you can check out your signature in all it&#x27;s glory by doing the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git log --show-signature&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output should look something like this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;commit 1a5fed0757e2c8600318595f1681cf508033e72f (HEAD -&amp;gt; master)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg: Signature made Sat Aug  5 01:30:43 2017 PDT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg:                using RSA key 678AA67FA701CFA7D666BCE841C5D2C6E5AF944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg: Good signature from &amp;quot;Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&amp;quot; [ultimate]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Author: Andrew De Ponte &amp;lt;cyphactor@gmail.com&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Date:   Sat Aug 5 01:30:43 2017 -0700&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        Initial signed commit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above shows you that the commit is signed and that the signature is &lt;strong&gt;verified&lt;&#x2F;strong&gt;. If it was a commit by someone else and wasn&#x27;t verified, maybe because you didn&#x27;t have their verified public key in your &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; key ring, it would look something like the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg: Can&amp;#39;t check signature: public key not found&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;error: could not verify the tag &amp;#39;v1.4.2.1&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;great-so-how-does-this-help&quot;&gt;Great. So how does this help?&lt;&#x2F;h3&gt;
&lt;p&gt;This makes it possible for people to verify via cryptography that you are actually the person that authored the commit or tag. If they are signing their commits and tags it also allows you to do the same. In fact, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&quot;&gt;Git&lt;&#x2F;a&gt; even allows you to have it reject merges and pulls if the commits are &lt;strong&gt;not&lt;&#x2F;strong&gt; signed by a verified person. To see more details on this, check out the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;git-scm.com&#x2F;book&#x2F;en&#x2F;v2&#x2F;Git-Tools-Signing-Your-Work&quot;&gt;Git Tools Signing Your Work in the Git SCM Book&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;To really understand exactly how that is done you have to understand that you have two keys, a public key and a private key, and that they are related. You share, and generally publish, your public key. This is because the public key is used by others to do two things. First, to verify signatures you have made with your private key, and second, to encrypt information to make sure you are the only one that can access&#x2F;decrypt it using your private key.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;publish-your-public-key&quot;&gt;Publish Your Public Key&lt;&#x2F;h4&gt;
&lt;p&gt;You need to make sure that you have given people your public key, that you have the other collaborators&#x27; public keys, and that everyone has verified everyone&#x27;s public keys. To facilitate sharing public keys there are key servers you can publish your keys to. Beyond that, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&quot;&gt;GitHub&lt;&#x2F;a&gt; also provides a mechanism for publishing your &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; public keys as well. Just go to your Settings, SSH &amp;amp; GPG Keys, and add your GPG Public Key. You can also publish your public key to a key server using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; directly. The following is an example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gpg --send-keys 41C5D2C6E5AF944C&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gpg: sending key 41C5D2C6E5AF944C to hkps:&#x2F;&#x2F;hkps.pool.sks-keyservers.net&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; The major key servers share and sync the public keys so you shouldn&#x27;t have to worry about dealing with multiple key servers.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;verify-and-sign&quot;&gt;Verify and Sign&lt;&#x2F;h4&gt;
&lt;p&gt;Once you have published your key, you need to work with people to verify that the key they have actually belongs to you. This is often done at a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Key_signing_party&quot;&gt;Key Signing Party&lt;&#x2F;a&gt; to be the most secure. However, I have known many to verify their keys over the phone, as long as the people can answer questions proving they are who they say they are.&lt;&#x2F;p&gt;
&lt;p&gt;You can search for someone&#x27;s public keys via their email address on the key servers using the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gpg --search-keys &amp;lt;their email address&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After you find and import their public key, you need to verify it and sign it. To verify it you can have your own little signing party, or do it via phone if you are comfortable with that. Either way, the process of verification is the same. First ask the person for the fingerprint of their public key. Next verify that it matches the fingerprint of the public key you have for them. Remember, you can see the fingerprint of their key by doing, &lt;code&gt;gpg --fingerprint &amp;lt;their email address&amp;gt;&lt;&#x2F;code&gt;. Once you have verified they match, you can define your level of trust for them using the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gpg --edit-keys &amp;lt;their email address&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; trust&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For details around the different levels of trust and what they mean you can refer to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnupg.org&#x2F;gph&#x2F;en&#x2F;manual&#x2F;x334.html&quot;&gt;Trust in a key&#x27;s owner&lt;&#x2F;a&gt;. You can also fully sign a public key by doing the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ gpg --edit-keys &amp;lt;their email address&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; sign&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can find out more about validating keys in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnupg.org&#x2F;gph&#x2F;en&#x2F;manual&#x2F;x334.html&quot;&gt;GPG Manual - Validating other keys on your public keyring&lt;&#x2F;a&gt;. More information is also available on exchanging keys and signing keys in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.gnupg.org&#x2F;gph&#x2F;en&#x2F;manual&#x2F;x56.html&quot;&gt;GPG Manual - Exchanging keys&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;confusion&quot;&gt;Confusion&lt;&#x2F;h4&gt;
&lt;p&gt;I know this topic can be a little confusing at times. A few parts are still confusing for me when I haven&#x27;t dealt with them in a while. So, if you are confused with terms, or want a deeper understanding of the entities involved and their attributes with &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt;, I recommend checking out the article &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;davesteele.github.io&#x2F;gpg&#x2F;2014&#x2F;09&#x2F;20&#x2F;anatomy-of-a-gpg-key&#x2F;&quot;&gt;Anatomy of a GPG Key&lt;&#x2F;a&gt;. If you are confused about &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&quot;&gt;GPG&lt;&#x2F;a&gt; itself, they have decent &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;gnupg.org&#x2F;documentation&#x2F;&quot;&gt;documentation&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Once all of the above has been done you should be able to cryptographically verify and manage your source code with true identity representation and trust.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Remote Stand-ups at UpTech</title>
        <published>2017-07-10T00:00:00+00:00</published>
        <updated>2017-07-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/remote-standups-at-uptech/"/>
        <id>https://drewdeponte.com/blog/remote-standups-at-uptech/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/remote-standups-at-uptech/">&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;&#x2F;h3&gt;
&lt;p&gt;Given that UpTech is a consultancy, our team is often pretty fragmented in terms of physical location. For example, I might be on-site at a client&#x27;s office while another member is at a different client&#x27;s office, and yet other members are at our office. This physical fragmentation makes it difficult to stay on top of what is going on across the organization on a day-to-day basis.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;normal-solution&quot;&gt;Normal Solution&lt;&#x2F;h3&gt;
&lt;p&gt;Normally, in a startup we would have a stand-up every morning to kick-off the day. If you aren&#x27;t familiar, a stand-up is a time-boxed meeting that is used in many agile methodologies to facilitate communication around individuals&#x27; daily commitments, as well as raise awareness of any challenges (a.k.a.  blockers). The reason it is called a stand-up is because the thinking is that if everyone has to stand during the meeting it would help keep the meeting short. For further details on stand-ups and their intent check out the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.m.wikipedia.org&#x2F;wiki&#x2F;Stand-up_meeting&quot;&gt;Wikipedia page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;our-solution&quot;&gt;Our Solution&lt;&#x2F;h3&gt;
&lt;p&gt;Given that our team is rarely in the same physical location at the same time, we have taken the principles and intent from the stand-up and adapted it to our situation by using a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;slack.com&quot;&gt;Slack&lt;&#x2F;a&gt; &lt;code&gt;#standups&lt;&#x2F;code&gt; channel to share our commitments and blockers every morning at 10 am. To aid with making sure we have the stand-up right at 10am everyday, we set up a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;208423427-Set-a-reminder&quot;&gt;Slack reminder&lt;&#x2F;a&gt; in the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel.&lt;&#x2F;p&gt;
&lt;p&gt;Then in the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel we communicate the classic stand-up information: What did I do yesterday?, What am I doing today?, Do I have any blockers? Specifically, we use the following template and generally prepare the mornings stand-up in a text buffer before pasting it into the &lt;code&gt;#standups&lt;&#x2F;code&gt; channel. The template&#x2F;example below is based on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;202288908-Format-your-messages&quot;&gt;Slack message format&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_Tue July 11, 2017 - Standup_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Yesterday*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_1_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• One thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_2_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Yet another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Today*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_1_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Something else I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_client_2_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Blockers*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A blocker that is currently preventing me from accomplishing something or will in the near future&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;When the above is pasted into &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;slack.com&quot;&gt;Slack&lt;&#x2F;a&gt; it looks as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;remote-standups-at-uptech&#x2F;slack-screenshot.png&quot; alt=&quot;Slack Screenshot&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Given that this is such a core part of our process and that I am a heavy &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vim.org&quot;&gt;Vim&lt;&#x2F;a&gt; user, I created the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;vim-slack-format&quot;&gt;Vim Slack Format&lt;&#x2F;a&gt; plugin to provide syntax highlighting in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vim.org&quot;&gt;Vim&lt;&#x2F;a&gt; for the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;get.slack.help&#x2F;hc&#x2F;en-us&#x2F;articles&#x2F;202288908-Format-your-messages&quot;&gt;Slack message format&lt;&#x2F;a&gt;. When using this plugin it looks as follows:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;remote-standups-at-uptech&#x2F;vim-slack-format-screenshot.png&quot; alt=&quot;Vim Slack Format Screenshots&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Without this virtual stand-up every morning we wouldn&#x27;t be able to successfully run our business. It constantly triggers discussions, questions, suggestions, etc. following the stand-ups.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-you-can-use-this&quot;&gt;How you can use this?&lt;&#x2F;h3&gt;
&lt;p&gt;If you work for a consultancy yourself, you might find this solution and template above valuable for the same reasons we do. However, if instead you are simply on a remote team, where there aren&#x27;t multiple clients you could easily modify the format to the following simpler version and get the same value out of it.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;_Tue July 11, 2017 - Standup_&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Yesterday*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• One thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Yet another thing I did yesterday&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Today*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Something else I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• Another thing I am going to do today&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*Blockers*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;• A blocker that is currently preventing me from accomplishing something or will in the near future&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At the end of the day, like any tool&#x2F;process. It comes down to having an open minded collaborative team that understands the value of process and communication to really get the value out of a practice like this. Tools are never a solution for culture.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>RSpec Basics Screencast</title>
        <published>2017-02-04T00:00:00+00:00</published>
        <updated>2017-02-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/rspec-basics-screencast/"/>
        <id>https://drewdeponte.com/blog/rspec-basics-screencast/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/rspec-basics-screencast/">&lt;p&gt;This is yet another screencast I dug up while cleaning out some of the digital clutter. This one provides a great basic walk through of outside in development despite using a sligtly older version of RSpec. The biggest difference in RSpec versions at this point is the way expections are written. In this screencast it references the old style:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;Catalog&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;should_receive&lt;&#x2F;span&gt;&lt;span&gt;(:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;all&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The new style avoids implementations that require monkey patching. This now looks as follows.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;Catalog&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;to receive&lt;&#x2F;span&gt;&lt;span&gt;(:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;all&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Despite this small deviation this screencast is still extremly valuable and hopefully helps people get a grasp on outside in development and the basics of RSpec. You should be able to easily adjust for the difference by referencing the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;rspec&#x2F;rspec-expectations&quot;&gt;rspec-expectations&lt;&#x2F;a&gt; documentation.&lt;&#x2F;p&gt;
&lt;video controls=&quot;controls&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.m4v&quot; type=&quot;video&#x2F;mp4&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.ogv&quot; type=&quot;video&#x2F;ogg&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.mov&quot; type=&quot;video&#x2F;quicktime&quot;&gt;
  Your browser does not support the &lt;code&gt;video&lt;&#x2F;code&gt; element. Please upgrade&#x2F;switch to a more modern browser that does if you want to be able to view videos.
&lt;&#x2F;video&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.m4v&quot; class=&quot;btn btn-primary navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .m4v&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.ogv&quot; class=&quot;btn btn-success navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .ogv&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0003-rspec-basics.mov&quot; class=&quot;btn btn-info navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .mov&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this episode we reset the state of code to the point where in episode 2 we should have dropped down and fleshed out the RSpec tests for the controller. This episode covers the very basics of RSpec while we drive out a Rails controller action as part of the feature outlined in episode 2.&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Release Date&lt;&#x2F;th&gt;
    &lt;td&gt;2013-05-15&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Size&lt;&#x2F;th&gt;
    &lt;td&gt;79.7 MB&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Duration&lt;&#x2F;th&gt;
    &lt;td&gt;21 mins&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Resolution&lt;&#x2F;th&gt;
    &lt;td&gt;1920 x 1080&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Cucumber Basics Screencast</title>
        <published>2017-01-07T00:00:00+00:00</published>
        <updated>2017-01-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/cucumber-basics-screencast/"/>
        <id>https://drewdeponte.com/blog/cucumber-basics-screencast/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/cucumber-basics-screencast/">&lt;p&gt;This is another screencast I dug up while cleaning out some of the digital clutter in my life. This one still provides a great basic walk through of how to properly define acceptance tests and use them to drive out code with Cucumber.&lt;&#x2F;p&gt;
&lt;video controls=&quot;controls&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.m4v&quot; type=&quot;video&#x2F;mp4&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.ogv&quot; type=&quot;video&#x2F;ogg&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.mov&quot; type=&quot;video&#x2F;quicktime&quot;&gt;
  Your browser does not support the &lt;code&gt;video&lt;&#x2F;code&gt; element. Please upgrade&#x2F;switch to a more modern browser that does if you want to be able to view videos.
&lt;&#x2F;video&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.m4v&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .m4v&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.ogv&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .ogv&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0002-cucumber-basics.mov&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .mov&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this screencast I give a basic introduction to Cucumber — what Cucumber is and how to use it. I use a real-world example of adding the list screencasts feature to The Code Breakdown Rails app. I start out writing a Cucumber feature and explaining it, then dive into using that feature to drive out the implementation.&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Release Date&lt;&#x2F;th&gt;
    &lt;td&gt;2012-12-04&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Size&lt;&#x2F;th&gt;
    &lt;td&gt;33.6 MB&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Duration&lt;&#x2F;th&gt;
    &lt;td&gt;16 mins&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Resolution&lt;&#x2F;th&gt;
    &lt;td&gt;1920 x 1080&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Under the Hood Screencast</title>
        <published>2016-12-18T00:00:00+00:00</published>
        <updated>2016-12-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-under-the-hood-screencast/"/>
        <id>https://drewdeponte.com/blog/git-under-the-hood-screencast/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-under-the-hood-screencast/">&lt;p&gt;Back in 2013 I did a series of screencasts with a good friend of mine, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.linkedin.com&#x2F;in&#x2F;brimil01&quot;&gt;Brian
Miller&lt;&#x2F;a&gt;. I was going through things trying to remove some of the digital clutter and noise in my life. In the process I found this screencast and realized it is still very applicable today. Therefore, I figured I might as well share it.&lt;&#x2F;p&gt;
&lt;video controls=&quot;controls&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.m4v&quot; type=&quot;video&#x2F;mp4&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.ogv&quot; type=&quot;video&#x2F;ogg&quot;&gt;
  &lt;source src=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.mov&quot; type=&quot;video&#x2F;quicktime&quot;&gt;
  Your browser does not support the &lt;code&gt;video&lt;&#x2F;code&gt; element. Please upgrade&#x2F;switch to a more modern browser that does if you want to be able to view videos.
&lt;&#x2F;video&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.m4v&quot; class=&quot;btn btn-primary navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .m4v&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.ogv&quot; class=&quot;btn btn-success navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .ogv&lt;&#x2F;a&gt;
&lt;a href=&quot;&#x2F;&#x2F;media.upte.ch&#x2F;tcb-0010-git-part-1.mov&quot; class=&quot;btn btn-info navbar-btn&quot;&gt;&lt;i class=&quot;fa fa-download&quot;&gt;&lt;&#x2F;i&gt; .mov&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;In this episode, Brian and I cover the data structure behind git, what commits are really composed of, and how we think people should try and think when using Git. The hope is that this will help get people over one of the larger hurdles in the learning curve of Git.&lt;&#x2F;p&gt;
&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;Release Date&lt;&#x2F;th&gt;
    &lt;td&gt;2013-07-30&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Size&lt;&#x2F;th&gt;
    &lt;td&gt;189.9 MB&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Duration&lt;&#x2F;th&gt;
    &lt;td&gt;16 mins&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
  &lt;tr&gt;
    &lt;th&gt;Resolution&lt;&#x2F;th&gt;
    &lt;td&gt;1920 x 1080&lt;&#x2F;td&gt;
  &lt;&#x2F;tr&gt;
&lt;&#x2F;table&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a SegmentedViewController</title>
        <published>2016-12-16T00:00:00+00:00</published>
        <updated>2016-12-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/building-a-segmented-view-controller/"/>
        <id>https://drewdeponte.com/blog/building-a-segmented-view-controller/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/building-a-segmented-view-controller/">&lt;p&gt;Let&#x27;s say you run into a scenario where you need to build a mobile interface that has tabs at the top of the screen. If you are working on Android this isn&#x27;t too much of a problem as it is natively supported and part of their &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;material.io&#x2F;guidelines&#x2F;components&#x2F;tabs.html&quot;&gt;Material Design&lt;&#x2F;a&gt;. If you are building an iOS app it is a bit of a different story as the native &lt;code&gt;UITabBarController&lt;&#x2F;code&gt; doesn&#x27;t really work at the top of the screen. Yes, there are some nasty things you can do to hack it. But, we really shouldn&#x27;t be hacking things, should we? If we want to not run into crazy issues later and continue the hack, we should generally use the framework and systems as they were designed to be used.&lt;&#x2F;p&gt;
&lt;p&gt;If we dig into Apple&#x27;s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;ios&#x2F;human-interface-guidelines&#x2F;overview&#x2F;design-principles&#x2F;&quot;&gt;iOS Human Interface Guidelines&lt;&#x2F;a&gt;
the closest thing I can find to tabs at the top of the screen is in the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;ios&#x2F;human-interface-guidelines&#x2F;ui-bars&#x2F;navigation-bars&#x2F;&quot;&gt;UI Bars -&amp;gt; Navigation Bars&lt;&#x2F;a&gt; section.&lt;&#x2F;p&gt;
&lt;img src=&quot;nav_bar_segmented_control.png&quot; alt=&quot;Nav Bar Segmented Control&quot; style=&quot;width: 300px; float: left; margin: 40px 40px 40px 0px;&quot; &#x2F;&gt;
&lt;p&gt;Looking through the images you will find the image to the left and an explanation suggesting that you use &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt; in the navigation bar at the top to help flatten your information hierarchy.&lt;&#x2F;p&gt;
&lt;p&gt;So, how do we actually make something like this happen?&lt;&#x2F;p&gt;
&lt;p&gt;It turns out that constructing an instance of a &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt;, injecting it into the &lt;code&gt;UiNavigationBar&lt;&#x2F;code&gt;, and getting callbacks when the various segments are selected is pretty straight forward.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UISegmentedControl&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;: [&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;New&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Replied&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addTarget&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; #selector&lt;&#x2F;span&gt;&lt;span&gt;(segmentSelected), &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;valueChanged&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;yourViewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;navigationItem&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;titleView&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above constructs a &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt; with two segements, &lt;strong&gt;New&lt;&#x2F;strong&gt;, and &lt;strong&gt;Replied&lt;&#x2F;strong&gt;. It also selects &lt;strong&gt;New&lt;&#x2F;strong&gt;. &lt;em&gt;Note:&lt;&#x2F;em&gt; This is only a visual indication it doesn&#x27;t trigger any callbacks. Then we call &lt;code&gt;addTarget&lt;&#x2F;code&gt; to register an action to be called when the value of the segmented control changes. This is the spiked ground work for most of the components necessary. However, there is a lot more involved to have the &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt; trigger changing the views.&lt;&#x2F;p&gt;
&lt;p&gt;The intended approach for this is to use a concept Apple created called a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;content&#x2F;featuredarticles&#x2F;ViewControllerPGforiPhoneOS&#x2F;index.html#&#x2F;&#x2F;apple_ref&#x2F;doc&#x2F;uid&#x2F;TP40007457-CH2-SW1&quot;&gt;Container View Controller&lt;&#x2F;a&gt;. These are basically responsible for owning and managing a collection of view controllers and their associated views. Prime examples of these are &lt;code&gt;UITabBarController&lt;&#x2F;code&gt; and &lt;code&gt;UINavigationController&lt;&#x2F;code&gt;. Turns out none of the existing &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;content&#x2F;featuredarticles&#x2F;ViewControllerPGforiPhoneOS&#x2F;index.html#&#x2F;&#x2F;apple_ref&#x2F;doc&#x2F;uid&#x2F;TP40007457-CH2-SW1&quot;&gt;Container Controllers&lt;&#x2F;a&gt; do what we want. So, we will have to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;content&#x2F;featuredarticles&#x2F;ViewControllerPGforiPhoneOS&#x2F;ImplementingaContainerViewController.html#&#x2F;&#x2F;apple_ref&#x2F;doc&#x2F;uid&#x2F;TP40007457-CH11-SW1&quot;&gt;Implement a Container View Controller&lt;&#x2F;a&gt; of our own that takes care of owning&#x2F;managing the &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt;, the parenting view,and managing a collection of View Controllers and their paired Views that are coupled to each segment of the &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;walk-through&quot;&gt;Walk Through&lt;&#x2F;h2&gt;
&lt;p&gt;Given that we now have an understanding of the core components and concepts. Lets walk through implementing a rough initial version of our custom container view controller.&lt;&#x2F;p&gt;
&lt;p&gt;Let&#x27;s start by creating a class that inherits from &lt;code&gt;UIViewController&lt;&#x2F;code&gt; called &lt;code&gt;SegmentedViewController&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we know that the &lt;code&gt;SegmentedViewController&lt;&#x2F;code&gt; needs to manage a collection of view controllers as well as a segmented control. So, let&#x27;s create stored properties for both of those.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentViewControllers: [UIViewController]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl: UISegmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have properties to hold the managed values we need to initialize them. We do this by defining a constructor that takes &lt;code&gt;viewControllers: [UIViewController]&lt;&#x2F;code&gt; and assigns them to our stored property &lt;code&gt;self.segmentViewControllers&lt;&#x2F;code&gt;. &lt;em&gt;Note:&lt;&#x2F;em&gt; We also have to define the required constructor enforced by &lt;code&gt;UIViewController&lt;&#x2F;code&gt;. However, we don&#x27;t want to support compilation via that mechanism so we have it fatal error out.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentViewControllers: [UIViewController]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl: UISegmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; viewControllers&lt;&#x2F;span&gt;&lt;span&gt;: [UIViewController]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;nibName&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; viewControllers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; required init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;coder&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; aDecoder&lt;&#x2F;span&gt;&lt;span&gt;: NSCoder) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		fatalError&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;init(coder:) has not been implemented&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Given that we can now have an object that knows about a collection of view controllers to manage, we need to use those to set up our other stored property, the &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt;. We can do this by using the standard &lt;code&gt;viewDidLoad&lt;&#x2F;code&gt; method of the &lt;code&gt;UIViewController&lt;&#x2F;code&gt; and defining a couple more methods.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentViewControllers: [UIViewController]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl: UISegmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; viewControllers&lt;&#x2F;span&gt;&lt;span&gt;: [UIViewController]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;nibName&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; viewControllers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; required init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;coder&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; aDecoder&lt;&#x2F;span&gt;&lt;span&gt;: NSCoder) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		fatalError&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;init(coder:) has not been implemented&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; override func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UISegmentedControl&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addTarget&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; #selector&lt;&#x2F;span&gt;&lt;span&gt;(segmentSelected), &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;valueChanged&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;navigationItem&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;titleView&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		var&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;in self&lt;&#x2F;span&gt;&lt;span&gt;.segmentViewControllers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				if let&lt;&#x2F;span&gt;&lt;span&gt; title &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; viewController.title {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						segmentTitles.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(title)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentSelected&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentControl&lt;&#x2F;span&gt;&lt;span&gt;: UISegmentedControl) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above, we added in some of the basic ground work that we covered at the beginning of the article. Specifically, we constructed the &lt;code&gt;UISegemntedControl&lt;&#x2F;code&gt; and assigned it to our stored property, &lt;code&gt;self.segementedControl&lt;&#x2F;code&gt;. We marked the first segment as the active one, visually, and we added a target called &lt;code&gt;segmentSelected&lt;&#x2F;code&gt; when the value of the segmented control changes. The &lt;code&gt;segmentTitles&lt;&#x2F;code&gt; method is a simply helper method that extracts the standard &lt;code&gt;title&lt;&#x2F;code&gt; property from the injected view controllers. This allows us to easily use them when constructing the &lt;code&gt;UISegmentedControl&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to add the ability for it to display the first view controller, as we already configured the &lt;code&gt;self.segmentedControl&lt;&#x2F;code&gt; telling it that the first one is selected.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentViewControllers: [UIViewController]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl: UISegmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; viewControllers&lt;&#x2F;span&gt;&lt;span&gt;: [UIViewController]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;nibName&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; viewControllers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; required init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;coder&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; aDecoder&lt;&#x2F;span&gt;&lt;span&gt;: NSCoder) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		fatalError&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;init(coder:) has not been implemented&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; override func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UISegmentedControl&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addTarget&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; #selector&lt;&#x2F;span&gt;&lt;span&gt;(segmentSelected), &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;valueChanged&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		displaySegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;navigationItem&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;titleView&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		var&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;in self&lt;&#x2F;span&gt;&lt;span&gt;.segmentViewControllers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				if let&lt;&#x2F;span&gt;&lt;span&gt; title &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; viewController.title {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						segmentTitles.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(title)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentSelected&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentControl&lt;&#x2F;span&gt;&lt;span&gt;: UISegmentedControl) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; displaySegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentViewControllerIndex&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span&gt;[segmentViewControllerIndex]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addChildViewController&lt;&#x2F;span&gt;&lt;span&gt;(viewController)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addSubview&lt;&#x2F;span&gt;&lt;span&gt;(viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;translatesAutoresizingMaskIntoConstraints&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;right&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;right&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;bottom&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;bottom&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;didMove&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toParentViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In order to accomplish this, we added a &lt;code&gt;displaySegmentViewController&lt;&#x2F;code&gt; method that given a &lt;code&gt;segmentViewControllerIndex&lt;&#x2F;code&gt; appropriately displays and manages the lifecycle of the child view controller and its view.&lt;&#x2F;p&gt;
&lt;p&gt;Now we need to add support so that when a segement is selected it appropriately displays the selected segment&#x27;s view and hides the previously selected segment&#x27;s view.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentViewControllers: [UIViewController]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open var&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl: UISegmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate var&lt;&#x2F;span&gt;&lt;span&gt; lastDisplayedSegmentViewControllerIndex:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; viewControllers&lt;&#x2F;span&gt;&lt;span&gt;: [UIViewController]) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;nibName&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bundle&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; viewControllers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	public&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; required init&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;coder&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; aDecoder&lt;&#x2F;span&gt;&lt;span&gt;: NSCoder) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		fatalError&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;init(coder:) has not been implemented&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; override func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		super&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;viewDidLoad&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UISegmentedControl&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;items&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addTarget&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;action&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; #selector&lt;&#x2F;span&gt;&lt;span&gt;(segmentSelected), &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;valueChanged&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		displaySegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;navigationItem&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;titleView&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; = self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentedControl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentTitles&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;] {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		var&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles: [&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;String&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		for&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;in self&lt;&#x2F;span&gt;&lt;span&gt;.segmentViewControllers {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				if let&lt;&#x2F;span&gt;&lt;span&gt; title &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; viewController.title {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						segmentTitles.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;append&lt;&#x2F;span&gt;&lt;span&gt;(title)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return&lt;&#x2F;span&gt;&lt;span&gt; segmentTitles&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	open&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; segmentSelected&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentControl&lt;&#x2F;span&gt;&lt;span&gt;: UISegmentedControl) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		var&lt;&#x2F;span&gt;&lt;span&gt; lastDisplayedIndex:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Int&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;? =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		if let&lt;&#x2F;span&gt;&lt;span&gt; i &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= self&lt;&#x2F;span&gt;&lt;span&gt;.lastDisplayedSegmentViewControllerIndex {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				lastDisplayedIndex &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; i&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		displaySegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(segmentControl.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		if let&lt;&#x2F;span&gt;&lt;span&gt; j &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; lastDisplayedIndex {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				hideSegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(j)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; displaySegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentViewControllerIndex&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span&gt;[segmentViewControllerIndex]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addChildViewController&lt;&#x2F;span&gt;&lt;span&gt;(viewController)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;addSubview&lt;&#x2F;span&gt;&lt;span&gt;(viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;translatesAutoresizingMaskIntoConstraints&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;right&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;right&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		NSLayoutConstraint&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;: viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;bottom&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;relatedBy&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;equal&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toItem&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;attribute&lt;&#x2F;span&gt;&lt;span&gt;: .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;bottom&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;multiplier&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1.0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;constant&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.0&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;isActive&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;didMove&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toParentViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; self&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;lastDisplayedSegmentViewControllerIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; segmentedControl&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;selectedSegmentIndex&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	fileprivate&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; hideSegmentViewController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; segmentViewControllerIndex&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;Int&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; viewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;= self&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;segmentViewControllers&lt;&#x2F;span&gt;&lt;span&gt;[segmentViewControllerIndex]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;willMove&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toParentViewController&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; nil&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;removeFromSuperview&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		viewController.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;removeFromParentViewController&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To do this we added a fileprivate stored property called &lt;code&gt;lastDisplayedSegmentViewControllerIndex&lt;&#x2F;code&gt; to track the previously selected segment. This was useful when we fleshed out the &lt;code&gt;segmentSelected&lt;&#x2F;code&gt; method. We also updated the &lt;code&gt;displaySegmentViewController&lt;&#x2F;code&gt; method to update &lt;code&gt;lastDisplayedSegmentViewControllerIndex&lt;&#x2F;code&gt; with a new index after it has displayed the segment&#x27;s view. The details on the required lifecycle management of the child view controllers that we implemented in the &lt;code&gt;displaySegementViewController&lt;&#x2F;code&gt; and &lt;code&gt;hideSegmentViewConroller&lt;&#x2F;code&gt; were provided in &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;content&#x2F;featuredarticles&#x2F;ViewControllerPGforiPhoneOS&#x2F;ImplementingaContainerViewController.html#&#x2F;&#x2F;apple_ref&#x2F;doc&#x2F;uid&#x2F;TP40007457-CH11-SW1&quot;&gt;Implement a Container View Controller&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;This completes our initial implementation of our &lt;code&gt;SegmentedViewController&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;&#x2F;h2&gt;
&lt;p&gt;Let&#x27;s look at how we would use this thing now. The following is a simple &lt;code&gt;AppDelegate&lt;&#x2F;code&gt; that would use the &lt;code&gt;SegemntedViewController&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;swift&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;import&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; UIKit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;@&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;UIApplicationMain&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;class&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; AppDelegate&lt;&#x2F;span&gt;&lt;span&gt;:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; UIResponder&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt;UIApplicationDelegate&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;	var&lt;&#x2F;span&gt;&lt;span&gt; window: UIWindow&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;? =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UIWindow&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;frame&lt;&#x2F;span&gt;&lt;span&gt;: UIScreen.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;bounds&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	func&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; application&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;_&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; application&lt;&#x2F;span&gt;&lt;span&gt;: UIApplication, &lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;didFinishLaunchingWithOptions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; launchOptions&lt;&#x2F;span&gt;&lt;span&gt;: [UIApplicationLaunchOptionsKey:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Any&lt;&#x2F;span&gt;&lt;span&gt;]&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt; Bool&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; vcOrange &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		vcOrange.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Orange&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		vcOrange.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;orange&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; vcYellow &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UIViewController&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		vcYellow.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;title&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Yellow&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		vcYellow.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;view&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;backgroundColor&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;yellow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		let&lt;&#x2F;span&gt;&lt;span&gt; segmentedViewController &lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; SegmentedViewController&lt;&#x2F;span&gt;&lt;span&gt;([vcOrange, vcYellow])&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;rootViewController&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; UINavigationController&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;rootViewController&lt;&#x2F;span&gt;&lt;span&gt;: segmentedViewController)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		window&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;!&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;makeKeyAndVisible&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;		return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;img src=&quot;demo_segmented_view_controller.png&quot; alt=&quot;Demo Segmented View Controller&quot; style=&quot;display: block; margin-left: auto; margin-right: auto; width: 300px;&quot; &#x2F;&gt;
&lt;h2 id=&quot;that-s-it&quot;&gt;That&#x27;s It&lt;&#x2F;h2&gt;
&lt;p&gt;All in all it isn&#x27;t too bad. I hope you found this valuable and if you have any questions don&#x27;t hesitate to contact me. This is just a little more complex than I would want to have to deal with in an app code base. So, I will probably break this out into a framework soon.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>The UpDesk UpWrite</title>
        <published>2013-12-11T00:00:00+00:00</published>
        <updated>2013-12-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/updesk-upwrite-initial-setup/"/>
        <id>https://drewdeponte.com/blog/updesk-upwrite-initial-setup/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/updesk-upwrite-initial-setup/">&lt;h2 id=&quot;backstory&quot;&gt;Backstory&lt;&#x2F;h2&gt;
&lt;p&gt;Over the last few years I have been paying more and more attention to
ergonamics in my workspace. It all began when I started having issues with
my wrists and given I am a software developer I need my hands to work
properly. This sent me down a path of exploring ergonomic keyboards and
standing desks. I started trying out the cheaper ergonomic keyboards and
never had any luck. Enter the Kinesis Advantage Pro, I finally decided to drop
a chunk of change on it and I really haven&#x27;t looked back. My next exploration
will be the ErgoDox which I recently ordered all the parts for.&lt;&#x2F;p&gt;
&lt;p&gt;A little bit before I switched to the Kinesis Advantage Pro I switched to a
fixed height standing desk which I bought from Ikea for approx. $150. I have
been using the fixed height standing desk for over a year now and I love it.
However, the more research I do around the topic the more I have found that it
isn&#x27;t good to stand all day, which is what I currently do. Therefore, I
started looking into motorized standing&#x2F;sitting desks. After a lot of
research I finally decided on the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;myupdesk.com&#x2F;upwrite&quot;&gt;UpDesk
UpWrite&lt;&#x2F;a&gt;.  It is at the lower end of the price
range, $1,149.00, for motorized standing&#x2F;sitting desks but it has the specs of
a lot of the more expensive alternatives. It also has the added benefit that
it is a dry erase&#x2F;wet erase surface so you can scribble notes on it while
working.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-setup&quot;&gt;The Setup&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;putting-it-together&quot;&gt;Putting it Together&lt;&#x2F;h3&gt;
&lt;p&gt;My &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;myupdesk.com&#x2F;upwrite&quot;&gt;UpDesk UpWrite&lt;&#x2F;a&gt; arrived tonight and it was
actually very straightforward in terms of physical setup. The included
instruction sheet explained things very well. It is actually much simpler in
my opinion than most Ikea furniture. It probably took me 25 mins to get it
put together. I was extremely impressed with the quality of packaging and the
quality of the parts them selves. It seems to be an extremely solid piece of
furniture that will last a long time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initializing-and-calibrating&quot;&gt;Initializing and Calibrating&lt;&#x2F;h3&gt;
&lt;p&gt;Once I physically setup the desk I tried to initialize it and callibrate it.
Initializing the desk was very straightforward on their instruction sheet and
worked like a champ. Calibrating it on the other hand did not work following
the instructions they provide. The instructions for calibration that were
provided are as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;At any height, measure the distance from the floor to the top of the desk.&lt;&#x2F;li&gt;
&lt;li&gt;Press both the &quot;UP&quot; and &quot;DOWN&quot; arrows at the same time until the display
shows three bars (---).&lt;&#x2F;li&gt;
&lt;li&gt;Release and immediately set the correct height by pressing either the &quot;UP&quot;
or &quot;DOWN&quot; arrow until the correct height is displayed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I tried the above steps numerous times and every time I got to the third step
and pressed the &quot;UP&quot; or &quot;DOWN&quot; arrows to adjust the displayed height it would
also move the desk up or down which made no sense if the goal of the process
was to callibrate the height.&lt;&#x2F;p&gt;
&lt;p&gt;So, it took a little playing around but I finally figured out how to properly
callibrate it. The directions to calibrate it should really be as follows:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;At any height, measure the distance from the floor to the top of the desk.&lt;&#x2F;li&gt;
&lt;li&gt;Press and hold both the &quot;UP&quot; and &quot;DOWN&quot; arrows at the same time, the display
will immediately display three bars (---), continue to hold the &quot;UP&quot; and
&quot;DOWN&quot; arrows until the display flashes from (---) to the displayed height.&lt;&#x2F;li&gt;
&lt;li&gt;Release and immediately set the display to height you previously measured in
the first step by pressing either the &quot;UP&quot; or &quot;DOWN&quot; arrow until the correct
height is displayed.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;dialing-in-presets&quot;&gt;Dialing in Presets&lt;&#x2F;h3&gt;
&lt;p&gt;Once I had it all calibrated I followed the rest of the instructions to set
the presets to heights that I like for standing and sitting. All worked great.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;So far the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;myupdesk.com&#x2F;upwrite&quot;&gt;UpDesk UpWrite&lt;&#x2F;a&gt; seems like a great
desk. It was a little frustrating that the directions weren&#x27;t clear enough, or
rather just plain wrong, for how to calibrate it. However, I am willing to
look past that small hickup and I hope this blog aids others in getting their
desks calibrated quicker than I did.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Shrinking Vagrant Linux Boxes</title>
        <published>2013-10-29T00:00:00+00:00</published>
        <updated>2013-10-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/shrinking-vagrant-linux-boxes/"/>
        <id>https://drewdeponte.com/blog/shrinking-vagrant-linux-boxes/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/shrinking-vagrant-linux-boxes/">&lt;p&gt;So, lately I have been using Virtual Machines via
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vagrantup.com&#x2F;&quot;&gt;Vagrant&lt;&#x2F;a&gt; a siginificant amount as we are now using
them to host our development environments and dependencies for all the
development work we do. We have been using &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;puppetlabs.com&#x2F;&quot;&gt;Puppet&lt;&#x2F;a&gt; to
automate the configuration of our environments and to make building our boxes
easier.&lt;&#x2F;p&gt;
&lt;p&gt;Once you have provisioned a VM and you have it all dialed, you will most
likely want to create a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;boxes.html&quot;&gt;Vagrant Box&lt;&#x2F;a&gt;
from that VM and host it up on S3 so that new developers can get started
simply by installing &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vagrantup.com&#x2F;&quot;&gt;Vagrant&lt;&#x2F;a&gt;, cloning your
repository and running:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ vagrant up&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This actually works great. However, I found that the VM disks both for the
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;vmware&#x2F;index.html&quot;&gt;Vagrant VMware Provider&lt;&#x2F;a&gt; and
the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;virtualbox&#x2F;index.html&quot;&gt;VirtualBox Provider&lt;&#x2F;a&gt;
grow dynamically, but they never shrink. So, when I was going through the
process of building the VM and installing all the dependency software, etc. it
was bloating the base machine.  This was the case even though I removed the
temporary cruft from the filesystem on the guest.&lt;&#x2F;p&gt;
&lt;p&gt;With a little research and some trial and error I found that you can shrink
these disks as long as they are ext3 or ext4 file systems with the help of the
following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ vagrant ssh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ sudo dd if=&#x2F;dev&#x2F;zero of=wipefile bs=1024x1024; rm wipefile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What the above command is doing is simply writing zero bytes to the wipefile in
chunks of 1024 bytes until there is no disk space left in your VM&#x27;s disk. Then
it is removing the wipefile. This basically leaves all those excess bytes
zero&#x27;d out.&lt;&#x2F;p&gt;
&lt;p&gt;This is necessary because the shrink&#x2F;compaction tools provided by either
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vmware.com&#x2F;&quot;&gt;VMWare&lt;&#x2F;a&gt; or &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.virtualbox.org&#x2F;&quot;&gt;VirtualBox&lt;&#x2F;a&gt;
both have no way of identifying space they can free up in the disks unless
they are zero&#x27;d out.&lt;&#x2F;p&gt;
&lt;p&gt;Before shrinking&#x2F;compacting you should always make sure to exit the guest
machine using the following commands:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ vagrant halt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.vmware.com&#x2F;&quot;&gt;VMware&lt;&#x2F;a&gt; you can shrink the vmdk disk by doing
the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ vmware-vdiskmanager -d &#x2F;path&#x2F;to&#x2F;main.vmdk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ vmware-vdiskmanager -k &#x2F;path&#x2F;to&#x2F;main.vmdk&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I discovered the above commands in the Vagrant VMware documentation,
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;vmware&#x2F;boxes.html&quot;&gt;http:&#x2F;&#x2F;docs.vagrantup.com&#x2F;v2&#x2F;vmware&#x2F;boxes.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.virtualbox.org&quot;&gt;VirtualBox&lt;&#x2F;a&gt; the only way I was able to
shrink the disk image was to clone it to a smaller copy using the following
command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ VboxManage clonehd name-of-original-vm.vdi name-of-clone-vm.vdi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once you have cloned the vdi you can then import it into the VM through
VirtualBox and get rid of the original vdi.&lt;&#x2F;p&gt;
&lt;p&gt;That is how you &quot;Shrink Vagrant Linux Boxes!&quot;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>AT&amp;T Samsung Galaxy S3 with Google Voice</title>
        <published>2013-01-06T00:00:00+00:00</published>
        <updated>2013-01-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/att-samsung-galaxy-s3-with-google-voice/"/>
        <id>https://drewdeponte.com/blog/att-samsung-galaxy-s3-with-google-voice/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/att-samsung-galaxy-s3-with-google-voice/">&lt;p&gt;Hi All,&lt;&#x2F;p&gt;
&lt;p&gt;It seems there is a little hickup with the instructions google provides you
with to &quot;Activate Google voicemail no this phone&quot;. That is at least for the
instructions for AT&amp;amp;T while trying to get Google Voice setup on an AT&amp;amp;T Galaxy
S3. The instructions Google provides say to enter the following exactly as
written as if dialing someone.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;*004*1&amp;lt;your 10 digit phone number&amp;gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Every time I tried the above instructions my phone would return an error code.
I got so frustrated I even got online with AT&amp;amp;T tech support so that they
could verify the state of things as I was trying various other commands that I
found on the web. None, of the ones that worked allowed me to setup Google
Voice as my voicemail provider appropriately. After being online with AT&amp;amp;T
tech support for a while. I tried simply prepending another * character to the
entire thing. Guess what, magically it worked. I even had AT&amp;amp;T tech support
verify that it made the proper configuration change on my account. So the
correct command that Google should be telling people to enter exactly as
written is really the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;**004*1&amp;lt;your 10 digit phone number&amp;gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To disable voicemail forwarding I used the following MMI code.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;##004#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Anyways, hope this blog post helps some other people struggling with this out
there. I know when I was searching I couldn&#x27;t find any solution though I did
see a number of message boards with people looking for an answer to this
problem. If I were a better person I would probably go back and update all
those message boards with my solution. I just can&#x27;t bring myself to do it.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>RVM Installed Ruby (SSL certificate verify failed)</title>
        <published>2012-09-07T00:00:00+00:00</published>
        <updated>2012-09-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/rvm-installed-ruby-ssl-certificate-verify-failed/"/>
        <id>https://drewdeponte.com/blog/rvm-installed-ruby-ssl-certificate-verify-failed/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/rvm-installed-ruby-ssl-certificate-verify-failed/">&lt;p&gt;Recently a few of our developers were having problems getting SSL certificate verify
failures in Ruby. The error was the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;net&#x2F;http.rb:799:in `connect&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;net&#x2F;http.rb:799:in `block in connect&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;timeout.rb:54:in `timeout&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;timeout.rb:99:in `timeout&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;net&#x2F;http.rb:799:in `connect&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;net&#x2F;http.rb:755:in `do_start&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;net&#x2F;http.rb:744:in `start&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:306:in `open_http&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:775:in `buffer_open&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:203:in `block in open_loop&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:201:in `catch&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:201:in `open_loop&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:146:in `open_uri&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:677:in `open&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	from &#x2F;Users&#x2F;adeponte&#x2F;.rvm&#x2F;rubies&#x2F;ruby-1.9.3-p125&#x2F;lib&#x2F;ruby&#x2F;1.9.1&#x2F;open-uri.rb:33:in `open&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The error was reproducable by running the following Ruby snippet in an &lt;strong&gt;irb&lt;&#x2F;strong&gt;
instance of the RVM installed Ruby version.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;require&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;open-uri&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;open&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;https:&#x2F;&#x2F;google.com&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I spent a good amount of time digging into things and trying to figure out
exactly what the issue was. I came to the conclusion that they either had an
out of date Root CA Certificate Bundle or SSL couldn&#x27;t find it for some reason.
So, I went down the path of trying to import cacert.pem from
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;curl.haxx.se&#x2F;ca&#x2F;cacert.pem&quot;&gt;http:&#x2F;&#x2F;curl.haxx.se&#x2F;ca&#x2F;cacert.pem&lt;&#x2F;a&gt; (cURL&#x27;s
website).&lt;&#x2F;p&gt;
&lt;p&gt;I went down this path because I vaguely remember doing this at some point in
the past to solve the Twitter API SSL Verify fail issue when they changed their
certs.  I ran into a huge amount of difficulty trying to get the thing imported
or converted into a format that Mac OS X Keychain Access would be happy with
importing. I tried pem, crt, pck12, etc. Nothing I did seemed to make a
difference.&lt;&#x2F;p&gt;
&lt;p&gt;This is when I saw a post of someone talking about SSL being installed inside
of RVM and I looked at the latest output from &lt;code&gt;rvm requirements&lt;&#x2F;code&gt;.  I
quickly noticed that it now says to install SSL via the following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;rvm pkg install openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Come to find out if you have run the above command before installing your Ruby
version it will be using the RVM packaged openssl instead of the system
openssl. That also means that the Root CA Certificate Bundle is different, or
in this case, &lt;strong&gt;missing completely&lt;&#x2F;strong&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;After discovering this and doing a little googling I found the solution to be
as simple as the following command:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;curl http:&#x2F;&#x2F;curl.haxx.se&#x2F;ca&#x2F;cacert.pem -o ~&#x2F;.rvm&#x2F;usr&#x2F;ssl&#x2F;cert.pem&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I found this solution on the following blog post
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fredwu.me&#x2F;post&#x2F;28834446907&#x2F;fix-openssl-error-on-mountain-lion-and-rvm&quot;&gt;http:&#x2F;&#x2F;fredwu.me&#x2F;post&#x2F;28834446907&#x2F;fix-openssl-error-on-mountain-lion-and-rvm&lt;&#x2F;a&gt;.
Hopefully, writing another blog post on the subject and linking to this one
will help it gain its ranks in google search so that other people can find it
quicker.&lt;&#x2F;p&gt;
&lt;p&gt;After running the above command you should now be able to restart your &lt;strong&gt;irb&lt;&#x2F;strong&gt;
instance and re-run the test snippet described at the beginning of this post.
This time you should get output looking similar to the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt; #&amp;lt;File:&#x2F;var&#x2F;folders&#x2F;j_&#x2F;9nxyjmd10js8g1sjx446vrsm0000gn&#x2F;T&#x2F;open-uri20120907-36935-4i4y64&amp;gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Just like that your SSL woes are gone.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-08-07T00:00:00+00:00</published>
        <updated>2012-08-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-008/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-008/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-008/">&lt;p&gt;I woke up early this morning and thought it was time for a little
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&quot;&gt;sublime_guard&lt;&#x2F;a&gt; love. I went through
and tackled all of the syntax highlighting issues. This included the following
issues (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;27&quot;&gt;#27&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;30&quot;&gt;#30&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;31&quot;&gt;#31&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;38&quot;&gt;#38&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;43&quot;&gt;#43&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;29&quot;&gt;#29&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;I also cleaned up a number of tickets that were lying around and had either
been completed already or were tickets that were invalid.&lt;&#x2F;p&gt;
&lt;p&gt;I also started a branch for adding python3 support to the plugin. The branch is
named &lt;strong&gt;python3_support&lt;&#x2F;strong&gt;. I would love it if anyone out there in the ether
would grab that branch, test it out, and give me some feedback.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, I hope you guys enjoy the updates. As usual if you installed from
Package Control just restart Sublime Text 2. If you installed manually then
just pull the latest version down with Git.&lt;&#x2F;p&gt;
&lt;p&gt;See you all next time.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ruby and Rails Mountain Lion Hiccups</title>
        <published>2012-07-27T00:00:00+00:00</published>
        <updated>2012-07-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/ruby-and-rails-mountain-lion-hiccups/"/>
        <id>https://drewdeponte.com/blog/ruby-and-rails-mountain-lion-hiccups/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/ruby-and-rails-mountain-lion-hiccups/">&lt;p&gt;So when Mac OS X Mountain Lion was released a few days ago I jumped on
upgrading and got switched over as soon as I could. My mentality for upgrading
is that I would much rather deal with the pain of upgrading in smaller chunks
when needed rather than waiting. Plus, I just like to be on the latest and
greatest in terms of the tools I use for my job.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, below is going to be a listing of some of the hiccups that either I or
other developers on my team have run into in terms of their Ruby and Rails
development environment setups.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;git&quot;&gt;Git&lt;&#x2F;h2&gt;
&lt;p&gt;Some of the devs on my team had Git installed via the
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;git-osx-installer&#x2F;&quot;&gt;git-osx-installer&lt;&#x2F;a&gt;. These
developers seemed to lose their Git installs when they upgraded. I was using a
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mxcl.github.com&#x2F;homebrew&#x2F;&quot;&gt;Homebrew&lt;&#x2F;a&gt; install of Git and it worked just
fine for me after upgrading. So be aware of what your situation is and resort
to brew because it is awesome.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;xcode-4-4&quot;&gt;XCode 4.4&lt;&#x2F;h2&gt;
&lt;p&gt;In order to build gems with the native exensions and just to have the basic
development tools around I installed the latest XCode 4.4. Once installed I
went to the preferences menu, in the download tab, and chose to install the
&lt;em&gt;Command Line Tools&lt;&#x2F;em&gt; because that is really what I was looking for more than
anything. I have read on other posts online that you can download the &lt;em&gt;Command
Line Tools&lt;&#x2F;em&gt; alone and install just them. I personally chose to install XCode as
I do use XCode and the native tools to work on iPhone&#x2F;iPad app development as
well.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gcc-4-2&quot;&gt;gcc-4.2&lt;&#x2F;h2&gt;
&lt;p&gt;The latest XCode now comes with clang&#x2F;llvm which is a new C&#x2F;C++&#x2F;Objective-C
compiler. The problem is that the Ruby language isn&#x27;t fully compatible with
clang and llvm. Therefore, you need to install GCC 4.2 using Homebrew. GCC 4.2
is the latest version of the GCC compiler that apple provided before switching
to clang&#x2F;llvm. Anyways, you can install GCC 4.2 by doing the following with
brew:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew tap homebrew&#x2F;dupes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew install apple-gcc42&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The above will install the apple gcc-4.2 in a side by side fashion with XCode.
This means that it won&#x27;t mess up your existing XCode install like other
solutions.&lt;&#x2F;p&gt;
&lt;p&gt;Once you install gcc-4.2 then you can install&#x2F;reinstall your ruby version
inside of RVM as needed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;apache-2-web-sharing&quot;&gt;Apache 2 (Web Sharing)&lt;&#x2F;h2&gt;
&lt;p&gt;In the upgrade it seems that they have revamped the Sharing preference pane. In
the process of this it seems that Apple has decided to remove the Web sharing
component of this preference pane. Don&#x27;t worry though. Apache is still there
and running. You just can&#x27;t start it and stop it from the preferences pane
anymore. You can use the following commands instead.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo apachectl stop&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo apachectl start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo apachectl restart&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;&#x2F;strong&gt; When the upgrade happened it nuked all my &lt;code&gt;&#x2F;etc&#x2F;apache2&#x2F;users&#x2F;&lt;&#x2F;code&gt;
configs and all my other apache configs. So, if you have any custom apache
configs as I did you should probably back them up before upgrading.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;x11&quot;&gt;X11&lt;&#x2F;h2&gt;
&lt;p&gt;It seems that another thing that was changed with the upgrade to Mac OS X
Mountain Lion was that they removed the X11 that I had previously installed and
seemed to no longer provide it. Thats ok though because XQuartz 2.7.2 is what
you want and it is available freely at
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;xquartz.macosforge.org&#x2F;landing&#x2F;&quot;&gt;http:&#x2F;&#x2F;xquartz.macosforge.org&#x2F;landing&#x2F;&lt;&#x2F;a&gt;.
Just install that bad boy and follow the on screen instructions to reboot when
it is done and you should be good to go in terms of X11.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;imagemagick&quot;&gt;ImageMagick&lt;&#x2F;h2&gt;
&lt;p&gt;Before upgrading I had ImageMagick installed via Homebrew. After, the upgrade was finished my ImageMagick was exiting with failures about some dylib. To solve this problem I simply ran the following and I was back in running order with respect to ImageMagick:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;brew upgrade imagemagick&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;pygments&quot;&gt;Pygments&lt;&#x2F;h2&gt;
&lt;p&gt;I use Pygments to handle syntax highlighting in my jekyll sites and it seemed to not be working after the upgrade. I believe this is because it is now using Python 2.7.2. To resolve this issue I just re-installed Pygments using the following:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;sudo easy_install Pygments&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-07-25T00:00:00+00:00</published>
        <updated>2012-07-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-007/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-007/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-007/">&lt;p&gt;It has been a while since I have provided an update on my &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&quot;&gt;Sublime Text 2 Guard
Plugin&lt;&#x2F;a&gt; and I just made some changes
so I figured I would make a quick post. The project has recently had a number
of contributions which I will list in the changes below.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed default Linux key-mappings
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;52&quot;&gt;#52&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed default Windows key-mappings
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;52&quot;&gt;#52&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Added Run all Tests &amp;amp; Show Guard Output, Thanks
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;whitequark&quot;&gt;@whitequark&lt;&#x2F;a&gt;
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;44&quot;&gt;#44&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;53&quot;&gt;#53&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Made it work without Bundler, Thanks
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;brandonblack&quot;&gt;@brandonblack&lt;&#x2F;a&gt;
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;51&quot;&gt;#51&lt;&#x2F;a&gt;,
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;50&quot;&gt;#50&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Clear output when predefined text found, Thanks
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;diogomafra&quot;&gt;@diogomafra&lt;&#x2F;a&gt;
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;48&quot;&gt;#48&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Added support for &lt;em&gt;rbenv&lt;&#x2F;em&gt;, Thanks
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;chrislerum&quot;&gt;@chrislerum&lt;&#x2F;a&gt;
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;45&quot;&gt;#45&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;I have been completely stoked with the growing usage of this plugin as well as
the abundance of contributions people have been making to the plugin. In this
update there are a number of people that need to be called out with special thanks.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;diogomafra&quot;&gt;@diogomafra&lt;&#x2F;a&gt; provided a &lt;em&gt;Clear output when
predefined text found&lt;&#x2F;em&gt; feature. I am sure many users will find this feature a
nice addition to smoothing out their workflow. Thank you for your contribution
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;diogomafra&quot;&gt;@diogomafra&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;chrislerum&quot;&gt;@chrislerum&lt;&#x2F;a&gt; provided &lt;strong&gt;rbenv support&lt;&#x2F;strong&gt;. I know
that this feature will be huge for a number of the users as this was a highly
requestd feature.  Thank you so much for your contribution
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;chrislerum&quot;&gt;@chrislerum&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;brandonblack&quot;&gt;@brandonblack&lt;&#x2F;a&gt; provided the ability to
function without bundler. This will allow users who aren&#x27;t using bundler to be
able to use this plugin.  I think this is a great addition as the more people
we can get using this plugin the more feedback we can get. Hence, the better it
will become. Thanks for your contribution
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;brandonblack&quot;&gt;@brandonblack&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;whitequark&quot;&gt;@whitequark&lt;&#x2F;a&gt; provided the basis for the &lt;strong&gt;Run
all Tests &amp;amp; Show Guard Output&lt;&#x2F;strong&gt; feature. I know a number of developers who have
been waiting for something like this to fit their personal workflow. Thank you
very much for your contribution &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;whitequark&quot;&gt;@whitequark&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;A big thanks goes out to all the above listed contributors and all of our
prior contributors. Thank you all for helping make this a solid very useful
plugin for the development community. As usual please make issues for any bugs
or feature requsets you have at &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&quot;&gt;Sublime Text 2 Guard
Plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>A New Rails Tagging Plugin</title>
        <published>2012-07-22T00:00:00+00:00</published>
        <updated>2012-07-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/a-new-rails-tagging-plugin/"/>
        <id>https://drewdeponte.com/blog/a-new-rails-tagging-plugin/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/a-new-rails-tagging-plugin/">&lt;p&gt;A little over 3 months ago I had the need for a good tagging plugin for Rails.
I tried out a number of the popular ones but they just weren&#x27;t up to my
standards in terms of their APIs and their functionality. To accomplish the
user experience goals that had been set forth for the project I would have had
to hack the existing Rails tagging plugins to pieces.&lt;&#x2F;p&gt;
&lt;p&gt;So after some discussion about the Rails plugins with my team. We decided that
I should just start my own Rails tagging plugin. Anyways, I started developing
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;tagalong&quot;&gt;Tagalong&lt;&#x2F;a&gt;, my Rails tagging plugin,
immediately. The library is now 3 months old and I figured I should let people
know that it exists and provide a breakdown of its features.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;tagalong&quot;&gt;Tagalong&lt;&#x2F;a&gt; has two major concepts that a
developer needs to understand before being able to use it. The first concept is
a &lt;em&gt;Tagger&lt;&#x2F;em&gt;. A &lt;em&gt;Tagger&lt;&#x2F;em&gt; is simply an object that can perform the act of tagging
other objects (&lt;em&gt;Taggables&lt;&#x2F;em&gt;). As I am sure you have guessed the second concept
is a &lt;em&gt;Taggable&lt;&#x2F;em&gt;. A &lt;em&gt;Taggable&lt;&#x2F;em&gt; is simply an object in the system that can be
tagged.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;tagalong&quot;&gt;Tagalong&lt;&#x2F;a&gt; Rails plugin is built
entirely around these two concepts a &lt;em&gt;Tagger&lt;&#x2F;em&gt; and a &lt;em&gt;Taggable&lt;&#x2F;em&gt;. This
architecture decision is one of the major differences between this Rails
tagging plugin and the other tagging plugins out there. A brief breakdown of
the plugin is as follows.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;clean easy to understand API&lt;&#x2F;li&gt;
&lt;li&gt;does NOT require saving of the model when tagging&#x2F;untagging&lt;&#x2F;li&gt;
&lt;li&gt;keeps history of tags &lt;em&gt;Taggers&lt;&#x2F;em&gt; have used&lt;&#x2F;li&gt;
&lt;li&gt;allows defining multiple &lt;em&gt;Taggers&lt;&#x2F;em&gt; and &lt;em&gt;Taggables&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;li&gt;tracks number of times tags are used&lt;&#x2F;li&gt;
&lt;li&gt;returns tag lists in alphabetical order&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The above are simply a few brief points. For details on all its features and
how to use it please refer to the GitHub project
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;tagalong&quot;&gt;http:&#x2F;&#x2F;github.com&#x2F;uptech&#x2F;tagalong&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>OctopusCI now has job rerun</title>
        <published>2012-07-22T00:00:00+00:00</published>
        <updated>2012-07-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/octopusci-now-has-job-rerun/"/>
        <id>https://drewdeponte.com/blog/octopusci-now-has-job-rerun/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/octopusci-now-has-job-rerun/">&lt;p&gt;I recently released v0.3.12 of my CI server
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;octopusci&quot;&gt;OctopusCI&lt;&#x2F;a&gt;.  This release provided a
feature which people have been asking for a while now.  I am glad to tell you
all that it is finally here.
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;octopusci&quot;&gt;OctopusCI&lt;&#x2F;a&gt; now has the capability of
re-running jobs simply by clicking a link.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-04-15T00:00:00+00:00</published>
        <updated>2012-04-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-006/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-006/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-006/">&lt;p&gt;Well, I am back with some more updates on my &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&quot;&gt;Sublime Text 2 Guard
Plugin&lt;&#x2F;a&gt;.  This is a smaller release
than the last as I have been very busy. Despite its small stature it is an
exciting one as we have another contribution to honor. The following are the
recent updates:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed comma, single quote, question mark color issues
(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;25&quot;&gt;#25&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed small color issue caused by &lt;code&gt;!&lt;&#x2F;code&gt; char
(&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&#x2F;26&quot;&gt;#26&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Better console colors, change &lt;code&gt;0 failures&lt;&#x2F;code&gt; from red to green (Thanks
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;lidanh&quot;&gt;@lidanh&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A special thanks goes out to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;lidanh&quot;&gt;@lidanh&lt;&#x2F;a&gt; for the code
contribution. The new colors are much nicer and the &lt;code&gt;0 failures&lt;&#x2F;code&gt; being green
instead of red makes it easier to detect success vs failure.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks also goes out to all the users of the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&quot;&gt;Sublime Text 2 Guard
Plugin&lt;&#x2F;a&gt;.  Especially, the users that
have been submitting bug reports and feature requests. This plugin wouldn&#x27;t
exist without the direction and feedback from you all.&lt;&#x2F;p&gt;
&lt;p&gt;Please continue to provide feedback via Sublime Text 2 Guard Plugin
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;sublime_guard&#x2F;issues&quot;&gt;issues&lt;&#x2F;a&gt; on our GitHub page.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My zsh Setup</title>
        <published>2012-04-13T00:00:00+00:00</published>
        <updated>2012-04-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/my-zsh-setup/"/>
        <id>https://drewdeponte.com/blog/my-zsh-setup/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/my-zsh-setup/">&lt;p&gt;Relatively recently I switched to ZSH for my shell. The primary reason I
switched was that I had more flexibility in prompts as I can setup a right
prompt and a left prompt. I also like the completion interfacing that ZSH
provides. Anyways, I finally got around to generalizing my ZSH setup and
making it available on GitHub as a backup for myself so that I can easily set
it up again in the future, as well as a means of sharing my setup with all of
you. It is available on GitHub at &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;dotzsh&quot;&gt;http:&#x2F;&#x2F;github.com&#x2F;drewdeponte&#x2F;dotzsh&lt;&#x2F;a&gt;
with instructions on how to install it using git.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>My VIM Setup</title>
        <published>2012-04-11T00:00:00+00:00</published>
        <updated>2012-04-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/my-vim-setup/"/>
        <id>https://drewdeponte.com/blog/my-vim-setup/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/my-vim-setup/">&lt;p&gt;So, as some of you may know I pulled my old .vimrc out of hiding and started
playing around with vim again to see if I would potentially want to switch back
to it from Sublime Text 2. The reason being that I still fealt I was missing
something that I had in vim (the quick keyboard navigation and general
flexibility). Anyways, I pulled my .vimrc out and added the basics of what I
think I am going to need for it to be an acceptable replacement for Sublime
Text 2. This includes fuzzy file search, tab completion, etc. Basically all the
things necessary for it to be a competitor to Sublime Text 2 in my mind. It
isn&#x27;t perferct yet but it is a start.&lt;&#x2F;p&gt;
&lt;p&gt;Note: The only reason I am doing this is because I already knew VIM so I don&#x27;t
have a learning curve to really explore this. In my eyes Sublime Text 2 and VIM
are pretty damn close in terms of functionality but Sublime Text 2 provides a
much smaller learning curve for the majority of people.&lt;&#x2F;p&gt;
&lt;p&gt;This does NOT mean that I am giving up on Sublime Text 2 or that I am going to
stop supporting my Sublime Text 2 plugins. If it comes to that at some point in
the future I will find a new mantainer for them and let you all know.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, I have made my vim setup available on github via
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;dotvim&quot;&gt;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;dotvim&lt;&#x2F;a&gt;. The
README for the repository provides instructions on how to install using git.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-02-28T00:00:00+00:00</published>
        <updated>2012-02-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-005/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-005/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-005/">&lt;p&gt;Well, I got some more updates for you all.&lt;&#x2F;p&gt;
&lt;p&gt;My Sublime Text 2 Guard Plugin has recently been recognized as an essential
Sublime Text 2 plugin on a nettuts+ blog post. Thanks to this publicity and the
exposure via Package Control, Twitter, GitHub, and Google I have gotten some
decent feedback, especially around my recent addition of colored output. Thanks
to all that feedback I have pushed out the following improvements to the
Sublime Text 2 Guard Plugin:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Support for directory paths with spaces (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;pull&#x2F;19&quot;&gt;#19&lt;&#x2F;a&gt;, Thanks &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;ffmike&quot;&gt;@ffmike&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed dash based coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;16&quot;&gt;#16&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed single quote based coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;17&quot;&gt;#17&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed question mark based coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;20&quot;&gt;#20&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed period based coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;21&quot;&gt;#21&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed success dot section identification &amp;amp; coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;22&quot;&gt;#22&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Fixed a second single quote based coloring issue (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;23&quot;&gt;#23&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Added command relativity (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;24&quot;&gt;#24&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The above break down of improvements include primarily a bunch of coloring
fixes, command relativity, and one very important issue that deserves some
recognition, issue &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;pull&#x2F;19&quot;&gt;#19&lt;&#x2F;a&gt; by
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;ffmike&quot;&gt;@ffmike&lt;&#x2F;a&gt;. This is the Sublime Text 2 Guard Plugin&#x27;s
first contribution. Much thanks goes out to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;ffmike&quot;&gt;@ffmike&lt;&#x2F;a&gt;
for being our first contributor.&lt;&#x2F;p&gt;
&lt;p&gt;As usual if any of you have identified bugs or features that you would like
added please submit them on the GitHub Issues page for the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues?sort=created&amp;amp;direction=desc&amp;amp;state=open&quot;&gt;Sublime Text 2
Guard
Plugin&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin in Color</title>
        <published>2012-02-22T00:00:00+00:00</published>
        <updated>2012-02-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-004/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-004/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-004/">&lt;p&gt;Hey all,&lt;&#x2F;p&gt;
&lt;p&gt;I know there are a number of you who have been eagerly awaiting this moment. I
sure have been. I am proud to announce the first release of the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;Sublime Text 2
Guard Plugin&lt;&#x2F;a&gt; that provides colored
output. Basically, it ended up that I had to define a language file to identify
the entities in the output and then define a theme to color those identified
entities. Once, I did that I simply programatically set the color_scheme and
syntax options for the output panel and like magic colors worked. Given the
complexity of the language definition and the limited test cases I had when
developing I am sure there are going to be some bugs to work out. So, as usual
please create issues if you find any of these
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&quot;&gt;issues&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-02-09T00:00:00+00:00</published>
        <updated>2012-02-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-003/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-003/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-003/">&lt;p&gt;Hey all,&lt;&#x2F;p&gt;
&lt;p&gt;My Sublime Text 2 Guard plugin has been out for a couple weeks now and it has
definitely gotten some more usage under its belt. Thanks to everyone for your
usage and feedback. As a result of the feedback and user generated issues I
have released a new version to tighten it up a bit both from a user experience
stand point as well as a stability standpoint. This release includes the
following:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Now installable via &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;wbond.net&#x2F;sublime_packages&#x2F;package_control&quot;&gt;Package Control&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Fixed Guard won&#x27;t start when installled via Package Control (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;11&quot;&gt;issue #11&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Added auto show output feature (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&#x2F;12&quot;&gt;issue #12&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;Replaced &lt;code&gt;#!&#x2F;bin&#x2F;sh&lt;&#x2F;code&gt; with &lt;code&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;code&gt; in internal scripts&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For info on how to get the latest version or how to report bugs, feature
requsts, etc. Please check out the GitHub page for the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;sublime_guard&lt;&#x2F;a&gt; project.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-02-01T00:00:00+00:00</published>
        <updated>2012-02-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-002/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-002/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-002/">&lt;p&gt;Hey all,&lt;&#x2F;p&gt;
&lt;p&gt;I was having some difficulties with a couple bugs in the Sublime Text 2 Guard
plugin I have been working on. So, I decided I would drop Jon Skinner,
developer of Sublime Text 2, an e-mail and see if he knew about the issues I
was having and hopefully of solutions&#x2F;work arounds for them. Jon, was very
helpful in terms of better understanding the issues as well as suggesting some
work arounds.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, given the input from Jon I took another look at the bugs&#x2F;features of
the Guard plugin and decided to tackle them tonight. The following items show
the progress that I made tonight with respect to the Sublime Text 2 Guard
plugin:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Enabled native Sublime Text 2 word wrap in the Guard output view.&lt;&#x2F;li&gt;
&lt;li&gt;Guard now exits properly when Sublime Text 2 exits&#x2F;dies.&lt;&#x2F;li&gt;
&lt;li&gt;Added default key bindings to show Guard output view (super+shift+c)&lt;&#x2F;li&gt;
&lt;li&gt;Submitted a pull request to get the Guard plugin added to the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;wbond.net&#x2F;sublime_packages&#x2F;package_control&quot;&gt;Package
Control&lt;&#x2F;a&gt; repository list.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As usual I am looking for feedback issues (feature requests, bug fixes, etc.)
You can find the project as
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;sublime_guard&lt;&#x2F;a&gt; on GitHub. As of
tonight I am down to two feature requests. So, please create bugs in the issues
if you run into any so that I can work on fixing them sooner rather than later.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Updates</title>
        <published>2012-01-27T00:00:00+00:00</published>
        <updated>2012-01-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-001/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-001/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-updates-001/">&lt;p&gt;Just dropping a quick note to all that follow my blog. Last night I made a
numeber updates to the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;Guard
Plugin&lt;&#x2F;a&gt; for &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.sublimetext.com&#x2F;2&quot;&gt;Sublime Text
2&lt;&#x2F;a&gt;. Most of these were in direct response to
feedback that I got from users after making the initial release on my blog, I
think, two days ago. The modifications I made are enumarted below:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The biggest addition is &lt;code&gt;RVM detection and integration&lt;&#x2F;code&gt;. The plugin is now
intelligent enough to detect if you have RVM installed and detect if you are
using a Project specific .rvmrc and of course respond by calling Guard
appropriately depending on the case.&lt;&#x2F;li&gt;
&lt;li&gt;Another relatively small fix is a &lt;code&gt;vertical only auto-scroll&lt;&#x2F;code&gt;. Before, if Guard
output went to the right past the width of the pane it was auto-scrolling to
the right and then bouncing back to the left at the next line. Now, it always
scrolls down the left most column of the output basically making it
auto-scroll vertically.&lt;&#x2F;li&gt;
&lt;li&gt;Third I added some output preprocessing that &lt;code&gt;strips out the Terminal Color Codes&lt;&#x2F;code&gt; so that the output is a bit cleaner.&lt;&#x2F;li&gt;
&lt;li&gt;I also added a lot of &lt;code&gt;descriptive output and error handling and output&lt;&#x2F;code&gt; to let
the user better know what is failing so they might be able to debug the
situation a bit better.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;As always if you have any feedback (feature requests, bug reports, etc.) you
can simply create an issue for the project at the projects &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&#x2F;issues&quot;&gt;GitHub Issues
Page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;If you are new to the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;Guard Plugin&lt;&#x2F;a&gt;
for &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.sublimetext.com&#x2F;2&quot;&gt;Sublime Text 2&lt;&#x2F;a&gt; you can find installation
instructions and document on the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;GitHub
Page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;For instructions on upgrading please checkout the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;GitHub
Page&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sublime Text 2 Guard Plugin Debut</title>
        <published>2012-01-25T00:00:00+00:00</published>
        <updated>2012-01-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-debut/"/>
        <id>https://drewdeponte.com/blog/sublime-text-2-guard-plugin-debut/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/sublime-text-2-guard-plugin-debut/">&lt;p&gt;Hi all. I know it has been a while. Please forgive me. My life has been a
little crazy. I am still in the process of buliding my house. I also recently
became engaged so I am trying to deal with wedding planning. Beyond that I am
still trying to get all my development work done for RealPractice, my side
company, and all of my open source projects.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, I needed a break from serious projects and decided it was time for a
small fun project that would potentially help me develop the more serious
projects more efficiently. A while back I started using a new text editor
called &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.sublimetext.com&#x2F;2&quot;&gt;Sublime Text 2&lt;&#x2F;a&gt;. Basically it is what
TextMate 2 promised (and failed) to be and more.&lt;&#x2F;p&gt;
&lt;p&gt;So, since I have been using this for a while and I have been developing Ruby
and Rails apps lately using BDD and TDD I decided it was time to remove the
annoyance of having to switch to the terminal after each little development
iteration to check Guard&#x27;s output to see why my tests are failing. Wow that was
a run on sentence. Oh, well it is 2 am and I just finished the plugin so bare
with me. Anyways. Therefore, I decided it was the perfect opportunity to build
a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.sublimetext.com&#x2F;2&quot;&gt;Sublime Text 2&lt;&#x2F;a&gt; plugin that integrates Guard
into it.&lt;&#x2F;p&gt;
&lt;p&gt;It is available with its documentation on GitHub at
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&quot;&gt;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;sublime_guard&lt;&#x2F;a&gt;.
Please don&#x27;t hesitate to go grab it, use it, extend it, contribute back, report
bugs, or throw me new feature requests.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Archaic - Archived Chats and Dev Helper</title>
        <published>2010-12-13T00:00:00+00:00</published>
        <updated>2010-12-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/archaic-archived-chats-and-dev-helper/"/>
        <id>https://drewdeponte.com/blog/archaic-archived-chats-and-dev-helper/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/archaic-archived-chats-and-dev-helper/">&lt;p&gt;So for those of that don&#x27;t know, I lead of team of software developers. For a
long time now I have noticed a number of gaps in the industry with respect to
software development and team collaboration. One area that I always felt was
missing some love was group chat.&lt;&#x2F;p&gt;
&lt;p&gt;Sure, there are a large number of different chat protocols and applications
that implement them all. However, they generally miss an archived history that
has full text searching. Beyond the group chat is prime location to distribute
push notifications when Git repositories that the team is working with have
changes pushed to them. Because of these two issues and number of other that I
really don&#x27;t want to get into at this point I have started a new open source
project called &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;archaic&quot;&gt;&quot;Archaic&quot;&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;archaic&quot;&gt;Archaic&lt;&#x2F;a&gt; is a Rails application that
provides archiving of IRC channel chats with a full text search interface as
well as general developer helpers. It is composed of two pieces, an IRC Bot and
the Rails application. Technically they both share the rails environment as the
IRC Bot should be run with rails runner. You can checkout the project at the
following:
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;archaic&quot;&gt;http:&#x2F;&#x2F;github.com&#x2F;cyphactor&#x2F;archaic&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I plan to keep the master branch functional so feel free to use the master
branch. It currently has the following features.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;IRC Chat Archiving&lt;&#x2F;li&gt;
&lt;li&gt;Full Text Chat Archive Searching with Context (to expand context simply click
on resulting match)&lt;&#x2F;li&gt;
&lt;li&gt;Week number helper (when anyone in IRC channel types &quot;weeknum&quot; it replies
with current week number)&lt;&#x2F;li&gt;
&lt;li&gt;Ticket number helper (when anyone in IRC channel types &quot;#\d+&quot; it replies with
link to that ticket)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This is the initial introduction to this project and I am sure it has numerous
directions that it can and will grow into. I very much welcome your thoughts,
suggestions, feature requests, bug reports, testing, etc.&lt;&#x2F;p&gt;
&lt;p&gt;I believe that having a good central place of communication for a team even if
they are working in the same office helps at least as a mechanism for keeping
your devs notified about repo pushes close to real time.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, enjoy!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rails friendly_id Plugin</title>
        <published>2010-08-26T00:00:00+00:00</published>
        <updated>2010-08-26T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/rails-friendly-id-plugin/"/>
        <id>https://drewdeponte.com/blog/rails-friendly-id-plugin/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/rails-friendly-id-plugin/">&lt;p&gt;Hey all. I recently discovered the friendly_id plugin for Rails at a Orange
Country Ruby Group meetup. It basically provides a bunch of awesome
functionality with respect to permalinking and slugging. Anyways, I very much
recommend that you all check it out and play around with it. You can get to the
projects GitHub page &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;github.com&#x2F;norman&#x2F;friendly_id&quot;&gt;here&lt;&#x2F;a&gt; and its
documentation &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;norman.github.com&#x2F;friendly_id&#x2F;&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Ruby Class vs. Instance Diagram</title>
        <published>2010-08-13T00:00:00+00:00</published>
        <updated>2010-08-13T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/ruby-class-vs-instance-diagram/"/>
        <id>https://drewdeponte.com/blog/ruby-class-vs-instance-diagram/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/ruby-class-vs-instance-diagram/">&lt;p&gt;One of the many things that I have changed on my new team is the language. They
were originally all PHP developers and my boss and I who have been using Ruby
and Rails for years now decided to develop the new products in Ruby and Rails
where fitting. Anyways, as a part of the process I have been educating (and
being educated) by my engineers on Ruby and Rails as they go through the
learning process. One of the topics that seems to have some confusion around it
is Class vs. Instance variables with respect to classes and objects. Because
this confusion I spent some time with one of the engineers to put together a
quick diagram to try and help clarify what is actually happening with respect
to Class vs. Instance variables and methods. You can find the diagram
&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;ruby-class-vs-instance-diagram&#x2F;ruby_class_vs_instance.pdf&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git, finding abandoned commits...</title>
        <published>2010-07-30T00:00:00+00:00</published>
        <updated>2010-07-30T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/git-finding-abandoned-commits/"/>
        <id>https://drewdeponte.com/blog/git-finding-abandoned-commits/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/git-finding-abandoned-commits/">&lt;p&gt;So, as many of you may know I recently took a position heading up a new
software engineering team that is responsible for producing the new products.
One of my first actions when I came on board was switching my team over from
SVN to Git. One of the engineers on the team abandoned a branch in one of our
Git repositories because he didn&#x27;t think he would need it anymore. Soon, after
he realized that he wanted something from that branch but now he couldn&#x27;t see
the brach anymore in &#x27;gitk --all&#x27; or any of the other tools because he
abandoned it. But, it has to still be there right, it is Git.&lt;&#x2F;p&gt;
&lt;p&gt;I knew there was a way to do this in Git and I have done it in the past but I
couldn&#x27;t remember how. After I explained a bit more to him about the internals
of Git and he went off and did some exploration he came back to me with his
found solution which follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;git fsck --unreachable| cut -f3 -d&amp;#39; &amp;#39;|xargs git rev-list --header|less&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I know there is some other way to find abandoned nodes in Git but I still can&#x27;t
remember. Anyways, just figured I would share this method in the hopes that it
would help someone out there. It may not be exactly what you want with respect
to the &#x27;cut&#x27; or &#x27;xargs&#x27; but I will let you all play with it a bit to get
exactly what you want.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>jQuery Comparative Histogram Plugin</title>
        <published>2009-10-31T00:00:00+00:00</published>
        <updated>2009-10-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/jquery-comparative-histogram-plugin/"/>
        <id>https://drewdeponte.com/blog/jquery-comparative-histogram-plugin/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/jquery-comparative-histogram-plugin/">&lt;p&gt;I recently wrote a jQuery Plugin that I am calling jquery_comphist. It is a
jQuery Plugin that draws a Comparative Histogram of a provided population
divided into two major groups with any number of shared sub-groups. One of the
most common uses for such a feature is when you are trying to display
demographics data on some population. Anyways, as usual the code is available
here (&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;jquery-comparative-histogram-plugin&#x2F;jquery.comphist.js&quot;&gt;jquery.comphist.js&lt;&#x2F;a&gt;,
&lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;jquery-comparative-histogram-plugin&#x2F;jquery.comphist.css&quot;&gt;jquery.comphist.css&lt;&#x2F;a&gt;) and you can see an example of it
below.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;jquery-comparative-histogram-plugin&#x2F;jquery-comparative-histogram.png&quot; alt=&quot;jQuery Comparative Histogram&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With the jQuery Comparative Histogram (CompHist) Plugin you can easily
represent populations and information about them. A prime usage exampe of this
is demographics. All the styling is done via CSS. Hence the style is easily
modified. It does the calculations for you and it allows for non listed group
counts via a &lt;code&gt;non_demo_count&lt;&#x2F;code&gt; data option.&lt;&#x2F;p&gt;
&lt;p&gt;The above demo was produced by defining a few code snippets. The first snippet
is a snippet of HTML that includes the jQuery Comparative Histogram javascript
source file and CSS style sheet. Note: The jQuery Comparative Histogram
javascript source file needs to come after the standard jQuery javascript
source file. An example of this snippet is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;text&#x2F;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; src&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;..&#x2F;jquery.comphist.js&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;link&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; rel&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;stylesheet&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;text&#x2F;css&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; href&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;..&#x2F;stylesheets&#x2F;jquery.comphist.css&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: In the above snippet the href values are likely to be different in your
case. The second code snippet is simply a single line of HTML where the div
that is to be the Comparative Histogram. It is key that this div has an id that
is easily referenced and a set height and width. An example of this snippet is
as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;compplaceholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; style&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;width: 375px; height: 200px;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The third code snippet needed is the javascript that defines the data, creates
the Comparative Histogram in the specified div, and handles the hover
functionality. An example of this is seen below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;text&#x2F;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span&gt; () {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; showCompHistTooltip&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; contents&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;		console&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;log&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;called my shit&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&amp;lt;div id=&amp;quot;comphist1tooltip&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; contents&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;&amp;lt;&#x2F;div&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;css&lt;&#x2F;span&gt;&lt;span&gt;({&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			position: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;absolute&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			display: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;none&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			top:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 20&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			left:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; -&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 30&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			border: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1px solid #fdd&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			padding: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;2px&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;background-color&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#fee&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			opacity:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;appendTo&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;fadeIn&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;200&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;	var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; comphist_data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		population_label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Active Fans This Week&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		group_1_label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Male&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_2_label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;Female&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		subgroups: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;13-17&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 16&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;18-24&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 7&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 27&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;25-34&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 29&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;35-44&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 9&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;45-54&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		{ label: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;55+&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;, group_1_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, group_2_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		non_demo_count:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	};&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;	$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#compplaceholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;comphist&lt;&#x2F;span&gt;&lt;span&gt;({},&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; comphist_data&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;	$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#compplaceholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;barover&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; perc&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#comphist1tooltip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		showCompHistTooltip&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pos&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;left&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;top&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; perc&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;	$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#compplaceholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;barout&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;e&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; perc&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#comphist1tooltip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hopefully, the example helps get you up and running quickly.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Flot Multi-series Bar Graph Support</title>
        <published>2009-08-22T00:00:00+00:00</published>
        <updated>2009-08-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/flot-multi-series-bar-graph-support/"/>
        <id>https://drewdeponte.com/blog/flot-multi-series-bar-graph-support/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/flot-multi-series-bar-graph-support/">&lt;p&gt;Hey boys and girls. I just got finished coding support for Multi-series bar
graphs into Flot (a jQuery based JavaScript graphing library). Hence, I figured
I would share not only the code but a little screenshot of it below. The code
for it can be found &lt;a href=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;flot-multi-series-bar-graph-support&#x2F;jquery.flot.js&quot;&gt;here&lt;&#x2F;a&gt;. Below is an example of how to use it.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;drewdeponte.com&#x2F;blog&#x2F;flot-multi-series-bar-graph-support&#x2F;flot-multi-serios-bar-graph.png&quot; alt=&quot;Flot Multi-Series Bar Graph&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;With the multi-series bar graph support, you can have Flot display the series
side by side. This is useful when you are interested in visually comparing
series and grouping segments you want to see columns in series that you are
specifically interested in comparing.&lt;&#x2F;p&gt;
&lt;p&gt;The above screenshot was produced by defining a few code snippets. The first snippet
is a snippet of HTML that includes the customized Flot javascript source file.
Note: The Flot javascript source file needs to come after the standard jQuery
javascript source file. An example of this snippet is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #5F6672;font-style: italic;&quot;&gt;&amp;lt;!--[if IE]&amp;gt;&amp;lt;script language=&amp;quot;javascript&amp;quot; type=&amp;quot;text&#x2F;javascript&amp;quot; src=&amp;quot;..&#x2F;excanvas.min.js&amp;quot;&amp;gt;&amp;lt;&#x2F;script&amp;gt;&amp;lt;![endif]--&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; language&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;text&#x2F;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; src&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;..&#x2F;jquery.js&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; language&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; type&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;text&#x2F;javascript&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; src&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;..&#x2F;jquery.flot.js&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Note: In the above snippet the href values are likely to be different in your
case. The second code snippet is simply a single line of HTML that is the div
that is to be the Multi-series Bar Graph. It is key that this div has an id
that is easily referenced and a set height and width. An example of this
snippet is as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; id&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;placeholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; style&lt;&#x2F;span&gt;&lt;span&gt;=&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;width: 375px; height: 200px;&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;div&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The third code snippet needed is the javascript that defines the data, creates
the Multi-series Bar Graph in the specified div, and handles the hover
functionality. An example of this is seen below.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #A9B2C3; background-color: #21252B;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span style=&quot;color: #D19A66;&quot;&gt; id&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;source&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$(function () {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	var ms_data&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [{&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;FOO&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:[[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;70&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;100&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;60&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;102&lt;&#x2F;span&gt;&lt;span&gt;]]},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;								 {&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;BAR&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:[[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;30&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;40&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;80&lt;&#x2F;span&gt;&lt;span&gt;]]},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;								 {&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;CAR&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;data&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;:[[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;5&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;10&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;25&lt;&#x2F;span&gt;&lt;span&gt;]]}]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;	var ms_ticks&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1&#x2F;28&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1&#x2F;29&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1&#x2F;30&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1&#x2F;31&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;],[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;4&lt;&#x2F;span&gt;&lt;span&gt;,&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1&#x2F;32&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;]];&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;		function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; plotWithOptions&lt;&#x2F;span&gt;&lt;span&gt;() {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;			$&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;plot&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#placeholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;),&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; ms_data&lt;&#x2F;span&gt;&lt;span&gt;, {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				bars: { show:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;, barWidth:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.6&lt;&#x2F;span&gt;&lt;span&gt;, series_spread:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;, align: &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;center&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				xaxis: { ticks:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; ms_ticks&lt;&#x2F;span&gt;&lt;span&gt;, autoscaleMargin:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; .10&lt;&#x2F;span&gt;&lt;span&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				grid: { hoverable:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;, clickable:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;			});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;		function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt; showTooltip&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; contents&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;				$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;#39;&amp;#39;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;css&lt;&#x2F;span&gt;&lt;span&gt;( {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						position: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;absolute&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						display: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;none&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						top:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						left:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						border: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;1px solid #fdd&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						padding: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;2px&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;background-color&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;: &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#fee&lt;&#x2F;span&gt;&lt;span&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						opacity:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; 0.80&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;appendTo&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;body&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;show&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		plotWithOptions&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#placeholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;plothover&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;event&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;			$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#x&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;text&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pos&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toFixed&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;			$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#y&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;text&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pos&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;y&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toFixed&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;));&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;						if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;previousPoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; !=&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;datapoint&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;								previousPoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;datapoint&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;								$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#tooltip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt;								var&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; x&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;datapoint&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toFixed&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;),&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;										y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;datapoint&lt;&#x2F;span&gt;&lt;span&gt;[&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;].&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;toFixed&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;							&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;								showTooltip&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pageX&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;pageY&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;														item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;series&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt; Group id: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; Math&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;floor&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;x&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;, y = &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; y&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;, seriesIndex: &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;seriesIndex&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;						}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				else&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;						$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#tooltip&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;remove&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;						previousPoint&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #56B6C2;&quot;&gt; null&lt;&#x2F;span&gt;&lt;span&gt;;            &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;		$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#placeholder&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;bind&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;plotclick&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #61AFEF;&quot;&gt; function&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;event&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; pos&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt;				if&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;item&lt;&#x2F;span&gt;&lt;span&gt;) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;						$&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;#clickdata&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;).&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B57EDC;&quot;&gt;text&lt;&#x2F;span&gt;&lt;span&gt;(&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;You clicked bar &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;dataIndex&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt; in &lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt; item&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;series&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #C6CCD7;&quot;&gt;label&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E06C75;&quot;&gt; +&lt;&#x2F;span&gt;&lt;span&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #98C379;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;&amp;quot;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;				}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;		});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;});&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #E5C07B;&quot;&gt;script&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Hopefully the code example helps get you up and running.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>TextMate Autotools Screencast</title>
        <published>2007-09-05T00:00:00+00:00</published>
        <updated>2007-09-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://drewdeponte.com/blog/textmate-autotools-screencast/"/>
        <id>https://drewdeponte.com/blog/textmate-autotools-screencast/</id>
        
        <content type="html" xml:base="https://drewdeponte.com/blog/textmate-autotools-screencast/">&lt;p&gt;I just threw together a screencast that covers a little TextMate Bundle I have
been working. The TextMate Autotools Bundle is an extension for the TextMate
editor which integrates TextMate with the standard GNU Autotools suite with a
specific emphasis on cross-platform building. Check it out below to see the
features and how to use them in this alpha version.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;&#x2F;em&gt; The video for this has been lost to the inter-web somewhere.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
