<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ben Brazier</title>
    <description>The latest articles on DEV Community by Ben Brazier (@bentorvo).</description>
    <link>https://dev.to/bentorvo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F874794%2F54c49247-c909-4db3-b2ae-e4826200a387.png</url>
      <title>DEV Community: Ben Brazier</title>
      <link>https://dev.to/bentorvo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bentorvo"/>
    <language>en</language>
    <item>
      <title>How to Blue-Green with DNS</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Mon, 26 Sep 2022 08:52:09 +0000</pubDate>
      <link>https://dev.to/bentorvo/how-to-blue-green-with-dns-2c8a</link>
      <guid>https://dev.to/bentorvo/how-to-blue-green-with-dns-2c8a</guid>
      <description>&lt;p&gt;The Domain Name System or DNS is the main way traffic is routed on the internet. It can be used to route traffic to one or many servers and can be chained so that the same url can lead to different locations at different points in time. This is what enables blue-green deployment of software and releasing new versions of software without downtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6wLdpZjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/601sgavz86bysk5gthly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6wLdpZjt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/601sgavz86bysk5gthly.png" alt="DNS Blue-Green Releasing" width="293" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So how can we use DNS to blue-green our software? In this article we will go through the process step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Blue Green Deployment?
&lt;/h2&gt;

&lt;p&gt;First we need to understand what blue-green means. Blue-green deployment is the process of provisioning more than one production environment so that you can set up a new version before cutting over to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--weW3XZY6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6a8p2mvg7p0k1oy06za.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--weW3XZY6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6a8p2mvg7p0k1oy06za.png" alt="DNS Cut-over" width="578" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By having both environments running you can quickly switch over to the new version which minimizes downtime and allows you to switch back to the previous version if needed. This is in contrast to an in-place update that relies on stopping the production environment, updating it, and starting it again.&lt;/p&gt;

&lt;p&gt;More information about blue-green deployment can be found &lt;a href="https://martinfowler.com/bliki/BlueGreenDeployment.html"&gt;here&lt;/a&gt; in Martin Fowlers blog post from 2010.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Deploy A Version of Our Software with an A Record
&lt;/h2&gt;

&lt;p&gt;In order to make use of blue-green deployment via DNS we first need to deploy a running version of our software. We can deploy a single host or multiple and create a DNS Record pointing their IP addresses. This will let us consistently access our service without needing to know the hosts IP addresses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GktL_HeW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ijucb33wsbphpu1rmgeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GktL_HeW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ijucb33wsbphpu1rmgeg.png" alt="Blue A Record" width="293" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this DNS record we should use an A record, which is a type of DNS record that maps hostnames to IP addresses. There are multiple types of DNS records with different purposes and A records are the most basic. We need one A record for each deployment.&lt;/p&gt;

&lt;p&gt;The best way to do this is using a version number in the A record and deploying a new set of infrastructure for each version to achieve immutable infrastructure and rolling deployments. It is also possible to just have two static environments that could be labelled blue and green.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create a CNAME DNS Record for our Application
&lt;/h2&gt;

&lt;p&gt;The next DNS record we need to create is a CNAME. A CNAME is an alias from one hostname to another, this means it can be used for redirects or to provide multiple names for a single service. We should provision a CNAME that our customers use for accessing our service so we have control of the routing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W5nXJdmS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufy54qb6rix6bpav8jol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W5nXJdmS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufy54qb6rix6bpav8jol.png" alt="CNAME Record to Blue" width="659" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This record should not be versioned as there is only one per environment and we use it as a lookup for where traffic should be routed. Here are some examples of what the initial CNAME and A record might look like:&lt;/p&gt;

&lt;pre&gt;
CNAME Record -&amp;gt; A Record
logging.company.com -&amp;gt; logging-01.company.com
logging.company.com -&amp;gt; 01.logging.company.com
logging.company.com -&amp;gt; logging-blue.company.com
logging.company.com -&amp;gt; blue.logging.company.com
&lt;/pre&gt;

&lt;h3&gt;
  
  
  3. Deploy a New Version of our Software with an A Record
&lt;/h3&gt;

&lt;p&gt;After our system is running and customers are using the CNAME for accessing our service we can deploy a new version of the software. It can be deployed right next to our current version and once deployed we should be able to access it via its own A record.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n5_AG-Em--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9awxctdpjvya9f82f9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n5_AG-Em--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p9awxctdpjvya9f82f9t.png" alt="Green A Record" width="293" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next we should run automated integration and regression tests so that we are confident the environment is working as expected and we can move onto the cut-over. It is important to make sure these tests don't impact the other deployments as they may share databases and other resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Update our Applications CNAME DNS Record
&lt;/h2&gt;

&lt;p&gt;To cut-over our application to the new version we just update our CNAME record to point at the new A record. This should be quick but depending on the time to live (TTL) of the DNS record may take some time to propagate since DNS is cached in multiple places based on the TTL provided. I usually recommend 60 seconds as a good standard for DNS TTL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V9iW7lbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp44pandut43sxvznq94.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V9iW7lbo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cp44pandut43sxvznq94.png" alt="CNAME Record to Green" width="659" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If any errors occur or we aren't happy with the new environment we can revert by redirecting the CNAME back at the old A record. This should be quick and easy to do due to the simplicity of the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Cleanup
&lt;/h2&gt;

&lt;p&gt;After the cut-over we may need to clean up the previous environment by deleting it or uninstalling any software that is left running. This can happen immediately or after some time but should be done as needed based on your specific environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Blue-green deployments are critical to minimizing risk and downtime of software releases and DNS is the main way to do so. There are many variations of this process but it is important to keep the process simple. Let me know if this is how you release new versions of your software and if there are any other parts of DNS releases you would like me to cover.&lt;/p&gt;

&lt;p&gt;For more content like this follow or contact me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>webdev</category>
      <category>cloud</category>
    </item>
    <item>
      <title>4 Reasons Not To Use Environment Variables</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Tue, 02 Aug 2022 03:39:00 +0000</pubDate>
      <link>https://dev.to/bentorvo/4-reasons-to-not-use-environment-variables-459l</link>
      <guid>https://dev.to/bentorvo/4-reasons-to-not-use-environment-variables-459l</guid>
      <description>&lt;p&gt;Environment variables are a simple way to configure software. They let you set a variable in the shell so that any processes you run can use the values provided. &lt;/p&gt;

&lt;p&gt;This is extremely helpful for cli tools but shouldn't be used for managing configuration of complex software. &lt;/p&gt;

&lt;p&gt;In order to understand why, we need to look at the downsides of using environment variables for configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jqoxi7gli34xnhz5u0r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jqoxi7gli34xnhz5u0r.png" alt="ENV vs FILE"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. All Types Must be Parsed from Strings
&lt;/h2&gt;

&lt;p&gt;Environment variables are always set as strings. This means any value that needs to be set as another type in the software will need to parse it from a string. &lt;/p&gt;

