<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Tim Kleier - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Tim Kleier - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 22:23:56 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/timkleier/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Extend CRUD Operations to Align with Business Workflows ]]>
                </title>
                <description>
                    <![CDATA[ Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/extend-crud-operations-to-align-with-business-workflows/</link>
                <guid isPermaLink="false">68c19bc01159a9ac851f6cb5</guid>
                
                    <category>
                        <![CDATA[ crud ]]>
                    </category>
                
                    <category>
                        <![CDATA[ API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Backend Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Wed, 10 Sep 2025 15:39:44 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1757518255485/8e727e36-d22a-42d9-b1a7-98d3ca5eae35.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Most developers are introduced to databases and APIs through a simple pattern: CRUD—Create, Read, Update, Delete. It seems like the perfect abstraction. With just four operations, you can model almost anything. Tutorials use it. Frameworks generate it. We teach it to beginners as the foundation of working with data.</p>
<p>But once you move beyond basic apps, CRUD starts to fall apart.</p>
<p>Real-world systems don’t just “update” or “delete” things. In a loan application system, for example, borrowers “submit” applications, loan officers “approve” or “reject” them, and applications are eventually “archived”. These aren’t generic CRUD operations—they’re <strong>domain-specific actions</strong> that carry meaning.</p>
<p>And that’s the problem: CRUD hides the meaning of our systems behind vague verbs. REST APIs inherit the same issue, mapping HTTP verbs onto CRUD but still failing to express real workflows clearly.</p>
<p>In this article, we’ll explore:</p>
<ul>
<li><p>Why CRUD works fine for simple apps but becomes an anti-pattern at scale</p>
</li>
<li><p>How concepts like <strong>upsert</strong>, <strong>archive</strong>, and <strong>bulk operations</strong> reveal its cracks</p>
</li>
<li><p>Why REST doesn’t solve these issues</p>
</li>
<li><p>How to design APIs around domain actions and workflows instead.</p>
</li>
</ul>
<p>By the end, you’ll see CRUD for what it really is—a teaching tool, not a design philosophy.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-crud">What is CRUD?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-what-is-crud">What is CRUD?</h2>
<p><strong>Create, Read, Update, Delete</strong>—these are the four basic operations we perform on data in a database.</p>
<ul>
<li><p><strong>Create</strong> – adds a new record.</p>
</li>
<li><p><strong>Read</strong> – fetches an existing record (or list of records).</p>
</li>
<li><p><strong>Update</strong> – changes one or more fields in a record.</p>
</li>
<li><p><strong>Delete</strong> – removes a record.</p>
</li>
</ul>
<p>For example, in a typical Node.js + Express app managing users:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a user</span>
app.post(<span class="hljs-string">'/users'</span>, createUser);

<span class="hljs-comment">// Read a user</span>
app.get(<span class="hljs-string">'/users/:id'</span>, getUser);

<span class="hljs-comment">// Update a user</span>
app.put(<span class="hljs-string">'/users/:id'</span>, updateUser);

<span class="hljs-comment">// Delete a user</span>
app.delete(<span class="hljs-string">'/users/:id'</span>, deleteUser);
</code></pre>
<p>This maps directly to the underlying SQL:</p>
<pre><code class="lang-sql"><span class="hljs-keyword">INSERT</span> <span class="hljs-keyword">INTO</span> <span class="hljs-keyword">users</span> (...);
<span class="hljs-keyword">SELECT</span> * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">UPDATE</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">SET</span> ... <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
<span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">users</span> <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span> = ...;
</code></pre>
<p>And that’s CRUD in its purest form—four operations that can describe almost any database interaction.</p>
<h2 id="heading-stretching-crud-upsert-archive-bulk">Stretching CRUD: Upsert, Archive, Bulk</h2>
<p>Developers quickly realize CRUD isn’t enough, so they invent extensions:</p>
<ul>
<li><p><strong>Upsert</strong>: a mix of “update” and “insert.” If the record exists, update it; if not, create it.</p>
</li>
<li><p><strong>Archive</strong>: instead of deleting a record, we “soft delete” or mark it as inactive so the history stays intact.</p>
</li>
<li><p><strong>Bulk operations</strong>: run create, update, or delete on many records at once for efficiency.</p>
</li>
</ul>
<p>These solve real problems, but they stretch CRUD’s simple model. We now need to distinguish between single and bulk resource actions. And we also need to factor in the technical concerns of upsertions and soft deletions.</p>
<h2 id="heading-breaking-crud-domain-actions">Breaking CRUD: Domain Actions</h2>
<p>The technical domain itself stretches CRUD substantially, but business domain concerns break it entirely. Take a loan application system:</p>
<ul>
<li><p>A borrower doesn’t “create” and “update” an application—they start, submit, or withdraw it.</p>
</li>
<li><p>A loan officer doesn’t “update” an application—they review, approve, or reject it.</p>
</li>
<li><p>Applications don’t get “deleted”—they’re usually archived so there’s a record for compliance.</p>
</li>
</ul>
<p>If we try to model these as plain CRUD, the meaning gets lost:</p>
<pre><code class="lang-http"><span class="hljs-attribute">PATCH /applications/123 { "status"</span>: "approved" }
</code></pre>
<p>Technically, it works. But what does “update” really mean here? Was the application submitted, rejected, or archived? You can’t tell from the API call.</p>
<p>The core problem: CRUD hides intent behind generic, technical language. Real business processes are expressed as domain-specific actions, not generic updates or deletes.</p>
<h2 id="heading-breaking-crud-domain-authorization">Breaking CRUD: Domain Authorization</h2>
<p>CRUD not only obscures intent—it also creates authorization gaps. Using the same loan application example:</p>
<ul>
<li><p>Only loan officers should approve applications.</p>
</li>
<li><p>Borrowers should only edit their own information or withdraw their applications.</p>
</li>
</ul>
<p>If “approve” is just modeled as a generic update, the system can’t distinguish between roles without additional checks. A naive authorization rule like “can this user update?” suddenly lets borrowers perform actions reserved for officers.</p>
<p>This mismatch between technical verbs and business rules can lead to:</p>
<ul>
<li><p>Security issues—unauthorized actions performed by the wrong user.</p>
</li>
<li><p>Audit problems—it’s unclear who did what, and when.</p>
</li>
<li><p>Workflow confusion—state transitions get lost in generic updates.</p>
</li>
</ul>
<p>The solution: treat each domain action as its own API call with explicit authorization rules:</p>
<pre><code class="lang-http"><span class="hljs-attribute">POST /applications/123/approve   # Only accessible to loan officers
POST /applications/123/withdraw  # Only accessible to the borrower</span>
</code></pre>
<p>By modeling actions instead of CRUD operations, intent and permissions are clear, reducing both bugs and security risks.</p>
<h2 id="heading-crud-alternative-align-to-workflows">CRUD Alternative: Align to Workflows</h2>
<p>Real-world applications follow workflows—sequences of states that a resource moves through. Take our loan application example:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1757257665063/f26ce4c4-afee-4b03-8ddc-bdb724aa9850.png" alt="Loan Application Workflow Diagram" class="image--center mx-auto" width="600" height="400" loading="lazy"></p>
<p>Here’s what the corresponding API endpoints might look like:</p>
<pre><code class="lang-http"># Borrower actions
<span class="hljs-attribute">POST /applications/123/submit       # Draft → Submitted
POST /applications/123/withdraw     # Draft/Submitted → Closed

# Loan officer actions
POST /applications/123/approve      # Submitted → Approved
POST /applications/123/reject       # Submitted → Rejected

# System/Admin actions
POST /applications/123/close        # Approved/Rejected → Closed

# Side effect</span>: spawning a Loan (after Approved)
<span class="hljs-attribute">POST /loans
{
  "applicationId"</span>: "123",
  "amount": 50000,
  "borrowerId": "456",
  "terms": { ... }
}
</code></pre>
<p>At this point, our API calls are almost entirely outside the CRUD pattern—the only one that resembles a CRUD action is the spawning of a loan, which looks like a “create”. Behind the scenes, we’ll still use <code>INSERT</code>, <code>SELECT</code>, and <code>UPDATE</code> statements in SQL, but at the API level we’re aligning to the actual business workflow. Because of it, we’re able to easily support the following:</p>
<ol>
<li><p><strong>Actions reflect business intent</strong> — each API call maps to a real-world task like submit, approve, or withdraw.</p>
</li>
<li><p><strong>Built-in authorization</strong> — endpoints clearly separate borrower, loan officer, and admin responsibilities.</p>
</li>
<li><p><strong>Auditability and workflow enforcement</strong> — state transitions are explicit and invalid transitions are prevented.</p>
</li>
<li><p><strong>Controlled side effects</strong> — spawning loans, notifications, and downstream processes are handled deliberately.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By moving away from CRUD and modeling domain actions instead, our API aligns with real business workflows, clearly communicates intent, and enforces rules and authorization naturally. State transitions, side effects, and auditing become explicit, reducing errors and security risks. While CRUD still powers the underlying database operations, thinking in terms of actions and workflows ensures that the system behaves the way the business expects.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Handle Breaking Changes for API and Event Schemas ]]>
                </title>
                <description>
                    <![CDATA[ Several years ago while designing APIs for an ecommerce company, I discovered the importance of API versioning. So I wrote about it in a freeCodeCamp article entitled How to Version a REST API.  Now I find myself designing event schemas for sending m... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-handle-breaking-changes/</link>
                <guid isPermaLink="false">66bccb69ec0f48126680c59a</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Microservices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ schema ]]>
                    </category>
                
                    <category>
                        <![CDATA[ versioning ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Thu, 19 Oct 2023 14:18:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/10/7115374283_30d07f11c3_c-2.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Several years ago while designing APIs for an ecommerce company, I discovered the importance of API versioning. So I wrote about it in a <a target="_blank" href="https://www.freecodecamp.org/news">freeCodeCamp</a> article entitled <a target="_blank" href="https://www.freecodecamp.org/news/how-to-version-a-rest-api/">How to Version a REST API</a>. </p>
<p>Now I find myself designing event schemas for sending messages across a distributed system. It's a very similar problem with similar pain points and solutions. Adhering to data contracts is critical to ensure we don't frustrate event subscribers or bring down systems.</p>
<p>Versioning APIs is translatable to versioning event schemas, but if you can effectively evolve schemas, you don't actually need versioning. Effective evolution of schemas comes down to avoiding breaking changes. </p>
<p>Though I covered that briefly in the article above, here I want to thoroughly address breaking changes and propose more solutions to avoiding them.</p>
<h2 id="heading-what-are-breaking-changes">What are Breaking Changes?</h2>
<p>Essentially, a breaking change to a schema (in an API or event context) is anything that requires a consumer to make an update on their end. It's a change that forces change. Schemas will evolve, but once a schema is in use in production, you have to be very careful not to break the data contract. </p>
<p>Removing an event format or changing an event's basic structure constitutes a breaking change. But the nuts and bolts are at the attribute (the field or property) level. </p>
<h3 id="heading-structural-breaking-changes">Structural breaking changes</h3>
<p>Here's a list of structural breaking changes for schema attributes:</p>
<ul>
<li><strong>Renaming Attributes</strong> – Changes to an attribute's name, even if it's just changing the case (for example, from camelCase to TitleCase), is a breaking change.</li>
<li><strong>Removing Attributes</strong> – Taking an attribute out of a schema.</li>
<li><strong>Data Types Changes</strong> – Changing data types, even if the change seems compatible.</li>
<li><strong>Making Attributes Required</strong> – Anytime you mark an attribute (even a new one) as required when it wasn't before, it's a breaking change.</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Type</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td>Renaming Attributes</td><td><code>name</code> to <code>firstName</code></td></tr>
<tr>
<td>Removing Attributes</td><td>Introducing <code>firstName</code> but removing <code>name</code></td></tr>
<tr>
<td>Data Type Changes</td><td>Changing <code>productSKU</code> from <code>integer</code> to <code>string</code></td></tr>
<tr>
<td>Making Attributes Required</td><td>Now requiring a <code>customerID</code></td></tr>
</tbody>
</table>
</div><h3 id="heading-semantic-breaking-changes">Semantic breaking changes</h3>
<p>The other primary category of attribute-level breaking changes has to do with changes in what the data means, or semantic changes. They force consumers to re-interpret the data they're getting. </p>
<p>They are as follows:</p>
<ul>
<li><strong>Format Changes</strong> – Any change to the format of an attribute. </li>
<li><strong>Meaning Changes</strong> – When the declared or implied meaning of data changes.</li>
<li><strong>Stricter Constraints</strong> – When attribute requirements are added or made more restrictive.</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Type</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td>Format Changes</td><td>Date from <code>mm/dd/yyyy</code> to <code>yyyy-mm-dd</code></td></tr>
<tr>
<td>Meaning Changes</td><td>Changing an enum, changing <code>providerCost</code> from dollars to cents</td></tr>
<tr>
<td>Stricter Constraints</td><td>Adding <code>percentage</code> maximum of 100 </td></tr>
</tbody>
</table>
</div><p>It's important to note that what counts as a "breaking change" might be more nuanced. Changing an <code>amount</code> from dollars to cents still forces a change by event subscribers, in interpreting the <em>meaning</em> of the data being sent. Be careful of those, as they are not always obvious.</p>
<h2 id="heading-what-are-non-breaking-changes">What are Non-Breaking Changes?</h2>
<p>We can generally describe non-breaking changes as additive or permissive ones. These are changes that don't require change for consumers. </p>
<p>Here is a list of non-breaking attribute changes: </p>
<ul>
<li><strong>Adding New Attribute</strong> – In all schema contexts, the addition of a new attribute is a non-breaking change, so long as it's not required (for example, for a POST request). </li>
<li><strong>Making Attribute Not Required</strong> – When an attribute was required but newer schema versions do not require it.</li>
<li><strong>Looser Constraints</strong> – Things like more permissive integer ranges (min and max) or allowing for greater decimal precision. Be cautious and communicate with consumers, though, as they may rely on stricter constraints.</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Type</td><td>Example</td></tr>
</thead>
<tbody>
<tr>
<td>Adding New Attribute</td><td>Adding <code>firstName</code> alongside <code>name</code></td></tr>
<tr>
<td>Making Attribute Not Required</td><td><code>customerID</code> is no longer required</td></tr>
<tr>
<td>Looser Constraints</td><td>Percentage max increased from 100 to 200</td></tr>
</tbody>
</table>
</div><p>Non-breaking changes can often be avoided. But evolving schemas effectively can be challenging and require a lot of thought so as not to break schemas and consumers' trust.</p>
<h2 id="heading-how-to-evolve-schemas">How to Evolve Schemas</h2>
<p>Sadly, the list of breaking changes is longer than the non-breaking ones. But there are some strategies for evolving schemas in a non-breaking way.</p>
<ol>
<li><strong>Domain Knowledge</strong> – Understanding the domain will help ensure you don't end up with poorly named attributes, attributes on the wrong object, or incorrect data types.</li>
<li><strong>Specific Attribute Names</strong> – Rather than changing an attribute's name, data type, or format, introduce a new attribute with a more specific name and correct the data type or format.</li>
<li><strong>Attribute Names With Intent</strong> – Leverage attribute names that reflect their format or intent. For example, consumers might not know whether <code>providerCost</code> would be in dollars or cents, so specify with <code>providerCostInDollars</code> or <code>providerCostInCents</code>. This will also prevent a breaking change if you're having calculation precision issues with dollars and decide to deliver the cost in cents. </li>
<li><strong>Drafted Schemas &amp; Attributes</strong> – Utilize "draft mode" extensively at the schema level, getting feedback on attributes in simulated environments before they are live in production. For schemas that are in use in production, you could introduce a <code>draftedAttributes</code> object and dump experimental (non-production ready) attributes into it. Communicate with consumers that they attributes are being refined – so they should expect breaking changes – and will be moved to the main schema when ready.</li>
<li><strong>Support Existing Attributes</strong> – Leave old attributes in the schema. Don't remove old attributes unless you've been able to coordinate a deprecation/sunsetting strategy with consumers.</li>
<li><strong>Versioning</strong> – If necessary, version your schemas. Although it can become quite difficult to maintain, versioning your schemas is a way to allow for backwards compatibility but move forward with a new schema. You can do high-level versioning (for example, v1 and v2) or more granular semantic versioning (for example, v1.0.1). It's best to version each schema independently, so you don't have to, for example, copy all API v1 endpoints to v2. </li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Breaking changes are a quick way to break trust for any API consumers or event subscribers. I hope that the guidelines above will provide more insight what constitutes a breaking versus non-breaking change, and how to evolve schemas effectively.</p>
<p>If you can't avoid breaking changes, <strong>make sure to coordinate with any and all consumers.</strong> You can actually earn more trust with your consumers if you effectively evolve schemas and communicate breaking changes when they are necessary. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use GitHub Copilot to Become a Happier and More Productive Developer ]]>
                </title>
                <description>
                    <![CDATA[ There are a number of AI tools for developers emerging on the market. But in my mind GitHub Copilot stands above the rest because of its usability, seamless IDE integration, and remarkable enhancements to developer productivity. Copilot offers a vari... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/developer-productivity-with-github-copilot/</link>
                <guid isPermaLink="false">66bccb6401b553e3578f98ca</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Happiness ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Fri, 16 Jun 2023 17:02:17 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/Screenshot-2023-06-14-at-12.42.04-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There are a number of AI tools for developers emerging on the market. But in my mind GitHub Copilot stands above the rest because of its usability, seamless IDE integration, and remarkable enhancements to developer productivity.</p>
<p>Copilot offers a variety of AI tools that have radically streamlined my experience as a software developer. I've used it to generate code, tests, and even simple applications. It's also great for debugging, refactoring, and documenting existing code. </p>
<p>Weirdly, using Copilot has caused me to develop features faster than business stakeholders can review them.</p>
<p>It's important to note that AI tools, including Copilot, can be blatantly wrong, apologize (or not) when corrected, and then confidently produce the same error. But as long as you're aware of the downsides of AI tools, and have enough coding knowledge to recognize when they're incorrect, you can mitigate them on the path to <a target="_blank" href="https://github.blog/2022-09-07-research-quantifying-github-copilots-impact-on-developer-productivity-and-happiness/">substantially improved productivity</a>.</p>
<h2 id="heading-how-to-setup-github-copilot">How to Setup GitHub Copilot</h2>
<p>For setup and basic usage of Copilot, check out the <a target="_blank" href="https://docs.github.com/en/copilot">docs</a>. You can add on Copilot to an individual or business account, and there's a free trial and reasonable <a target="_blank" href="https://github.com/features/copilot#pricing">pricing</a> after the trial. </p>
<p>After adding Copilot to your GitHub account, you'll want to install the <a target="_blank" href="https://docs.github.com/en/copilot/getting-started-with-github-copilot">plugins for your IDE</a> and log into GitHub to access Copilot.</p>
<p>In this article, we'll use these <a target="_blank" href="https://marketplace.visualstudio.com/search?term=copilot&amp;target=VSCode&amp;category=All%20categories&amp;sortBy=Relevance">Visual Studio Code extensions</a>:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>GitHub Extension</td><td>Description</td><td>Preview</td></tr>
</thead>
<tbody>
<tr>
<td><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot">Copilot</a></td><td>AI pair programmer with in-IDE code suggestions</td><td>No</td></tr>
<tr>
<td><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-nightly">Copilot Nightly</a></td><td>Nightly build of Copilot, includes latest changes</td><td>No</td></tr>
<tr>
<td><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-labs">Copilot Labs</a></td><td>Experimental features in sidebar</td><td><a target="_blank" href="https://githubnext.com/projects/copilot-labs/">Yes</a></td></tr>
<tr>
<td><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot-chat">Copilot Chat</a></td><td>Interactive chat in sidebar, part of Copilot X</td><td><a target="_blank" href="https://github.com/features/preview/copilot-x">Yes</a></td></tr>
<tr>
<td><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.heygithub">Copilot Voice</a></td><td>Voice assistant</td><td><a target="_blank" href="https://githubnext.com/projects/copilot-voice/">Yes</a></td></tr>
</tbody>
</table>
</div><p>Notes:</p>
<ol>
<li>This info is up-to-date as the writing of this article, but will likely change as GitHub evolves these products.</li>
<li>I haven't yet received access to Copilot Voice or Copilot (X) for Pull Requests, so my perspective on these are limited and based on GitHub's preview docs.</li>
</ol>
<h3 id="heading-privacy">Privacy</h3>
<p>Before jumping into some key use cases for Copilot, a quick note on privacy: Basically, if you trust GitHub to host your source code, you can likely trust what they do with your Copilot prompts and code snippets. [See their <a target="_blank" href="https://github.com/features/copilot#faq">FAQ docs</a> and <a target="_blank" href="https://docs.github.com/en/site-policy/privacy-policies/github-privacy-statement">Privacy Statement</a>.]</p>
<h2 id="heading-use-cases-for-github-copilot">Use Cases for GitHub Copilot</h2>
<p>The uses cases for GitHub Copilot are numerous, especially when you add in <a target="_blank" href="https://github.com/features/preview/copilot-x">t</a>he preview features of Labs, Chat, and Voice. Using Copilot's features can really streamline the development process. </p>
<p>Here are some great ways to leverage Copilot extensions:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Category</td><td>Extension(s)</td></tr>
</thead>
<tbody>
<tr>
<td>Code Generation</td><td>Copilot, Copilot Nightly, Copilot Voice</td></tr>
<tr>
<td>Explaining Code</td><td>Copilot Labs, Copilot Chat, Copilot Voice</td></tr>
<tr>
<td>Language Translation</td><td>Copilot Labs, Copilot Chat</td></tr>
<tr>
<td>Debugging</td><td>Copilot Labs, Copilot Chat</td></tr>
<tr>
<td>Refactoring</td><td>Copilot Labs, Copilot Chat</td></tr>
<tr>
<td>Test Generation</td><td>Copilot, Copilot Nightly, Copilot Labs, Copilot Chat</td></tr>
<tr>
<td>Code Reviews</td><td>Copilot Chat</td></tr>
<tr>
<td>Voice-Driven Development</td><td>Copilot Voice</td></tr>
</tbody>
</table>
</div><h3 id="heading-code-generation">Code Generation</h3>
<p>Copilot is known for its code completion features. If it's given a comment in the code or you type the beginnings of a line of code, Copilot will suggest a solution that you can accept, ignore, or explore alternatives. It's referred to as "ghost text".</p>
<p>Once you have the Copilot extension installed and you're logged in, code completion is as simple as typing instructions and hitting the Tab key once the suggestion comes up.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/Screen-Recording-2023-06-09-at-8--1-.gif" alt="Image" width="600" height="400" loading="lazy">
<em>A comment prompt in Ruby that Copilot uses to create a method and invocation</em></p>
<p>Taking code completion one step further, Copilot Chat can take a single prompt and generate instructions for building an entire application. </p>
<p>I asked it to create a REST API in Node with CRUD functions for "products", and it generated functional code. Impressive overall. Given the same prompt, ChatGPT also gave me instructions for how to run the code, which was nice.</p>
<p>Copilot Voice can also write or edit code based on voice commands. Most of the time, using the keyboard with Copilot code completion is faster than dictating lines of code with Voice. But it's compelling to think about using Copilot Voice to create and run code without having to type or stare at a screen.</p>
<h3 id="heading-explaining-code">Explaining Code</h3>
<p>I often have to stare at a screen to figure out what a block of code is doing. Sometimes it's legacy code where I don't understand the business context. Sometimes it's using a particular library I'm not used to. Sometimes I curse the person who wrote it, even if it's me.</p>
<p>Below is some code generated by Copilot Chat from my "REST API in Node..." prompt from above:</p>
<pre><code class="lang-javascript">app.get(<span class="hljs-string">'/products/:id'</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> id = req.params.id;
  <span class="hljs-keyword">const</span> product = products.find(<span class="hljs-function">(<span class="hljs-params">p</span>) =&gt;</span> p.id === id);
  <span class="hljs-keyword">if</span> (product) {
    res.json(product);
  } <span class="hljs-keyword">else</span> {
    res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">'Product not found'</span> });
  }
});
</code></pre>
<p>I took this code and fed it into the "Explain" feature in Copilot Labs. Here's the response...</p>
<p><em>Here is the explanation for the code above:</em>  </p>
<ol>
<li><em>We define a route with the route path /products/:id. The colon : in the path indicates that it is a route parameter. The value of the route parameter will be available in req.params. For example, if the route path is /products/:id and we make a request to /products/5, then the value of req.params will be { id: 5 }.</em></li>
<li><em>We get the id from req.params and find the product with the given id from the products array. If a product with the given id exists, we return it. Otherwise, we send a 404 error response with the error message Product not found.</em></li>
</ol>
<p>This is a pretty straightforward segment of code, and the response is clear and straightforward as well. It would be easy to add this as documentation in a code comment above the function.</p>
<p>Another good example is regular expressions. I understand how regular expressions work but I don't often have the patience to figure out what a particular regex is doing. I fed Copilot Chat this giant regex statement for email validation:</p>
<pre><code>(?:[a-z0<span class="hljs-number">-9</span>!#$%&amp;<span class="hljs-string">'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&amp;'</span>*+/=?^_<span class="hljs-string">`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])</span>
</code></pre><p>It explained the regex at a high level, indicating it was broken into the local and domain parts, representing before and after the "@" sign in an email address. Then it described allowable characters in each part. Quite helpful.  </p>
<h3 id="heading-language-translation">Language Translation</h3>
<p>Developers are often required to quickly learn new languages and frameworks. Copilot Labs and Chat make this pretty easy. Here's an array of products in JavaScript and Ruby that was converted by Copilot:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">let</span> products = [
  { <span class="hljs-attr">id</span>: <span class="hljs-string">'1'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Product 1'</span>, <span class="hljs-attr">price</span>: <span class="hljs-number">10.99</span> },
  { <span class="hljs-attr">id</span>: <span class="hljs-string">'2'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Product 2'</span>, <span class="hljs-attr">price</span>: <span class="hljs-number">19.99</span> },
  { <span class="hljs-attr">id</span>: <span class="hljs-string">'3'</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">'Product 3'</span>, <span class="hljs-attr">price</span>: <span class="hljs-number">7.99</span> }
];
</code></pre>
<pre><code class="lang-ruby">products = [
  { <span class="hljs-symbol">id:</span> <span class="hljs-string">'1'</span>, <span class="hljs-symbol">name:</span> <span class="hljs-string">'Product 1'</span>, <span class="hljs-symbol">price:</span> <span class="hljs-number">10.99</span> },
  { <span class="hljs-symbol">id:</span> <span class="hljs-string">'2'</span>, <span class="hljs-symbol">name:</span> <span class="hljs-string">'Product 2'</span>, <span class="hljs-symbol">price:</span> <span class="hljs-number">19.99</span> },
  { <span class="hljs-symbol">id:</span> <span class="hljs-string">'3'</span>, <span class="hljs-symbol">name:</span> <span class="hljs-string">'Product 3'</span>, <span class="hljs-symbol">price:</span> <span class="hljs-number">7.99</span> }
]
</code></pre>
<p>This is a very simple example, so let's try making this into a class and going the other way (from Ruby to JavaScript):</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span></span>
  <span class="hljs-keyword">attr_reader</span> <span class="hljs-symbol">:name</span>, <span class="hljs-symbol">:price</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">initialize</span><span class="hljs-params">(name, price)</span></span>
    @name = name
    @price = price
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<pre><code class="lang-javascript"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> </span>{
  <span class="hljs-keyword">constructor</span>(name, price) {
    <span class="hljs-built_in">this</span>.name = name;
    <span class="hljs-built_in">this</span>.price = price;
  }
}
</code></pre>
<p>This checks out. For good measure, I tested TypeScript as well, and it worked perfectly, too.</p>
<h3 id="heading-debugging">Debugging</h3>
<p>This is a very handy feature. You can give Copilot Chat or Labs problematic code or error messages and it will indicate what it thinks the issue is. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/06/Screen-Recording-2023-06-14-at-1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Copilot Labs "Fix Bug" Brush Feature</em></p>
<p>I can't tell you how many hairs I've pulled out because I couldn't find what amounted to a syntax error. Copilot's ability to fix bugs just makes me happier and hairier. </p>
<p>You can also give Copilot Chat an error message with no other prompt and it can tell you the issue. I arbitrarily removed a dot from the Node REST API code:</p>
<pre><code class="lang-javascript">products[productIndex] = { id, ..req.body };
</code></pre>
<p>I copied/pasted the error message in Chat, and it responded with...</p>
<blockquote>
<p>Looking at the code excerpt you provided, it seems that the issue is on line 49 where there is a syntax error in the object literal. The ".." before <code>req.body</code> is causing the error. It should be just one dot instead of two.</p>
</blockquote>
<p>This is both correct (the line and source of the error) and incorrect (that it should be only one dot). It then gave me a code snippet with three dots, which is also correct. </p>
<p>As I mentioned at the outset, you've gotta double-check AI's work. Still, I'm impressed by Copilot's ability to parse an error message, describe what it thinks is wrong, and suggest a fix.</p>
<h3 id="heading-refactoring">Refactoring</h3>
<p>Another great use case is refactoring. Consider the code below:</p>
<pre><code class="lang-ruby"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">price_with_discount</span></span>
  price - (price * discount_rate)
<span class="hljs-keyword">end</span>
</code></pre>
<p>This simple price calculation doesn't factor in <code>nil</code> values, strings that should be numbers, or reasonable values for <code>price</code> or <code>discount_rate</code>. We need the code to do this:</p>
<ol>
<li>Ensure <code>price</code> is an integer or float (not nil)</li>
<li>Ensure <code>price</code> is not negative</li>
<li>Ensure <code>discount_rate</code> is a float (not nil)</li>
<li>Ensure <code>discount_rate</code> is not negative and less than or equal to 1</li>
</ol>
<p>Copilot Chat handles this with ease...</p>
<pre><code class="lang-ruby"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">price_with_discount</span><span class="hljs-params">(price, discount_rate)</span></span>
  raise ArgumentError, <span class="hljs-string">"Price must be a positive number"</span> <span class="hljs-keyword">unless</span> price.is_a?(Numeric) &amp;&amp; price &gt;= <span class="hljs-number">0</span>
  raise ArgumentError, <span class="hljs-string">"Discount rate must be a float between 0 and 1"</span> <span class="hljs-keyword">unless</span> discount_rate.is_a?(Float) &amp;&amp; discount_rate &gt;= <span class="hljs-number">0</span> &amp;&amp; discount_rate &lt;= <span class="hljs-number">1</span>

  price - (price * discount_rate)
<span class="hljs-keyword">end</span>
</code></pre>
<h3 id="heading-test-generation">Test Generation</h3>
<p>Using Copilot to generate tests is technically a subset of "Code Generation" above, but I felt it was so useful it warranted its own mention.</p>
<p>Generating unit tests for code can be tedious if you're trying to cover happy and sad paths, primary use cases and edge cases. Our <code>price_with_discount</code> code above needs test cases to ensure an error is raised if <code>price</code> or <code>discount_rate</code> don't meet the requirements. In addition, we might want to test the following:</p>
<ol>
<li>A <code>price</code> without a <code>discount_rate</code></li>
<li>A <code>price</code> with a reasonable <code>discount_rate</code> (for example, a 10% discount)</li>
<li>A <code>price</code> with a 100% <code>discount_rate</code> (for example, if we want to give the product away)</li>
</ol>
<p>With these and our previous error cases, here's what Copilot Chat generated, after a little fine-tuning (re-prompting) and switching from Minitest to Rspec.</p>
<pre><code class="lang-ruby">RSpec.describe Product <span class="hljs-keyword">do</span>
  describe <span class="hljs-string">"#price_with_discount"</span> <span class="hljs-keyword">do</span>
    context <span class="hljs-string">"when given a valid price and discount rate"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"returns the price with the discount applied"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, <span class="hljs-number">100</span>, <span class="hljs-number">0</span>.<span class="hljs-number">2</span>)
        expect(product.price_with_discount(product.price, product.discount_rate)).to eq(<span class="hljs-number">80</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>

    context <span class="hljs-string">"when given a nil price"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"raises an ArgumentError with an appropriate message"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, <span class="hljs-literal">nil</span>, <span class="hljs-number">0</span>.<span class="hljs-number">2</span>)
        expect { product.price_with_discount(product.price, product.discount_rate) }.to raise_error(ArgumentError, <span class="hljs-string">"Price must be a positive number"</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>

    context <span class="hljs-string">"when given a price less than 0"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"raises an ArgumentError with an appropriate message"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, -<span class="hljs-number">100</span>, <span class="hljs-number">0</span>.<span class="hljs-number">2</span>)
        expect { product.price_with_discount(product.price, product.discount_rate) }.to raise_error(ArgumentError, <span class="hljs-string">"Price must be a positive number"</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>

    context <span class="hljs-string">"when given a nil discount rate"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"raises an ArgumentError with an appropriate message"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, <span class="hljs-number">100</span>, <span class="hljs-literal">nil</span>)
        expect { product.price_with_discount(product.price, product.discount_rate) }.to raise_error(ArgumentError, <span class="hljs-string">"Discount rate must be a float between 0 and 1"</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>

    context <span class="hljs-string">"when given a discount rate less than 0"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"raises an ArgumentError with an appropriate message"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, <span class="hljs-number">100</span>, -<span class="hljs-number">0</span>.<span class="hljs-number">2</span>)
        expect { product.price_with_discount(product.price, product.discount_rate) }.to raise_error(ArgumentError, <span class="hljs-string">"Discount rate must be a float between 0 and 1"</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>

    context <span class="hljs-string">"when given a discount rate greater than 1"</span> <span class="hljs-keyword">do</span>
      it <span class="hljs-string">"raises an ArgumentError with an appropriate message"</span> <span class="hljs-keyword">do</span>
        product = Product.new(<span class="hljs-string">"Test Product"</span>, <span class="hljs-number">100</span>, <span class="hljs-number">1.5</span>)
        expect { product.price_with_discount(product.price, product.discount_rate) }.to raise_error(ArgumentError, <span class="hljs-string">"Discount rate must be a float between 0 and 1"</span>)
      <span class="hljs-keyword">end</span>
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>One test for valid input, five for invalid input. All six work, and I didn't have to write them!</p>
<h3 id="heading-code-reviews">Code Reviews</h3>
<p>One feature of Copilot X is <a target="_blank" href="https://githubnext.com/projects/copilot-for-pull-requests#technical-preview-available-now">Copilot for Pull Requests</a>. Here are some of the key features:</p>
<ul>
<li><strong>Template Expansion</strong> – Leverage Copilot to fill in your PR template and explain code</li>
<li><strong>Gentest</strong> – Generate tests for your code based on Copilot's analysis</li>
<li><strong>Ghost Text</strong> – Receive suggestions while you're typing in the PR</li>
</ul>
<h3 id="heading-voice-driven-development">Voice-Driven Development</h3>
<p>Formerly known as "Hey, Github!", Copilot Voice allows you to use natural language prompts to interact with your code. It looks impressive, boasting these capabilities:</p>
<ul>
<li><strong>Write/Edit Code</strong> – Use voice controls to trigger Copilot code suggestions</li>
<li><strong>Code Navigation</strong> – Navigate a file without a keyboard or mouse</li>
<li><strong>Control the IDE</strong> – Trigger any VS Code command</li>
<li><strong>Code Summarization</strong> – Get summaries of blocks of code</li>
</ul>
<h2 id="heading-summary">Summary</h2>
<p>GitHub is rapidly producing revolutionary developer productivity tools with its suite of Copilot extensions. It's increasing my joy in programming and decreasing my time spent on mind-numbing tasks. I would encourage you to keep track of enhancements to Copilot as they're happening quickly.</p>
<p>Ignore click-bait promises of a "10x productivity gain", but don't ignore the research of <a target="_blank" href="https://github.blog/2022-09-07-research-quantifying-github-copilots-impact-on-developer-productivity-and-happiness/">Copilot's impact on developer productivity and happiness</a>. </p>
<p>Spend some time with Copilot tools trying out the use cases above, and I think you'll be surprised by its effect on your productivity and happiness.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 5 Truths Engineers Can't Tell Their Clients During a Production Outage ]]>
                </title>
                <description>
                    <![CDATA[ My birthday present this year was a production outage.  Some people go for cake and ice cream. Others plan a fun outing. I got an outage instead of an outing. And it was anything but fun. In the midst of it, my colleague and I vacillated between tria... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/5-truths-engineers-cant-tell-their-clients-during-a-production-outage/</link>
                <guid isPermaLink="false">66bccb60dcbc26cdff6679d1</guid>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Freelancing ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Tue, 06 Oct 2020 05:01:00 +0000</pubDate>
                <media:content url="https://cdn-media-2.freecodecamp.org/w1280/5f9c9850740569d1a4ca1957.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>My birthday present this year was a production outage. </p>
<p>Some people go for cake and ice cream. Others plan a fun outing. I got an outage instead of an outing. And it was anything but fun.</p>
<p>In the midst of it, my colleague and I vacillated between triaging the issue and fuming about how difficult it was to find its source. </p>
<p>And as I came up for air to connect with my patient and insightful wife, I shared with her how inadequate I felt, and consulted with her in how to communicate effectively with the affected client.</p>
<p>They needed to know we were going to fix it. They needed that fix to be fast. They needed to know the fix would last. </p>
<p>We tactfully crafted emails and had reassuring phone calls with them. We updated them often and gave them the right amount of transparency and technical insight.</p>
<p>But here are the truths that we couldn't tell them.</p>
<h2 id="heading-1-we-were-not-prepared-for-this">1. We were not prepared for this</h2>
<p>As is the case with many engineers on many projects, we inherited this application. We were left with little documentation and poor tools for debugging production. And there are too many moving parts to count. </p>
<p>It's like we're taking a fire extinguisher into a forest fire.</p>
<p>Our time and your financial budget didn't allow for extensive preparations for a production outage, and now we're facing the heat. In more ways than one, we were not prepared for this.</p>
<h2 id="heading-2-the-cause-of-the-outage-could-be-one-of-20-things">2. The cause of the outage could be one of 20 things</h2>
<p>The cause? Might be the server. Might be the code. Might be the database or a third-party package. Might be food poisoning. Might be our fault. Might be yours.</p>
<p>The solution? Might just need a restart. Might need an index on that database table. Might need to update that package or configuration setting. Might need Pepto-Bismol. Might need to burn the whole thing and start again.</p>
<h2 id="heading-3-we-have-absolutely-no-idea-how-long-its-going-to-take-to-fix">3. We have absolutely no idea how long it's going to take to fix</h2>
<p>A restart of the server could take ten minutes. A rebuild of the server could take anywhere from ten hours to ten days. We might be able to track down the bug in a few minutes, or we may never discover what actually happened. </p>
<p>It all depends on identifying the cause, and we've already established that could be one of 20 (or more) things.</p>
<p>We've also established that we weren't prepared for this. Might as well leave us alone and trust that we care enough to fix the problem as fast as possible. </p>
<p>In the meantime, we'd suggest you considering reworking your definition of "fast".</p>
<h2 id="heading-4-we-need-the-problem-to-manifest-again-before-we-can-figure-out-the-cause">4. We need the problem to manifest again before we can figure out the cause</h2>
<p>Because we have so little in the way of tools and documentation, we're basically flying blind. Thankfully, we've installed some monitoring tools to help us out. </p>
<p>The catch is that those tools can only monitor things going forward. So we need this intermittent issue to show up again before we can actually diagnose the problem.</p>
<p>We could certainly try this in a staging or test environment, and we did, but it's not succumbing to the same problems that production is experiencing. And, actually, it's an entirely different setup than production. </p>
<p>Our only option at this point is to take down production again. Tell your team to hold on tight while we pound production, not to try to fix it, but just to reproduce the problem so our tools can capture what's happening.</p>
<h2 id="heading-5-you-really-should-be-paying-us-more-for-this-level-of-stress">5. You really should be paying us more for this level of stress</h2>
<p>We're not sleeping. Barely eating. Our families haven't seen us for days. We spend all our time in front of a computer except for short bursts in front of the refrigerator, in the bathroom, or in the corner in the fetal position.</p>
<p>These stress levels warrant double pay, at least. But we realize now is not the time to negotiate a new contract. We're all in survival mode, and apparently, production's health is more important than our own. </p>
<p>And that's the reason why you should pay us (a lot) more during an emergency outage.</p>
<h2 id="heading-concluding-thoughts">Concluding Thoughts</h2>
<p>These are truths that engineers really can't communicate to their clients during the crisis of a production outage. </p>
<p>If you've thought some of these things, just know that many of us have thought them. If you resonate with these sentiments, many of us have felt this way. Production outages cause immense amounts of pressure and stress. </p>
<p>If you're wondering about the actual circumstances of my birthday outage, the issue was an intermittently unexpected response from a third-party email service. It caused an application error, but that error wasn't caught. </p>
<p>Instead, the request was tried again. And again. And then a few hundred (thousand?) more times until it brought the server to its knees. We'd restart the server and within another hour it was down again.</p>
<p>It took days to track down the actual cause, as our monitoring and debugging tools weren't honed. We saw spiked CPU and RAM usage but no clear link to rogue processes. We couldn't reproduce the problem in any environment but production. And the offending code was abstract and utilized libraries we weren't familiar with.</p>
<p>Next time, we'll be more prepared. We've installed tools to give us profiling capability and stack tracing for requests in production. We're going to be more cautious in implementing third-party tools and ensure our application can gracefully handle their failure. </p>
<p>I, personally, plan to negotiate a higher rate (likely 1.5 or 2 times my normal rate) for outages that make me drop all my other responsibilities.</p>
<p>Our preparation should also include a commitment to staying calm and silencing doubt. Panicking causes us to chase symptoms instead of focusing in on the source. Doubt tries to convince us we can't figure out the problem and never will be able to. </p>
<p>Operating out of a place of calm and confidence will bring that needed reassurance to our clients, and help us effectively navigate production outages. And have more fun on our birthdays.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Version a REST API ]]>
                </title>
                <description>
                    <![CDATA[ If you're not very familiar with APIs, you might be wondering...why all the fuss about API versioning?  If you've been burned by API changes, you're probably the one fussing. If you are a maintainer of an API, you might also be fussing about trying t... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-version-a-rest-api/</link>
                <guid isPermaLink="false">66bccb6c4a4c0beb784641d6</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ data contracts ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST ]]>
                    </category>
                
                    <category>
                        <![CDATA[ REST API ]]>
                    </category>
                
                    <category>
                        <![CDATA[ versioning ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tim Kleier ]]>
                </dc:creator>
                <pubDate>Tue, 03 Mar 2020 01:17:36 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/03/Art-Exhibit-Blog-Banner.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're not very familiar with APIs, you might be wondering...why all the fuss about API versioning? </p>
<p>If you've been burned by API changes, you're probably the one fussing. If you are a maintainer of an API, you might also be fussing about trying to field challenging questions like these:</p>
<pre><code># Is <span class="hljs-built_in">this</span> version <span class="hljs-number">2</span> <span class="hljs-keyword">of</span> just products or <span class="hljs-keyword">of</span> the entire API?
<span class="hljs-regexp">/v2/</span>products

# What catalyzed the change between v1 and v2? How are they different?
<span class="hljs-regexp">/v1/</span>products
/v2/products
</code></pre><p>These questions around versioning are not easy to answer. It's not always clear as to what <code>v1</code> or <code>v2</code> is referring to. And we should not just make a second version of an endpoint when the first no longer <em>seems</em> to suffice. </p>
<p>There are clear reasons <em>why</em> your API needs to have versioning, and there are clear strategies for <em>how</em> to effectively navigate API changes. </p>
<p>However, I have found that most developers--including myself, until I learned some lessons the hard way--are not aware of these reasons and strategies.</p>
<p>This article seeks to highlight those reasons for versioning and strategies for accomplishing it. We're going to assume a <a target="_blank" href="https://restfulapi.net/">REST</a> API context, as it's a standard for many APIs, and focus on the <em>versioning</em> aspect.</p>
<h2 id="heading-what-is-versioning">What is Versioning?</h2>
<p>We should start with level-setting on what is meant by the term "API versioning". Here's our working definition:</p>
<blockquote>
<p>API versioning is the practice of transparently managing changes to your API.</p>
</blockquote>
<p>Versioning is effective communication around changes to your API, so consumers know what to expect from it. You are delivering data to the public in some fashion and you need to communicate when you change the way that data is delivered.</p>
<p>What this boils down to, in the nitty gritty, is managing data contracts and breaking changes. The former is the primary building block of your API and the latter reveals why versioning is needed.</p>
<h3 id="heading-data-contracts">Data Contracts</h3>
<p>An API is an Application Programming <strong>Interface</strong>, and an interface is a <em>shared</em> boundary to exchange information. The data contract is the heart of this interface.</p>
<blockquote>
<p>A data contract is an agreement on the shape and general content of the request and/or response data. </p>
</blockquote>
<p>To illustrate a data contract, here's a basic JSON response body:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"data"</span>: [
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Product 1"</span>
    },
    {
      <span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>,
      <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Product 2"</span>
    }
  ]
}
</code></pre>
<p>It's an object with a <code>data</code> property that is an array (list) of products, each with an <code>id</code> and <code>name</code> property. But the <code>data</code> property could have just as easily been called <code>body</code>, and the <code>id</code> property on each product could have been a GUID instead of an integer. If a single product was being returned, <code>data</code> could be an object instead of an array. </p>
<p>These seemingly subtle changes would have made for a different agreement, a different contract, regarding the "shape" of the data. The data shape could apply to property names, data types, or even the expected format (JSON vs. XML).</p>
<h2 id="heading-why-is-versioning-needed">Why is Versioning Needed?</h2>
<p>With APIs, something as simple as changing a property name from <code>productId</code> to <code>productID</code> can break things for consumers. This very thing happened to our team last week. </p>
<p>Thankfully, we had tests to catch changes to the API contract. However, we shouldn't have needed those tests, because the maintainers of the API should have known this would be a breaking change.</p>
<h3 id="heading-breaking-changes">Breaking Changes</h3>
<p>This was a breaking change to the agreed upon data contract because their change forced us to change our application as well. </p>
<blockquote>
<p><em>What constitutes a "breaking change" in an API endpoint?</em> Any change to your API contract that forces the consumer to also make a change. </p>
</blockquote>
<p>Breaking changes primarily fit into the following categories:</p>
<ol>
<li>Changing the request/response format (e.g. from XML to JSON)</li>
<li>Changing a property name (e.g. from <code>name</code> to <code>productName</code>) or data type on a property (e.g. from an integer to a float)</li>
<li>Adding a required field on the request (e.g. a new required header or property in a request body)</li>
<li>Removing a property on the response (e.g. removing <code>description</code> from a product)</li>
</ol>
<h3 id="heading-api-change-management">API Change Management</h3>
<p>It is never wise or kind to force consumers of an API to make a change. If you must make a breaking change, that's what versioning is for, and we'll cover the most effective ways to version your application and endpoints. </p>
<p>But first let's briefly discuss how to avoid breaking changes in the first place. We could call this API change management.</p>
<p>Effective change management in the context of an API is summarized by the following principles:</p>
<ul>
<li>Continue support for existing properties/endpoints</li>
<li>Add new properties/endpoints rather than changing existing ones</li>
<li>Thoughtfully sunset obsolete properties/endpoints</li>
</ul>
<p>Here's an example that demonstrates all three of these principles in the context of the response for requesting user data:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"data"</span>: {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Carlos Ray Norris"</span>,     <span class="hljs-comment">// original property</span>
    <span class="hljs-attr">"firstName"</span>: <span class="hljs-string">"Carlos"</span>,           <span class="hljs-comment">// new property</span>
    <span class="hljs-attr">"lastName"</span>: <span class="hljs-string">"Norris"</span>,            <span class="hljs-comment">// new property</span>
    <span class="hljs-attr">"alias"</span>: <span class="hljs-string">"Chuck"</span>,                <span class="hljs-comment">// obsolete property</span>
    <span class="hljs-attr">"aliases"</span>: [<span class="hljs-string">"Chuck"</span>, <span class="hljs-string">"Walker"</span>]   <span class="hljs-comment">// new property</span>
  },
  <span class="hljs-attr">"meta"</span>: {
    <span class="hljs-attr">"fieldNotes"</span>: [
      {
        <span class="hljs-attr">"field"</span>: <span class="hljs-string">"alias"</span>,
        <span class="hljs-attr">"note"</span>: <span class="hljs-string">"Sunsetting on [future date]. Please use aliases."</span>
      }
    ]
  }
}
</code></pre>
<p>In this example, <code>name</code> was an original property. The <code>firstName</code> and <code>lastName</code> fields are being implemented to provide a more granular option, in the event that the consumer wants to display "Mr. Norris" with some string interpolation but without having to parse the <code>name</code> field. However, the <code>name</code> property will be supported in an ongoing fashion. </p>
<p><code>alias</code>, on the other hand, is going to be deprecated in favor of the <code>aliases</code> array--because Chuck has so many aliases--and there is a note in the response to indicate the sunsetting time frame.</p>
<h2 id="heading-how-do-you-version-an-api">How Do You Version an API?</h2>
<p>These principles will take a long way in navigating changes to your API without needing to roll a new version. However, sometimes it's avoidable, and if you need a brand new data contract, you'll need a new version of your endpoint. So you'll need to communicate that to the public in some way.</p>
<p>As an aside, do note that we're not talking about the version of the underlying code base. So if you're using <a target="_blank" href="https://semver.org/">semantic versioning</a> for your application that also supports a public API, you will likely want to separate those versioning systems.</p>
<p>How do you create a new version of your API? What are the different methods for doing so? You'll need to determine what <em>type</em> of versioning strategy you want to take in general, and then as you develop and maintain your API, you'll need to determine the <em>scope</em> of each version change.</p>
<h3 id="heading-scope">Scope</h3>
<p>Let's tackle scope first. As we explored above, sometimes data contracts will be compromised by a breaking change, and that means we'll need to provide a new version of the data contract. That could mean a new version of an endpoint, or it could mean a change at a more global application scope.</p>
<p>We can think of levels of scope change within a tree analogy:</p>
<ul>
<li><strong>Leaf</strong> - A change to an isolated endpoint with no relationship to other endpoints</li>
<li><strong>Branch</strong> - A change to a group of endpoints or a resource accessed through several endpoints</li>
<li><strong>Trunk</strong> - An application-level change, warranting a version change on most or all endpoints</li>
<li><strong>Root</strong> - A change affecting access to all API resources of all versions</li>
</ul>
<p>As you can see, moving from leaf to root, the changes become progressively more impactful and global in scope.</p>
<p>The <em>leaf</em> scope can often be handled through effective API change management. If not, simply create a new endpoint with the new resource data contract.</p>
<p>A <em>branch</em> is a little trickier, depending on just how many endpoints are affected by the data contract change on the resource in question. If the changes are relatively confined to a clear group of related endpoints, you could potentially navigate this by introducing a new name for the resource and updating your docs accordingly.</p>
<pre><code># variants, which has a breaking change, is accessed on multiple routes
/variants
/products/:id/variants

# we introduce product-variants instead
/product-variants
/products/:id/product-variants
</code></pre><p>A <em>trunk</em> refers to application-level changes that are often a result of a change in one of the following categories:</p>
<ul>
<li>Format (e.g. from <a target="_blank" href="https://www.w3schools.com/xml/xml_whatis.asp">XML</a> to <a target="_blank" href="https://www.w3schools.com/js/js_json_intro.asp">JSON</a>)</li>
<li>Specification (e.g. from an in-house one to <a target="_blank" href="https://www.freecodecamp.org/news/p/ccead735-3d4a-4304-b4e2-57b78ce59156/jsonapi.org">JSON API</a> or <a target="_blank" href="https://www.openapis.org/">Open API</a>)</li>
<li>Required headers (e.g. for authentication/authorization)</li>
</ul>
<p>These will necessitate a change in your overall API version, so you should plan carefully and execute the transition well. </p>
<p>A <em>root</em> change will force you to go one step further in ensuring that all consumers of all versions of your API are aware of the change.</p>
<h2 id="heading-types-of-api-versioning">Types of API Versioning</h2>
<p>As we turn to different types of API versioning, we'll want to use these insights into varying scopes of API changes to evaluate the types. Each approach has its own set of strengths and weaknesses in addressing changes based on their scope.</p>
<p>There are several methods for managing the version of your API. URI path versioning is the most common.</p>
<h3 id="heading-uri-path">URI Path</h3>
<pre><code>http:<span class="hljs-comment">//www.example.com/api/v1/products</span>
http:<span class="hljs-comment">//api.example.com/v1/products</span>
</code></pre><p>This strategy involves putting the version number in the path of the URI, and is often done with the prefix "v". More often than not, API designers use it to refer to their application version (i.e. "trunk") rather than the endpoint version (i.e. "leaf" or "branch"), but that's not always a safe assumption.</p>
<p>URI path versioning implies orchestrated releases of application versions that will require one of two approaches: maintaining one version while developing a new one or forcing consumers to wait for new resources until the new version is released. It also means you'd need to carry over any non-changed endpoints from version to version. However, for APIs with relatively low volatility, it's still a decent option.</p>
<p>You would likely not want to relate your version number to that of the endpoint or resource, because it would easily result in something like a <code>v4</code> of <code>products</code> but a <code>v1</code> of <code>variants</code>, which would be rather confusing.</p>
<h3 id="heading-query-params">Query Params</h3>
<pre><code>http:<span class="hljs-comment">//www.example.com/api/products?version=1</span>
</code></pre><p>This type of versioning adds a query param to the request that indicates the version. Very flexible in terms of requesting the version of the resource you'd like at the "leaf" level, but it holds no notion of the overall API's version and lends itself to the same out-of-sync issues mentioned in the above comment on endpoint-level versioning of the URI path.</p>
<h3 id="heading-header">Header</h3>
<pre><code>Accept: version=<span class="hljs-number">1.0</span>
</code></pre><p>The header approach is one that provides more granularity in serving up the requested version of any given resource. </p>
<p>However, it's buried in the request object and isn't as transparent as the URI path option. It's also still hard to tell whether <code>1.0</code> refers to the version of the endpoint or the API itself.</p>
<h3 id="heading-integrating-types">Integrating Types</h3>
<p>Each of these approaches seem to have the weakness of either favoring a "leaf" or "trunk" scope, but not supporting both. </p>
<p>If you need to maintain the overall API version and also provide support for multiple versions of resources, consider a blend of the URI Path and Query Params types, or a more advanced Header approach.</p>
<pre><code># URI path and query params combo
<span class="hljs-attr">http</span>:<span class="hljs-comment">//api.example.com/v1/products?version=1</span>
http:<span class="hljs-comment">//api.example.com/v1/products?version=2</span>

# Extended headers, <span class="hljs-keyword">for</span> http:<span class="hljs-comment">//api.example.com/products</span>
Accept: api-version=<span class="hljs-number">1</span>; resource-version=<span class="hljs-number">1</span>
<span class="hljs-attr">Accept</span>: api-version=<span class="hljs-number">1</span>; resource-version=<span class="hljs-number">2</span>
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>We've covered a lot of ground here, so let's recap:</p>
<ul>
<li>API versioning is the practice of transparently managing changes to your API.</li>
<li>Managing an API boils down to defining and evolving data contracts and dealing with breaking changes.</li>
<li>The most effective way to evolve your API without breaking changes is to follow effective API change management principles.</li>
<li>For most APIs, versioning in the URI path is the most straightforward solution.</li>
<li>For more complex or volatile APIs, you can manage varying scopes of changes by employing an integration of URI path and query params approaches.</li>
</ul>
<p>Although these principles should provide clear direction in how to effectively manage change to your APIs, evolving an API is potentially more of an art than a science. It requires thought and foresight to create and maintain a reliable API.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