&lt;p&gt;For example, if I want an integer from the environment variable "FOO" in python I would need to run the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os
foo = int(os.environ['FOO'])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiwc5w5ed3sldygqip6f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuiwc5w5ed3sldygqip6f.png" alt="Parsing Types"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This requires an understanding of how the programming language parses strings into the appropriate datatypes and requires a lot more testing than directly using native data structures. This problem is also extended to include files. &lt;/p&gt;

&lt;p&gt;If you want to configure files like ssh keys or ssl certs then doing so with environment variables can get very messy due to newlines and formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. No Nesting or Built In Structure
&lt;/h2&gt;

&lt;p&gt;Environment variables are global values, which means that they can have naming collisions. For example, if you need to set the "URL" for multiple downstream services they will need to be prefixed to prevent collisions like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FOO_URL=x.com
BAR_URL=y.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lack of structure leads to long names that can unintentionally overlap with other services or features if you are not careful. &lt;/p&gt;

&lt;p&gt;It also prevents encapsulation and grouping of configuration values. Using structured data like JSON or YAML instead can allow you to pass through groups of keys without needing to worry about the parent structure of the configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Global Access within a Process
&lt;/h2&gt;

&lt;p&gt;Good software engineering minimises the use of global state so that code is easy to test and trace. Environment variables do not - they actively encourage the use of global state and make it very easy to pull in values from anywhere. The deeper in the code this is the harder it can be to inject configuration and run tests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os

def a():
    foo = int(os.environ['FOO'])
    return foo * 42

def b(foo):
    return foo * 42
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the python example above function "a" is much harder to test than function "b" because we have separated the management of configuration from the pure functionality. This doesn't go away by avoiding environment variables but in my experience it is a contributing factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Need to be Set at Runtime
&lt;/h2&gt;

&lt;p&gt;Environment variables need to be set in the process before running an application. This creates additional complexity in starting and managing processes. If you execute a python application that pulls config from a file it requires no additional shell commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However if you need to set environment variables it will need to be scripted into the specific shell of the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FOO=BAR &amp;amp;&amp;amp; python3 app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Environment variables are a great way to get started in managing software for configuration, however any complex software should replace the use of environment variables with file based configuration like JSON or YAML. &lt;/p&gt;

&lt;p&gt;This makes managing the configuration simpler and enables a more mature implementation of types, testing, and process management.&lt;/p&gt;

&lt;p&gt;For one example of how to implement configuration files refer to:  &lt;a href="http://torvo.com.au/articles/how-to-use-feature-flags" rel="noopener noreferrer"&gt;How to Use Feature Flags&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more content like this follow or contact me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>DevOps 101: Packaging Software</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Wed, 13 Jul 2022 05:35:29 +0000</pubDate>
      <link>https://dev.to/bentorvo/devops-101-packaging-software-2l6p</link>
      <guid>https://dev.to/bentorvo/devops-101-packaging-software-2l6p</guid>
      <description>&lt;p&gt;Packaging code is a key step in the software development life cycle. It is the process of taking source code, installing any dependencies that are required and converting it to code that can be executed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rBP6_wKG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrs2a5lwv2u0o4bti87w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rBP6_wKG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vrs2a5lwv2u0o4bti87w.png" alt="DevOps 101 Packaging Software" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Anyone who develops and maintains software will need to package a new version of their code any time the source code or its dependencies change. Doing this on a frequent basis will need to automate the process, so how do we do it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Packaging with Shell Scripts
&lt;/h2&gt;

&lt;p&gt;Firstly, we need to start with packaging our code. The most common way to package software is using shell commands (BASH or ZSH) on Linux. Most server environments run Linux and we can run them on Mac directly or on Windows with Windows Subsystem for Linux (WSL). Using these commands we need to copy our code into an empty directory, install our dependencies and run our unit tests. An example package script for a Python application could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env bash

set -e

# Make sure our distribution directory exists
mkdir -p ./dist/

# Cleanup any old files from previous packaging
rm -rf ./dist/*

# Install any dependencies listed in requirements
python3 -m pip install -r ./requirements.txt -t ./dist/

# Copy our source code into our distribution
cp -rf ./src/* ./dist/

( cd ./dist/; python3 -m unit_test)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By automating our packaging process with a simple readable script like this we can constantly package and test our code. We can also add and modify steps within the process very easily to use any language specific tooling or testing frameworks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Run Our Script
&lt;/h2&gt;

&lt;p&gt;Packaging software can be done locally or on remote build agents. It is a good idea to have the flexibility to do either so that developers can locally work on their code whilst still being able to deliver changes with central tooling for transparency and traceability.&lt;/p&gt;

&lt;p&gt;To package our code locally we can simply execute the script from a compatible terminal. To run the script in a central tool like GitLab we can add a CICD configuration file that runs the script whenever we commit changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing Our Code
&lt;/h2&gt;

&lt;p&gt;Unit testing should be done as part of our packaging process in order to maintain confidence that our software works or to get fast feedback if it doesn't. These tests will validate that our code executes and provides the expected responses based on our inputs. They don't require configuration to integrate with other systems and should be able to run without connecting to other services.&lt;/p&gt;

&lt;p&gt;We can run our unit tests before installing dependencies or after packaging our files, depending on how much our code integrates with other libraries. An example set of unit tests that runs within a Python module might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python3

from . import add

print("Unit Testing Mathematics")
assert add(1, 1) == 2, "Failed addition test A001"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Storing Our Package
&lt;/h2&gt;

&lt;p&gt;Once we have tested our package we can upload it to a central storage location such as AWS S3, Google Cloud Storage, Azure Blob Storage or an FTP server. This will give us access to the working software that is ready for configuration and deployment without needing to repackage it. This is highly specific to the location of the upload but the services will usually provide an appropriate cli tool that allows us to handle this upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Packaging code is the first step in this process of delviering software and should be automated to that we can quickly and effectively deliver working software to our customers on a frequent basis. By choosing flexible tools and including testing as part of the process we can speed up software development whilst keeping the process as simple as clicking a button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1AP8UXOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4iw0yykvccusdkzgkkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1AP8UXOt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n4iw0yykvccusdkzgkkm.png" alt="Package, Configure, Deploy, &amp;amp; Release" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After packaging our code we need to configure it for deployment and release. In an upcoming article we will discuss the process of automating configuration and how it can be done without relying on complex tools or repetitive manual work.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How to Use Feature Flags</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Tue, 05 Jul 2022 05:26:32 +0000</pubDate>
      <link>https://dev.to/bentorvo/how-to-use-feature-flags-39md</link>
      <guid>https://dev.to/bentorvo/how-to-use-feature-flags-39md</guid>
      <description>&lt;p&gt;Feature flags or feature toggles are settings that control how software runs and which features are enabled or disabled. Feature flags should be configured on the same host our software runs on using structured data formats to ensure that they are performant, stable and easy to manage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NnHxlL1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xic5o09p5peauysas28w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NnHxlL1o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xic5o09p5peauysas28w.png" alt="Feature Flags" width="300" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Feature Flags
&lt;/h2&gt;

&lt;p&gt;By using feature flags it is possible to integrate incomplete functionality into our software without breaking the whole system. Feature flags also allow us to test in production environments and roll out functionality to small groups of users at a time. This can be helpful when aiming to continuously integrate and deliver new code on a frequent basis.&lt;/p&gt;

&lt;p&gt;Feature flags can be as simple as enabling features based on the environment, or as complex as modifying what functionality to use for different users at different points in time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Network Requests
&lt;/h2&gt;

&lt;p&gt;When we configure feature flags we can do so on the host that is running our software or somewhere else over the network. However, we should avoid making network requests to get our feature flags because it can increase outages, slow down our systems and make changes harder to manage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XsCHVLIp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk2jdkb0ndbl63x3p0gz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XsCHVLIp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lk2jdkb0ndbl63x3p0gz.png" alt="Network Requests" width="300" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If feature flags need to be accessed over a network, any time a host handles a request it can cause failures due to throttling. This can be common for processes running in serverless environments or environments that scale up and down frequently. The problem of throttling can be mitigated by getting the values and caching them locally or in a data store, but doing so can increase code complexity whilst also introducing more issues related to caching.&lt;/p&gt;

&lt;p&gt;When feature flag configuration is accessed via a network call the latency of any request increases based on the response time of that system. This can cause long and unpredictable latency compared to the consistency of making a request to the local environment.&lt;/p&gt;

&lt;p&gt;If feature flags are stored externally the values and system that manages the configuration may change separately to the host that needs the flags. This can lead to configuration changes being modified in production with potential outages if things are misconfigured. Instead it is better to change the feature flag configuration with the service and test them before releasing the software.&lt;/p&gt;

&lt;h2&gt;
  
  
  Avoid Environment Variables
&lt;/h2&gt;

&lt;p&gt;Environment variables are often used to pass values to command-line interface software that needs configuration. This is a quick and easy way to change settings but we should avoid using them to configure feature flags.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lBvz8LDq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jj0pycu8o9eflh2x7fqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lBvz8LDq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jj0pycu8o9eflh2x7fqf.png" alt="Environment Variables" width="300" height="163"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Environment variables are limited to string only, so any software that needs to write or read environment variables needs to parse the strings into appropriate data types. This complexity is extra work on both the software and any tooling that manages the software, which shouldn't be necessary.&lt;/p&gt;

&lt;p&gt;Environment variables are not structured and are globally scoped within a process, which means that any structured keys need to be flattened. As an example, to set the property C of group B within software A to the value 9090 we would need to flatten the environment variable as:&lt;/p&gt;

&lt;pre&gt;A_B_C="9090"&lt;/pre&gt;

&lt;p&gt;This extra parsing and global scope can lead to even more complex handling of the environment variables.&lt;/p&gt;

&lt;p&gt;It is hard to package and include environment variables with software as they are loaded in at run time. To set the values we need to run commands or a script setting the values on the host for the shell that the software runs in. One option is to load them from a file by exporting everything in it just before running the software. This works, but there is a better way ...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;We can configure the feature flags for our software by including a structured data file such as JSON/YAML within our software directory as config.json/config.yaml. We can then load this file when our software starts and parse it with built in tooling. We can use built in types as well as structured config for different flags.&lt;/p&gt;

&lt;h3&gt;
  
  
  config.json
&lt;/h3&gt;

&lt;pre&gt;{
    "features": {
        "customer_icon": {
            "enabled": true
        },
        "billing_alerts": {
            "release_date": "2022-08-06"
        },
        "date_format": "%Y-%m-%d",
        "console": {
            "version": 1.0
        }
    }
}
&lt;/pre&gt;

&lt;h3&gt;
  
  
  config.yaml
&lt;/h3&gt;

&lt;pre&gt;---
features:
  customer_icon:
    enabled: true # We can also write comments in yaml
  billing_alerts:
    release_date: '2022-08-06'
  date_format: "%Y-%m-%d"
  console:
    version: 1.0 # Should be updated to 2.0 soon
&lt;/pre&gt;

&lt;p&gt;We can avoid network issues by storing the feature flag configuration on the host running the software. By including it as a file on the host we reduce the latency to almost 0 and avoid outages caused by network failures.&lt;/p&gt;

&lt;p&gt;We can also avoid the limitations of environment variables by using structured data formats such as JSON and YAML. This lets us structure our data appropriately and use built in types other than strings.&lt;/p&gt;

&lt;p&gt;To use these feature flags we just load them in and switch functionality on or off depending on the values. Here is a Python example:&lt;/p&gt;

&lt;pre&gt;import datetime
import json

# Loading JSON File
configuration = json.loads(open('./config.json', 'r').read())

# Date Format
date_format = configuration['features']['date_format']
print("Using Date Format:", date_format)

# Todays Date
date_today = datetime.datetime.today()
print("Todays Date:", date_today.strftime(date_format))

# Billing Alerts
billing_alerts_release_date = datetime.datetime.strptime(
    configuration['features']['billing_alerts']['release_date'],
    date_format
)
print(
    "Billing Alerts Release Date", 
    billing_alerts_release_date.strftime(date_format)
)
if billing_alerts_release_date &amp;lt; date_today:
    print("Billing Alerts Are Enabled")
else:
    print("Billing Alerts Aren't Enabled Yet")

# Customer Icon
print(
    "Showing Customer Icon", 
    configuration['features']['customer_icon']['enabled']
)

# Console Version
print(
    "Using Console Version", 
    configuration['features']['console']['version']
)
&lt;/pre&gt;

&lt;p&gt;This is how we can enable or disable features, release functionality on a specified date, and use built in types to manage our configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Structured configuration files are the best way to manage feature flags without worrying about network issues or parsing everything in and out of environment variables. This can also be used to manage any environment specific settings within our system as a central point of control.&lt;/p&gt;

&lt;p&gt;There are many more positive side effects of configuring software with structured files that we haven't covered yet. Let us know if this solution works for you or if you have any further questions.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>python</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The Truth About Continuous Delivery</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Mon, 04 Jul 2022 04:55:29 +0000</pubDate>
      <link>https://dev.to/bentorvo/the-truth-about-continuous-delivery-2983</link>
      <guid>https://dev.to/bentorvo/the-truth-about-continuous-delivery-2983</guid>
      <description>&lt;p&gt;Continuous delivery is hard. There is no simple way to learn all of the moving parts required to automate packaging, configuring, deploying, testing and releasing code. It isn’t something you can implement in a week and it requires time and effort to work towards.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--56_7ubbr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/od6xyh6gqxqll4rt3whn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--56_7ubbr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/od6xyh6gqxqll4rt3whn.png" alt="Continuous Delivery" width="351" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If every step in the process is done with a different tool, by a different team, or in a different location, then it can feel impossible to continuously deliver on a daily basis. But it isn’t. You can continuously deliver code without needing to know 15 different tools and talk to 5 different teams within your organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Continuous Delivery?
&lt;/h2&gt;

&lt;p&gt;Continuous delivery is about having the ability to go from source code to production quickly and in a fully automated process. It enables small, frequent updates that minimise risk and maximise feedback. The benefits are generally well understood across the industry but the implementations vary. Some teams deliver changes to production every few minutes, while others can take weeks or months to release new code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UNWCBdGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0unz9ddw0t03w51gj358.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UNWCBdGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0unz9ddw0t03w51gj358.png" alt="Code Into Production" width="404" height="172"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It should be possible for most teams to deliver changes daily, but in order to understand why we need to know what issues can get in the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it so Difficult?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dev and Ops&lt;/strong&gt; culture separation can be a strong contributor to how well teams can continuously deliver. A significant factor in the culture of a team is resourcing.&lt;/p&gt;

&lt;p&gt;It is easy to find developers who want to write code on their laptop but hard to find developers who want to manage infrastructure.&lt;/p&gt;

&lt;p&gt;It is easy to find operations people who want to manage infrastructure but hard to find operations people who want to write code.&lt;/p&gt;

&lt;p&gt;It is especially hard to find team members that want to write, deploy, test, release and support services when a large part of the industry prefers to split these tasks into different teams and even different sections of an organisation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w3lz_2dw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtu00ftxpuqfr7e1kic0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w3lz_2dw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qtu00ftxpuqfr7e1kic0.png" alt="Dev &amp;amp; Ops" width="394" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tools and vendors&lt;/strong&gt; are a dime a dozen. For any part of the continuous delivery process, you can find a handful of tools and vendors trying to get you to use them. This makes it extremely easy to pick up and add complexity to the stack, which simultaneously raises the bar of knowledge required and often hides the underlying fundamentals of how software is delivered.&lt;/p&gt;

&lt;p&gt;Even when implementing a tool for each step in continuous delivery it is common to find gaps and integration points that aren’t supported and require an understanding of the whole stack to resolve. This is why we should focus on a minimal stack and treat every extra tool or vendor as a debt in both the technical and business sense.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--J0UpxsEC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbcd12j7zvyd5soqq8gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--J0UpxsEC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mbcd12j7zvyd5soqq8gk.png" alt="Tools &amp;amp; Vendors" width="775" height="152"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guidance and training&lt;/strong&gt; is easy to find when it comes to using one of the vendor provided tools, but is hard to find if you just want to understand the fundamentals. But where and how can we learn the fundamentals?&lt;/p&gt;

&lt;p&gt;I have been asked a lot in my work to provide reference for how to implement continuous delivery and in my experience there is a lot of theory available but not much implementation. I believe this is a problem that needs to be resolved in the industry right now, which is what I am aiming to achieve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zDXa6V27--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1x4ljfptijeou2r02x4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zDXa6V27--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1x4ljfptijeou2r02x4g.png" alt="Continuous Delivery Training" width="348" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How Can We Make it Easier?
&lt;/h2&gt;

&lt;p&gt;When it comes to complex problems we need to think long and hard about our options. In the words of Kent Beck, “make the change easy, then make the easy change”. But how do we make the change easy?&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--M032bvJq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/2550670043/xq10bqclqpsezgerjxhi_normal.jpeg" alt="Kent Beck profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Kent Beck
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @kentbeck
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      for each desired change, make the change easy (warning: this may be hard), then make the easy change
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      23:07 PM - 25 Sep 2012
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=250733358307500032" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=250733358307500032" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=250733358307500032" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Firstly, we must reduce the number of different tools we use and focus our effort on a few key solutions. The more different tools you use, the more knowledge is split up and harder to share.&lt;/p&gt;

&lt;p&gt;Tools used across the industry range from code, to DSLs, to cli tools, and more &lt;strong&gt;.&lt;/strong&gt; However, the one thing that we can always rely on is code. Instead of using declarative languages or cli tools we should focus our efforts on code and writing re-usable packages that can be integrated with other tasks. There is no good reason why we can’t package, configure, deploy, test and release code within a single programming language after getting it’s dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nfL437ET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9vmtomya8pz79i9mqhi8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nfL437ET--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9vmtomya8pz79i9mqhi8.png" alt="Less Tools More Simplicity" width="682" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, we can invest in understanding the implementation. Instead of learning many different tools we can focus on the fundamentals of both the steps required and automation in general.&lt;/p&gt;

&lt;p&gt;This is significantly harder initially but results in far better long term goals because tools come and go but understanding is retained.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mY-cKrb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mox67v38vtztb092hfnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mY-cKrb5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mox67v38vtztb092hfnv.png" alt="Continuous Learning" width="390" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thirdly, we need to iterate on your implementation. No matter how simple the system or how much knowledge you have there is no way to improve without iteration because each environment is different. Each change we make may or may not improve things, and the only way to know is to try.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--omIcwi3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1p0ezpslfwq4jy2ioki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--omIcwi3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1p0ezpslfwq4jy2ioki.png" alt="Iterating on Continuous Delivery" width="390" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Continuous delivery is hard, but it doesn’t have to be. By simplifying what is required, focusing on our understanding and investing in learning we can continuously improve our ability to deliver software.&lt;/p&gt;

&lt;p&gt;I recently posted a tutorial demonstrating an MVP for Continuous Delivery in the simplest way I could. It only requires the use of Bash, Python and AWS, which should make it approachable for any developer who can code.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/9Lc1UpHQNQE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I want to help improve the quality of software delivery across the industry so please let me know if this is valuable to you or if you have any suggestions.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>development</category>
      <category>programming</category>
      <category>microservices</category>
      <category>devops</category>
    </item>
    <item>
      <title>6 Symptoms of a Distributed Monolith</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Fri, 01 Jul 2022 04:47:23 +0000</pubDate>
      <link>https://dev.to/bentorvo/6-symptoms-of-a-distributed-monolith-ken</link>
      <guid>https://dev.to/bentorvo/6-symptoms-of-a-distributed-monolith-ken</guid>
      <description>&lt;p&gt;Distributed monoliths occur when the structure of an organisation and its code is split up whilst still being tightly coupled. This becomes a problem because the scale of the system increases but all of its parts need to be managed together, slowing down and increasing the risk of any changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsubbp1jb6xremug2h0x1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsubbp1jb6xremug2h0x1.png" alt="6 Symptoms of a Distributed Monolith"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is important to be able to identify when you are dealing with a distributed monolith but how can we? Lets look at 6 symptoms that your software architecture is a distributed monolith.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Lock Step Deployment
&lt;/h2&gt;

&lt;p&gt;When two services need to be deployed together, they are coupled. If they are within a monolith this can be easy to manage. However, deployment can become slow and painful if they are separate services that should actually be managed independently. We can resolve this problem by identifying the cause of the coupling and refactoring our solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq28c81h9sm0g6x8bmh0n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq28c81h9sm0g6x8bmh0n.png" alt="Lock Step Deployment"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the two services use shared code, the solution could be restructuring the code to share a library that is managed separately. If they use shared infrastructure, this could mean splitting the services onto separate hosts.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Version Coupling
&lt;/h2&gt;

&lt;p&gt;If Service A directly calls a version of Service B, every time Service B is updated we need to update the configuration of Service A. This coupling of changes can make it complex to manage the lifecycles of both applications but it is possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbuz6wa0d5dc14jisri0c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbuz6wa0d5dc14jisri0c.png" alt="Version Coupling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ideally, Service A should call an endpoint for Service B that isn't a specific version and is also managed by Service B. This can usually be done with DNS by using CNAMES like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A1.domain.com &amp;gt; calls &amp;gt; B.domain.com &amp;gt; B1.domain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A1.domain.com &amp;gt; calls &amp;gt; B1.domain.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Bi-directional Dependencies
&lt;/h2&gt;

&lt;p&gt;If Service A calls Service B and Service B calls Service A, it can be difficult to test changes to either system. When this happens we have the option of changing the whole environment simultaneously, testing events being sent to through both the old and new versions of software, or significant extra complexity in how to route messages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1sxz52o9jve47rcashqc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1sxz52o9jve47rcashqc.png" alt="Bi-directional Dependencies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Shared Database Access
&lt;/h2&gt;

&lt;p&gt;When two services share the same database access it becomes easy to pull data from another domain without calling the service directly. This can lead to coupled services that are connected at the database layer. When a service modifies it's own database structure it shouldn't impact any other services. If it does, then the services are coupled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7kdwf0g1rzbx8v13kaa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft7kdwf0g1rzbx8v13kaa.png" alt="Shared Database Access"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is nothing wrong with sharing a database to save on administrative effort but this should be tightly controlled with security to prevent coupling. A common way to do this with Postgres is by using separate users and schemas per service. If a service wants access to another service's data it should call the downstream service directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Shared Queues
&lt;/h2&gt;

&lt;p&gt;In the same way that shared database access causes coupling, so too do shared queues. If two services talk to a shared queue directly, it isn't possible for either service to safely modify, change or redirect the messages without risk of breaking both services.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb4x9mbv0qtpjs96porh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyb4x9mbv0qtpjs96porh.png" alt="Shared Queues"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sharing queues should be avoided as much as possible and any queue should be owned by a single service and not exposed to others.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Enterprise Service Bus
&lt;/h2&gt;

&lt;p&gt;The enterprise service bus (ESB) is another common data storage pattern similar to shared databases and shared queues but on a larger scale. ESBs aim to allow any message to be sent and received via a central bus. This means that once a service sends a message to the bus it is not clear who is consuming the message, what is being done with it, and if it succeeded. These issues can't be easily resolved and mean that our system becomes coupled with not only one other system but more than we may be aware of.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f8kyc1wrenmn56dqazs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f8kyc1wrenmn56dqazs.png" alt="The Enterprise Service Bus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Regardless of your system architecture you should be able to clearly identify if your system is a monolith, microservices, or a distributed monolith. Identifying coupling to other services through shared deployments, shared data, and bidirectional dependencies is critical in this process. Doing so will allow us to structure our architecture so that we can avoid ending up with a distributed monolith.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>programming</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Pros and Cons of AWS Lambda Function URLs</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Thu, 30 Jun 2022 04:17:04 +0000</pubDate>
      <link>https://dev.to/bentorvo/the-pros-and-cons-of-aws-lambda-function-urls-524d</link>
      <guid>https://dev.to/bentorvo/the-pros-and-cons-of-aws-lambda-function-urls-524d</guid>
      <description>&lt;p&gt;AWS Lambda Function URLs were released on the 6th of April 2022 as an infrastructure configuration that gives you public URLs to directly trigger AWS Lambda Functions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7irh2b8u3rq0tp9umszy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7irh2b8u3rq0tp9umszy.png" alt="The Pros and Cons of AWS Lambda Function URLs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This service provides a faster and simpler way to trigger AWS Lambda Functions than AWS API Gateway or AWS Application Load Balancer (ALB). The URLs follow a standard structure as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://**&amp;lt;url-id&amp;gt;**.lambda-url.**&amp;lt;region&amp;gt;**.on.aws
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pro: Fast Implementation &amp;amp; Deployment
&lt;/h2&gt;

&lt;p&gt;AWS Lambda Function URLs are very quick to configure and deploy whilst requiring less set up than the other alternatives. When I set up the endpoint it is almost instantly available for use and only really requires a few configuration values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xz3fgxt1e5sw9gmqb43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xz3fgxt1e5sw9gmqb43.png" alt="AWS API Gateway and AWS ALB are Slow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS API Gateway takes longer to deploy and requires a more complex set of resources to set up. The API, Resources, Methods, Deployment, Stage, and Lambda Permissions are all part of setting this up.&lt;/p&gt;

&lt;p&gt;AWS ALB requires additional underlying resources to be configured and has an upfront cost to using it. There is quite a bit that goes into designing AWS networks but at a minimum they contain a VPC, Subnets, IGW, and Security Groups. AWS ALBs also require multiple different resources to make up a working system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pro: IAM for Access Control
&lt;/h2&gt;

&lt;p&gt;The options for AWS Lambda Function URLs authentication are None or using IAM. When you use None any additional security should be within the code. However, when you use IAM you can reference IAM resources with significant granularity. This means that if you and your customers both use AWS there is a strong and simple integration point for security by just referring to their AWS IAM resources directly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm18hwjkitdd7wsn6x07g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm18hwjkitdd7wsn6x07g.png" alt="AWS IAM to AWS Lambda"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pro: AWS Lambda Alias Support
&lt;/h2&gt;

&lt;p&gt;AWS Lambda Aliases are also supported by the new URLs which means that you can keep a consistent public facing URL when replacing the underlying infrastructure. This isn’t as practical as if it was done with DNS but can work if you don’t mind the AWS Lambda alias and versioning system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3skuv45kmb4bqrys4qk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz3skuv45kmb4bqrys4qk.png" alt="AWS Lambda Aliases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Con: No Custom DNS Support
&lt;/h2&gt;

&lt;p&gt;As mentioned previously DNS can’t be used for AWS Lambda Function URLs which can be an issue for both releases and the presentation of the service to customers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6iwy5y3djj4xbjekrsj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy6iwy5y3djj4xbjekrsj.png" alt="No Custom DNS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The lack of custom DNS is similar to the Private AWS API Gateway and can cause issues if you use DNS automation for release processes.&lt;/p&gt;

&lt;p&gt;It is possible to work around the custom DNS issue by deploying AWS CloudFront and pointing at the URL on the backend. This is about the same effort as deploying AWS API Gateway, which negates the benefits of using the new feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Con: AWS Account ID Exposure
&lt;/h2&gt;

&lt;p&gt;According to AWS the new URLs expose the AWS Account ID used for the service which can provide information to any malicious actors. AWS Account IDs are not considered a credential for security purposes but publishing this information should probably be avoided where possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m6uhl325v1l1saac6ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m6uhl325v1l1saac6ma.png" alt="AWS Account ID Exposure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Con: Limited Network Controls
&lt;/h2&gt;

&lt;p&gt;Due to the implementation of AWS Lambda Function URLs there is no way to implement network controls based on IP or any lower level than the prior mentioned authorisation. This is a limitation that could be an issue depending on your environment. For large enterprises like I have worked for in the past it is not acceptable but if you are running a start up it may be worth sacrificing for the speed to implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f2hjb1bfaep4ttf7ct2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f2hjb1bfaep4ttf7ct2.png" alt="No IP Controls"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;It is always good to see more functionality being added to AWS Lambda and serverless solutions. However, the new AWS Lambda Function URLs leave a lot to be desired in their access controls and DNS implementation. Hopefully we will get custom DNS as a feature in the near future so that we don’t have to use AWS Aliases and the AWS provided URLs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqaun458mijf8muf5o1x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpqaun458mijf8muf5o1x.png" alt="URL vs ALB vs API"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-urls.html" rel="noopener noreferrer"&gt;Lambda function URLs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>programming</category>
      <category>devops</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Why Cache Invalidation Doesn't Work</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Wed, 29 Jun 2022 00:04:58 +0000</pubDate>
      <link>https://dev.to/bentorvo/why-cache-invalidation-doesnt-work-1i54</link>
      <guid>https://dev.to/bentorvo/why-cache-invalidation-doesnt-work-1i54</guid>
      <description>&lt;p&gt;Using cache invalidation to release a new version of a website doesn’t work.&lt;/p&gt;

&lt;p&gt;When developing a small website it is easy to skip the process of managing caching and just serve everything directly. However, once a website scales up and starts leveraging a Content Distribution Network (CDN) it is important to implement a proper caching strategy. When developers skip this step it can result in customers receiving out of date content and even broken websites.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AvgLofeI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6h3teh84r90vlt3zmb1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AvgLofeI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o6h3teh84r90vlt3zmb1.jpeg" alt="Cache Invalidation Doesn’t Work" width="700" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CDNs Use Caches
&lt;/h2&gt;

&lt;p&gt;Content Distribution Networks (CDN) are commonly used to cache responses to web requests for performance. When a CDN caches a website it will serve content without returning to the origin. This saves time and provides a better customer experience. However, if the CDN has cached content it can serve information that is out of date. One of the ways developers can roll out new content is by invalidating the cache with tools provided by the CDN.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dCWysNpZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nawcwe1sth2e1o6wpg3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dCWysNpZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nawcwe1sth2e1o6wpg3h.png" alt="Common CDN Providers" width="880" height="660"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Cache Invalidation Doesn’t Work
&lt;/h2&gt;

&lt;p&gt;Invalidating the cache at the CDN level doesn’t have any impact on the users browser or Internet Service Provider (ISP) caching. This means that even if you invalidate the cache there is no way to know what is happening from the customer’s perspective.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2FoSmqfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy8nec4yfw3n25st8zkr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2FoSmqfW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy8nec4yfw3n25st8zkr.png" alt="Caching Example" width="880" height="279"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browsers cache headers using the same instructions the CDN would. This means that if a user accesses your site, you subsequently invalidate the cache, and the user comes back to your site they can still be receiving the old versions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Invalidation is intended for use in exceptional circumstances, not as part of your normal workflow. Invalidations don’t affect cached copies in web browser caches or caches operated by third-party internet service providers. — &lt;a href="https://cloud.google.com/cdn/docs/cache-invalidation-overview"&gt;Google&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is also common for ISPs to cache the data of commonly used websites to save them networking costs and reduce the load on the servers they own.&lt;/p&gt;

&lt;p&gt;Once a user’s browser or an ISP caches your content you cannot remove it from the cache. This is why cache invalidation doesn’t work and alternative solutions should be used.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are The Alternatives?
&lt;/h2&gt;

&lt;p&gt;Instead of invalidating caches when making changes to websites we should use appropriate cache headers or cache busting. It is common for websites to set caching headers by default but it is important to use them properly to avoid the need for cache invalidation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Expires
&lt;/h3&gt;

&lt;p&gt;We could use the expires header to set a time for when a specific object should be cleared from the cache. However, it can be difficult to manage this header and it has some technical issues:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the time format is difficult to parse, many implementation bugs were found, and it is possible to induce problems by intentionally shifting the system clock — &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching"&gt;Mozilla&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Expires: Tue, 28 Feb 2022 22:22:22 GMT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Cache-Control: Max-Age
&lt;/h3&gt;

&lt;p&gt;Generally we should use the max-age header to provide a duration that an object should be cached. A good starting point is to set this to 86400, which is equal to one day as the header is set in seconds. This means that if you rolled out a new version of a site it would be guaranteed to show up to all users after 24 hours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cache-Control: max-age=86400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cache Busting
&lt;/h2&gt;

&lt;p&gt;If we want to use caching but also roll out instant updates to our customers we can use a more complex solution known as Cache Busting. By setting a unique URL or query string value to our requests caches will treat each version as a new object. This means if we deploy new links with every change and never cache the initial index.html we can load new files without waiting for the cache to clear the old ones.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Initial link  
/css/main.css?1653714985
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# New link  
/css/main.css?1653715024&amp;lt;/pre&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Next time you need to invalidate a cache to deploy a website change try using max-age or cache busting instead. It will save you time and effort every deployment whilst providing confidence that the correct files are being served to your customers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--msZoQISP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ka40m5j4wv026wvrhtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--msZoQISP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0ka40m5j4wv026wvrhtm.png" alt="Cache Control &amp;amp; Busting Instead of Invalidation" width="366" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  More Information
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching"&gt;HTTP caching - HTTP | MDN&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control"&gt;Cache-Control - HTTP | MDN&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more content follow me here or contact me via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>programming</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>5 AWS Lambda Pitfalls Most Developers Don't Know About</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Tue, 28 Jun 2022 03:37:03 +0000</pubDate>
      <link>https://dev.to/bentorvo/5-aws-lambda-pitfalls-most-developers-dont-know-about-io4</link>
      <guid>https://dev.to/bentorvo/5-aws-lambda-pitfalls-most-developers-dont-know-about-io4</guid>
      <description>&lt;p&gt;Using AWS Lambda can save a lot of time in getting services up and running but has some major drawbacks when used extensively. It is important to understand these pitfalls as they don’t usually matter until you run into them in production when it is too late to avoid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flq0u6tjxnbdba88c5ipk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flq0u6tjxnbdba88c5ipk.png" alt="AWS Lambda Pitfalls"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Private API Gateway is Incompatible with Custom DNS
&lt;/h2&gt;

&lt;p&gt;It is common in large scale software development to use private networking to increase security of internal services. This helps prevent unauthorized access to services that should never be available for public consumption. AWS Lambda supports this by using AWS VPC when configured appropriately.&lt;/p&gt;

&lt;p&gt;It is also standard in most software development to use DNS to decouple services. DNS lets you deploy a new version of a service and cutover to it without modifying the existing service, this works because DNS records are just a pointer for where the service is hosted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaqfjx43kn4qrlbpqh9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqaqfjx43kn4qrlbpqh9r.png" alt="Private AWS API Gateway"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One of the common configurations of AWS Lambda uses AWS API Gateway to make the lambda accessible as a HTTP endpoint. However if you use API Gateway in a private network configuration you cannot leverage custom hostnames. This means you can only use the AWS API Gateway DNS record that is tightly coupled to the infrastructure and therefore need to modify the infrastructure to release a new version of the service.&lt;/p&gt;

&lt;p&gt;Modifying the existing service infrastructure to release a new version increases the risk of the change and makes it harder to roll back.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Application Load Balancer to Lambda is Expensive
&lt;/h2&gt;

&lt;p&gt;Another frontend for AWS Lambda is AWS Application Load Balancer which fixes the prior mentioned DNS and networking issue. However, compared to the extremely low costs AWS API Gateway, this is an expensive alternative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblacknxbz84asuz6feyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblacknxbz84asuz6feyy.png" alt="AWS ALB is Expensive"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my region AWS ALB costs approximately $18 per month as a base (before the cost of compute power). This might not seem like much but with the prominence of microservices it is common for organisations to provision hundreds of different AWS Lambdas, which can lead to huge additional costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. AWS Lambda Environment Variables Exposed
&lt;/h2&gt;

&lt;p&gt;AWS Lambda can be configured with environment variables for things like database URLs, usernames, and passwords. This configuration shows up in the console when viewed with read only privileges. This means that giving people read only access in production can lead to exposed credentials.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgctjivonjty9m80mcry5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgctjivonjty9m80mcry5.png" alt="Example of Password Exposure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on your control of AWS IAM and your business environment this may or may not impact you but it is worth thinking about when configuring your services.&lt;/p&gt;

&lt;p&gt;An alternative solution to this is embed your configuration into your application zip, I will cover this in a future article so follow me here to get updates about that.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. API Gateway &amp;amp; Lambda Timeout Limits
&lt;/h2&gt;

&lt;p&gt;AWS Lambda has a hard timeout of 15 minutes and when used in conjunction with AWS API Gateway a maximum timeout of 29 seconds. This means that any request that goes longer than one of these, depending on the context, will throw an error and fail.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvzmliabfkz3e2gsni5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvzmliabfkz3e2gsni5t.png" alt="API Gateway &amp;amp; Lambda Limits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is important to handle these exceptions gracefully and return a response to the user but in order to do so we need to timeout before the timeout limit. This requires additional code to track the current duration of the execution, and cancelling it when getting too close to the timeout limit.&lt;/p&gt;

&lt;p&gt;AWS Lambda timeouts also cause extra work to manage long running processes. To run a permanent background process you will need to handle starting and stopping constantly to fit within timeouts. This is usually far more difficult than an EC2 based solution that keeps a single process open.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. SQS &amp;amp; Lambda Throughput Limit Errors
&lt;/h2&gt;

&lt;p&gt;When using the AWS SQS as a direct trigger for AWS Lambda and limiting the throughput of the AWS Lambda Function any additional requests will throw errors. These errors can wreak havoc on alerting systems because each of these errors will show in your metrics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76q8eqi93wq98nritnlc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76q8eqi93wq98nritnlc.png" alt="SQS &amp;amp; Lambda Limits"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It can also be a problem if you leverage dead letter queues as these failures contribute to the maximum retries per task without even invoking the lambda. Which can cause good messages to be pushed into the dead letter queue due to throughput limitations.&lt;/p&gt;

&lt;h2&gt;
  
  
  In Conclusion
&lt;/h2&gt;

&lt;p&gt;AWS Lambda is a great service that enables software development with minimal operational overhead, but like all tools it has limits and it is helpful to understand them. I often use AWS Lambda to get services running but find that moving to AWS EC2 based services is often more cost effective and simple in the long term.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>programming</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Git the Parts to Avoid</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Mon, 27 Jun 2022 06:45:40 +0000</pubDate>
      <link>https://dev.to/bentorvo/git-the-parts-to-avoid-4pad</link>
      <guid>https://dev.to/bentorvo/git-the-parts-to-avoid-4pad</guid>
      <description>&lt;p&gt;Git is a great tool for managing code changes over time and allowing code to be integrated by teams of developers. But even the most helpful tools can become problematic when misused, and we need to understand these drawbacks in order to avoid them. The most common problems with Git are caused by rewriting history and undoing changes that have already been made.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xb3hi7fjonjo5062n5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xb3hi7fjonjo5062n5h.png" alt="Git"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lets look at the parts of Git that we should avoid to keep our life as developers simple and easy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Squash
&lt;/h2&gt;

&lt;p&gt;The standard process for using Git is to clone a repository, make changes locally, then integrate them with the remote server. When a developer has committed multiple changes to a repository and pushes the code to the remote server there will be multiple commits showing in the version history. This is beneficial so that the changes can be tracked but sometimes is seen as confusing or hard to read.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86z3gbma7o128sua5xrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86z3gbma7o128sua5xrd.png" alt="Squash"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sometimes developers will use the git squash functionality to convert the multiple commits into a single commit so that a whole change is in one commit. However, this should be avoided for a few reasons.&lt;/p&gt;

&lt;p&gt;Firstly, it removes intermediary states, which means that when something goes wrong we are not able to access the commits between the start and the end of the change.&lt;/p&gt;

&lt;p&gt;Secondly, it rewrites the history of the changes and we lose track of when the commits were made. This results in less information being available to help identify when changes from different branches were made and when conflicts arose.&lt;/p&gt;

&lt;p&gt;Thirdly, it increases the size of changes, which in turn increases risk. It is far easier to deal with frequent small changes as opposed to infrequent large changes.&lt;/p&gt;

&lt;p&gt;Instead of using squash it is better to keep the commit history unmodified and present each commit as it was when made. This lets us keep the history of changes, review all of the commits made within a change, and manage the risk by making smaller changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Force Push
&lt;/h2&gt;

&lt;p&gt;Force push is a way to overwrite changes on the remote server with our version of the code. But doing this can cause issues for other team members and cause us to lose code changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmop1fwerxvqrg46vqoe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmop1fwerxvqrg46vqoe.png" alt="Force Push"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we force push our changes to the remote server, other developers working on the same code base may end up working off old code. If they pull the latest copy and you subsequently force push over the top of that, their clients will be out of sync. The problem is compounded if they respond by force pushing their own changes, causing the same issue for you.&lt;/p&gt;

&lt;p&gt;Forcing the overwrite of remote code can also lose changes that were made since your last pull. This can lead to old bugs coming back, failed builds, and the loss of work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Git is a great tool but when misused can cause a lot of issues. As part of using Git we should avoid rewriting history or undoing changes with functionality such as squash and force push. Doing so will help us keep our work simple and efficient.&lt;/p&gt;

&lt;p&gt;Follow me here for more content or contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>devops</category>
      <category>productivity</category>
      <category>git</category>
    </item>
    <item>
      <title>Deadlines Without Estimates</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Fri, 24 Jun 2022 06:45:39 +0000</pubDate>
      <link>https://dev.to/bentorvo/deadlines-without-estimates-45ld</link>
      <guid>https://dev.to/bentorvo/deadlines-without-estimates-45ld</guid>
      <description>&lt;p&gt;In my last article &lt;a href="https://dev.to/bentorvo/why-estimates-are-waste-1o0f"&gt;Why Estimates Are Waste&lt;/a&gt; we covered some problems with estimates but this raised some questions about managing deadlines. Most companies think that in order to meet deadlines we need to estimate and plan out all of our work. This isn’t the case and today we will cover why.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftljqmjaj25n94tkyd3jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftljqmjaj25n94tkyd3jk.png" alt="Smaller Releases Lowers Risk"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Large Releases Are Higher Risk
&lt;/h2&gt;

&lt;p&gt;Software delivery in large organisations is often managed by identifying a deadline far into the future, determining what is required for the deadline, then aiming to deliver on or just before that date.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1451360776233623557-665" src="https://platform.twitter.com/embed/Tweet.html?id=1451360776233623557"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1451360776233623557-665');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1451360776233623557&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;This leads to a large amount of time spent estimating and planning what can be done and in what order. The risk involved in this planning work should be taken seriously because the further in the future we plan the harder it is to be accurate. And as mentioned previously, estimates are only as valuable as they are accurate.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“there’s no value in wasting time estimating something that you know is going to change, and making long-term plans based on those estimates is foolhardy” —&lt;/em&gt; &lt;a href="https://holub.com/noestimates-an-introduction/" rel="noopener noreferrer"&gt;&lt;em&gt;Allen Holub&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Having a large amount of time between identifying customers needs and delivering value to them also increases the risk that the solution doesn’t work or isn’t what the customer wants.&lt;/p&gt;

&lt;p&gt;So how can we reduce the risk of large releases?&lt;/p&gt;

&lt;h2&gt;
  
  
  Deliver Frequently
&lt;/h2&gt;

&lt;p&gt;We may have a deadline set for 12 months from now, but what stops us delivering sooner?&lt;/p&gt;

&lt;p&gt;Instead of delivering a large solution in 12 months we can deliver a small one in 3 months. This gives us faster feedback and if we are going in the wrong direction we have saved 9 months of development. If things are going well we can continue to deliver every 3 months whilst incorporating feedback we wouldn’t otherwise have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly9u87j12x8ddezf1h6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fly9u87j12x8ddezf1h6d.png" alt="Continuous Delivery"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What if instead of delivering in 3 months we deliver today?&lt;/p&gt;

&lt;p&gt;We might not even be able to get a working version today, but how close can we get? If we try and deliver today it becomes clear that we need to only focus on the most important piece of work. This mentally lets us work with priorities instead of estimates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prioritisation Over Planning
&lt;/h2&gt;

&lt;p&gt;We don’t need plans, we need priorities. Priorities let us define what is important and trying to deliver a solution today can help guide us.&lt;/p&gt;

&lt;p&gt;We need priorities to identify what to work on but we only need enough prioritisation to continue working. Any effort spent not trying to deliver value to our customers as soon as possible is waste and slows us down.&lt;/p&gt;

&lt;p&gt;This is why in order to deliver more value faster all we need to do is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Identify the most valuable task.&lt;/li&gt;
&lt;li&gt; Work on that task.&lt;/li&gt;
&lt;li&gt; Repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If everyone in your organisation follows this process when delivering software I believe it will be a lot more effective than any other process you’ve seen.&lt;/p&gt;

&lt;p&gt;Contact me on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Twitter:&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Email:&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Website:&lt;/strong&gt; &lt;a href="http://torvo.com.au" rel="noopener noreferrer"&gt;torvo.com.au&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>management</category>
    </item>
    <item>
      <title>Why Estimates Are Waste</title>
      <dc:creator>Ben Brazier</dc:creator>
      <pubDate>Thu, 23 Jun 2022 06:58:27 +0000</pubDate>
      <link>https://dev.to/bentorvo/why-estimates-are-waste-1o0f</link>
      <guid>https://dev.to/bentorvo/why-estimates-are-waste-1o0f</guid>
      <description>&lt;p&gt;Software development is unpredictable but people waste hours every week trying to guess how long tasks will take.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f47d6gg56fexci0462x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5f47d6gg56fexci0462x.png" alt="No Estimates"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estimation can provide confidence in future changes, but this doesn’t apply to software development because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  If you can predict work then you should automate it instead of repeating it.&lt;/li&gt;
&lt;li&gt;  If you can’t predict work then attempting to do so is a waste of time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Automation Instead of Accurate Estimation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Repetition increases predictability.&lt;/strong&gt; It isn’t possible to accurately estimate how long a task will take if you have never done it. In other words, the more you repeat a task the more predictable it becomes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuglko2e9wduw2l9mmn9y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuglko2e9wduw2l9mmn9y.png" alt="Predictability ≈ Repetitions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Repeated work should be automated.&lt;/strong&gt; In software development the ability to re-use libraries, frameworks, and APIs means that repeatable work can be automated. The more you repeat it the more effort would be saved with code re-use and automation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymirbvaboetzhia2u5zk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fymirbvaboetzhia2u5zk.png" alt="Value of Automation ≈ Repetitions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accurate Estimates Correlate with Wasted Effort.&lt;/strong&gt; As repetitions increase the value of automating and the predictability both go up. Therefore …&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvut6o8rmjs3f0qu8fn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuvut6o8rmjs3f0qu8fn6.png" alt="V ≈ R ≈ P"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Inaccurate Estimation is Harmful
&lt;/h2&gt;

&lt;p&gt;If the purpose of estimation is to plan around the future then inaccurate estimates can only lead to problems. This is compounded by the cost of estimating work in time and effort.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1466892889439494147-224" src="https://platform.twitter.com/embed/Tweet.html?id=1466892889439494147"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1466892889439494147-224');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1466892889439494147&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Instead of spending time and effort on estimating work that can’t be predicted or should be automated we should find alternatives. One of the most agile approaches is to work without estimates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Without Estimates
&lt;/h2&gt;

&lt;p&gt;Working without estimates is critical to good software development and goes hand in hand with continuous delivery. The simplest process to work without estimates is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Identify the most valuable task.&lt;/li&gt;
&lt;li&gt; Work on that task.&lt;/li&gt;
&lt;li&gt; Repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is important to consider the time spent on estimating work and the value it provides. This minimal process may be too strict for you but next time you are estimating your work consider the value it provides.&lt;/p&gt;

&lt;p&gt;If you would like to discuss this further please contact me on &lt;strong&gt;Twitter&lt;/strong&gt; &lt;a href="https://twitter.com/BenTorvo" rel="noopener noreferrer"&gt;@BenTorvo&lt;/a&gt; or &lt;strong&gt;Email&lt;/strong&gt; &lt;a href="http://torvo.com.au/" rel="noopener noreferrer"&gt;ben@torvo.com.au&lt;/a&gt;&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>programming</category>
      <category>productivity</category>
      <category>management</category>
    </item>
  </channel>
</rss>
