<?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>Forem: Miles Watson</title>
    <description>The latest articles on Forem by Miles Watson (@mileswatson).</description>
    <link>https://forem.com/mileswatson</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%2F513901%2F9c5fdc4c-39cc-49a8-abd9-25fec9a3691f.JPG</url>
      <title>Forem: Miles Watson</title>
      <link>https://forem.com/mileswatson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mileswatson"/>
    <language>en</language>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (6/): Deploying to AWS</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Fri, 08 Oct 2021 15:31:31 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-6-deploying-to-aws-2gi0</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-6-deploying-to-aws-2gi0</guid>
      <description>&lt;p&gt;In the last post, we created a static front-end application with &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; + &lt;a href="https://bulma.io/" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt;, and then integrated it into our Rust code + Dockerfile. In this final post, we will cover the process of actually deploying the app to &lt;a href="https://aws.amazon.com/elasticbeanstalk/" rel="noopener noreferrer"&gt;AWS Elastic Beanstalk&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Elastic Beanstalk?
&lt;/h3&gt;

&lt;p&gt;Elastic Beanstalk is a service provided by AWS which enables developers to focus purely on application code, without worrying about the infrastructure the code is being run on. Although we won't be exploring the full power of EB, it is capable of capacity provisioning, load balancing, scaling, and application health monitoring. &lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Deployment
&lt;/h3&gt;

&lt;p&gt;The first step in manually deploying your application is to create a zipped archive of your code to upload to EB. As an effort to stay cross-platform, we will do this using &lt;code&gt;git archive&lt;/code&gt; (this has the added benefit of automatically ignoring anything in the gitignore).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git archive &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;zip HEAD &lt;span class="nt"&gt;-o&lt;/span&gt; ./target/repo.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will place a zip of our repo into the &lt;code&gt;target&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;Now we have the zip file, you should following the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to &lt;a href="//console.aws.amazon.com/"&gt;AWS Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Use the search bar to go to the "Elastic Beanstalk" page, and make sure you are in the "Elastic Beanstalk &amp;gt; Environments page"&lt;/li&gt;
&lt;li&gt;Select your desired region using the dropdown menu in the top right&lt;/li&gt;
&lt;li&gt;Click the "Create application" button (alternatively, click "Create Environment, and then select "Web server environment")&lt;/li&gt;
&lt;li&gt;Give your application a suitable name
&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%2Fj53b4wr1bah9x7nkidn5.png" alt="AWS console"&gt;
&lt;/li&gt;
&lt;li&gt;Give the application environment (the collection of services that will run your application) the name "production"
&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%2Fiwhwnllbbxmh6kewvjgs.png" alt="AWS console"&gt;
&lt;/li&gt;
&lt;li&gt;Select the following platform options: 
&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%2Fuqv9phv0fqjigtl439ji.png" alt="AWS console"&gt;
&lt;/li&gt;
&lt;li&gt;Upload your zip file, and then click "Create environment"
&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%2Fjf3e10lf095kv1t7hqdj.png" alt="AWS console"&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you go back the environments page, you will see that an environment with the name "production" has been created. It should have the status "Pending" - you will now have to wait around ten minutes for your application to build and startup (EB uses the &lt;code&gt;docker-compose.yml&lt;/code&gt; file to build the images from scratch on the underlying EC2 instance).&lt;/p&gt;

&lt;p&gt;Once the environment health transitions to "Ready", you should be able to go to the provided URL (HTTP &lt;em&gt;only&lt;/em&gt;, as setting up HTTPS is beyond the scope of this series).&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a Deployment Pipeline
&lt;/h3&gt;

&lt;p&gt;Manually updating your application like this can be time-consuming, so I will now show you how to automatically deploy your code with GitHub Actions.&lt;/p&gt;

&lt;p&gt;First, you will need to use the "IAM" service to create a user (so that the workflow can access your AWS account). The user should be called "url-shortener-deploy" and the credential type should be "Programmatic access".&lt;/p&gt;

&lt;p&gt;We will be using the &lt;a href="https://github.com/marketplace/actions/beanstalk-deploy" rel="noopener noreferrer"&gt;Beanstalk Deploy&lt;/a&gt;, which requires the &lt;code&gt;AWSElasticBeanstalkWebTier&lt;/code&gt; and &lt;code&gt;AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy&lt;/code&gt; permissions. Make sure to attach these to the IAM role, and then create the user.&lt;/p&gt;

&lt;p&gt;Once you have clicked &lt;code&gt;Create user&lt;/code&gt;, you will be shown a table with the access credentials. You will only be shown these once - don't close the window just yet. In a new tab, open your repo on GitHub and add the following secrets (Settings &amp;gt; Secrets &amp;gt; New repository secret):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS_ACCESS_KEY_ID&lt;/li&gt;
&lt;li&gt;AWS_SECRET_ACCESS_KEY
You should set these to the corresponding credentials of your &lt;code&gt;url-shortener-deploy&lt;/code&gt; user, and then close the credential view on the AWS console.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next, create a new workflow called &lt;code&gt;deploy.yml&lt;/code&gt; (this should be in the same directory as &lt;code&gt;test.yml&lt;/code&gt;). This action will use the secrets we set in the last step to deploy our code to AWS whenever code is pushed to production.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to AWS&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout Latest Repo&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@master&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;production"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Generate Deployment Package&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mkdir target &amp;amp;&amp;amp; git archive --format=zip HEAD -o ./target/repo.zip&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get timestamp&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gerred/actions/current-time@master&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;current-time&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run string replace&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frabert/replace-string-action@master&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;format-time&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;pattern&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[:\.]+'&lt;/span&gt;
          &lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;steps.current-time.outputs.time&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;replace-with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-"&lt;/span&gt;
          &lt;span class="na"&gt;flags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;g"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to EB&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;einaregilsson/beanstalk-deploy@v18&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws_access_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws_secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;application_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;url-shortener&lt;/span&gt;
          &lt;span class="na"&gt;environment_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
          &lt;span class="na"&gt;version_label&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url-shortener-${{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;steps.format-time.outputs.replaced&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
          &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eu-west-2&lt;/span&gt;
          &lt;span class="na"&gt;deployment_package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;target/repo.zip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: The string replacement step simply sets the code version to the current time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Testing Auto-Deployment
&lt;/h3&gt;

&lt;p&gt;Now that we have created the workflow, we need to push to the &lt;code&gt;production&lt;/code&gt; branch. Normally we can do this via a PR on the GitHub web interface, but that only works after we have created and pushed the branch. To do this, use the following git commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git branch production
git push origin production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all goes correctly, your workflow should take about 15 minutes to deploy your code to AWS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Now it's your turn!
&lt;/h3&gt;

&lt;p&gt;Now that you have the barebones structure up and running, perhaps you could try adding the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;persistance with an AWS-provided database (like Aurora or DynamoDB)&lt;/li&gt;
&lt;li&gt;expiring links, so that a given memory / storage limit isn't exceeded&lt;/li&gt;
&lt;li&gt;a fully fleshed-out frontend with common pages (such as an FAQ, contact us)&lt;/li&gt;
&lt;li&gt;a custom domain name + https support for EB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's all for this series! If you have any issues, make sure to check out the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-6" rel="noopener noreferrer"&gt;part-6 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>svelte</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (5/): Frontend</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Wed, 29 Sep 2021 17:04:06 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-5-frontend-p0n</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-5-frontend-p0n</guid>
      <description>&lt;p&gt;In the last post, we worked on containerizing the backend of our application, so that we can deploy it with a single command. In this post, we will create a static front-end application with &lt;a href="https://svelte.dev/" rel="noopener noreferrer"&gt;Svelte&lt;/a&gt; + &lt;a href="https://bulma.io/" rel="noopener noreferrer"&gt;Bulma&lt;/a&gt;, and then integrate it into our Rust code + Dockerfile. I will be using the &lt;a href="https://yarnpkg.com/" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt; package manager, but feel free to use &lt;code&gt;npm&lt;/code&gt; if you prefer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloning the Template
&lt;/h3&gt;

&lt;p&gt;First, run the following command in the root of your repo. This will create a directory called &lt;code&gt;svelte&lt;/code&gt; which contains a template that we'll use to build a simple frontend for our API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init svelte@next svelte
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Select the &lt;code&gt;Skeleton project&lt;/code&gt; template, &lt;code&gt;Yes&lt;/code&gt; to Typescript, and then &lt;code&gt;No&lt;/code&gt; to all the other questions.&lt;/p&gt;

&lt;p&gt;Inside the &lt;code&gt;svelte&lt;/code&gt; directory, run &lt;code&gt;yarn install&lt;/code&gt; to install dependencies, and then &lt;code&gt;yarn dev&lt;/code&gt; to start a dev server. By going to &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt; you should see a simple message:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrnua1zzka9velle7acb.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%2Fjrnua1zzka9velle7acb.png" alt="template welcome page"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Adding a Static Adapter
&lt;/h3&gt;

&lt;p&gt;Before we can deploy the site, we need to adapt it to our deployment target. SvelteKit provides a number of different adapters for platforms like Cloudflare Workers, Netlify, and Vercel. In our case, however, we will be using &lt;code&gt;adapter-static&lt;/code&gt; to prerender our entire site. &lt;/p&gt;

&lt;p&gt;First, we need to install the adapter using Yarn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add &lt;span class="nt"&gt;--dev&lt;/span&gt; @sveltejs/adapter-static@next
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to change the &lt;code&gt;svelte.config.js&lt;/code&gt; file to configure the adapter. Import the adapter...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;adapter&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/adapter-static&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...then update &lt;code&gt;config.kit&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// hydrate the &amp;lt;div id="svelte"&amp;gt; element in src/app.html&lt;/span&gt;
    &lt;span class="nl"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// prerender the pages so they can be served statically&lt;/span&gt;
    &lt;span class="nx"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;adapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By running &lt;code&gt;yarn build&lt;/code&gt;, you should see that the &lt;code&gt;/svelte/build&lt;/code&gt; directory is populated with an &lt;code&gt;index.html&lt;/code&gt; file (among some other files / folders).&lt;/p&gt;

&lt;h3&gt;
  
  
  Serving with Rocket
&lt;/h3&gt;

&lt;p&gt;Now that we have statically built our application, we can serve it with Rocket. To do so, simply change our launch function to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[launch]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.manage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;DashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;routes!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;shorten&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="nf"&gt;.mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nd"&gt;cfg!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debug_assertions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// debug mode, therefore serve relative to crate root&lt;/span&gt;
                &lt;span class="nn"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nd"&gt;relative!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/svelte/build"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// dockerized, therefore serve from absolute path&lt;/span&gt;
                &lt;span class="nn"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/app/static"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;if cfg!(debug...&lt;/code&gt; statement will become clearer later on, when we update the Dockerfile.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing Tests
&lt;/h3&gt;

&lt;p&gt;Unfortunately, you may get an email saying that your Github Actions tests have failed. If you look at the logs, it should be apparent that the &lt;code&gt;FileServer&lt;/code&gt; failed to mount, because it couldn't find the provided directory. To fix this, we can add steps to install yarn, install dependencies, and then build the static site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Rust&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Yarn&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install --global yarn&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Dependencies&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn --cwd svelte install&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build Svelte&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;yarn --cwd svelte run build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the sake of completion, I also added a simple test to check that the static site is being served as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;static_site&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid rocket instance"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.dispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tests should now pass as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the Dockerfile
&lt;/h3&gt;

&lt;p&gt;Currently our Dockerfile uses two images - one to build the Rust project, and the second to run the executable. Now we need to add a third one for building the static site.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;
&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--offline&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; .

&lt;span class="c"&gt;# use a node image for building the site&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:16&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;static&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /svelte&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./svelte .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn build

&lt;span class="c"&gt;# use a slim image for actually running the container.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rust:slim&lt;/span&gt;

&lt;span class="c"&gt;# ...&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/local/cargo/bin/aws-rust-api /usr/local/bin/aws-rust-api&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=static /svelte/build/ ./static&lt;/span&gt;

&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to start your application using &lt;code&gt;docker-compose --build&lt;/code&gt; and see your site when you go to &lt;a href="http://127.0.0.1" rel="noopener noreferrer"&gt;http://127.0.0.1&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Functionality
&lt;/h3&gt;

&lt;p&gt;Although our site is being served statically, we still don't have any functionality! First, we will add support for simple Bulma styling to the &lt;code&gt;app.html&lt;/code&gt; &lt;code&gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&lt;/code&gt; tags.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will be using &lt;a href="https://www.npmjs.com/package/superagent" rel="noopener noreferrer"&gt;SuperAgent&lt;/a&gt; for making API requests, so let's add it to our dependency list.&lt;br&gt;
&lt;code&gt;yarn add superagent&lt;/code&gt;&lt;br&gt;
Next, we will create a &lt;code&gt;routes/__layout.svelte&lt;/code&gt; file, which will wrap around any of the routes in the directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"svelte"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container is-fluid my-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar is-dark"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"navigation"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-brand"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"navbar-item ml-5 is-dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.png"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"32"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"logo"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"title is-2 navbar-item"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;URL Shortener&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;slot&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us a simple, function-less navbar to go across the top of the screen.&lt;br&gt;
Next, change the &lt;code&gt;index.svelte&lt;/code&gt; file to contain the following script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;superagent&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;superagent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;superagent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/shorten?url=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`http://&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we can bind to these variables / functions by appending the following to the &lt;code&gt;index.svelte&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    {#if request == null}
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"field has-addons"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"control"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
                    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt;
                    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
                    &lt;span class="na"&gt;bind:value=&lt;/span&gt;&lt;span class="s"&gt;{url}&lt;/span&gt;
                    &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"URL"&lt;/span&gt;
                &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"control"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"button is-info"&lt;/span&gt; &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{click}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Shorten&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    {:else}
        {#await request}
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        {:then response}
            &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-header-title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Done!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt;
                        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"content"&lt;/span&gt;
                        &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;{getUrl(response.text)}&lt;/span&gt;
                        &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{getUrl(response.text)}&lt;span class="nt"&gt;&amp;lt;/a&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-footer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
                        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-footer-item button"&lt;/span&gt;
                        &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; (request = null)}&amp;gt;Back&lt;span class="nt"&gt;&amp;lt;/button&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;
                        &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"card-footer-item button is-info"&lt;/span&gt;
                        &lt;span class="na"&gt;on:click=&lt;/span&gt;&lt;span class="s"&gt;{()&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                            navigator.clipboard.writeText(
                                getUrl(response.text)
                            )}&amp;gt;Copy&lt;span class="nt"&gt;&amp;lt;/button&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/footer&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        {:catch}
            &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Something went wrong!&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
        {/await}
    {/if}
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;bind:value={url}&lt;/code&gt; is one of Svelte's special two-way bindings - updating the textbox will update the variable, and vice versa.&lt;/p&gt;

&lt;p&gt;When the user clicks the button, the &lt;code&gt;click&lt;/code&gt; function will start an asynchronous request to the API, and set the &lt;code&gt;request&lt;/code&gt; variable to the uncompleted promise.&lt;/p&gt;

&lt;p&gt;This will then cause the page to show &lt;code&gt;Loading...&lt;/code&gt; until the request completes, at which point the shortened URL is displayed (with some buttons).&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Product
&lt;/h3&gt;

&lt;p&gt;If you did everything correctly, you should be able to run &lt;code&gt;docker-compose up --build&lt;/code&gt; and use your site at &lt;a href="http://127.0.0.1" rel="noopener noreferrer"&gt;http://127.0.0.1&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGmSKZx4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGmSKZx4.gif" alt="URL Shortener Demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all for this post! If you have any issues, make sure to check out the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-5" rel="noopener noreferrer"&gt;part-5 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;p&gt;In the next post, we will cover the basics of EB, and set up a CD pipeline for automatically deploying your program to the cloud. Make sure to click the "Follow" button if you want to be alerted when the next part is available!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>svelte</category>
      <category>aws</category>
      <category>docker</category>
    </item>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (4/): Dockerizing</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Sat, 25 Sep 2021 13:50:30 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-4-dockerizing-2e38</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-4-dockerizing-2e38</guid>
      <description>&lt;p&gt;In the last post, we created some unit tests that will allow us to automatically test our application. In this post, we will cover the process of Dockerizing our application in preparation for deploying with AWS Elastic Beanstalk.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Docker?
&lt;/h3&gt;

&lt;p&gt;Explaining fully the features and advantages / disadvantages of Docker would take an entire blog post in itself, so if you aren't familiar with the concept of containers then watch the following video:&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Installing Docker
&lt;/h3&gt;

&lt;p&gt;The easiest way to use Docker is with Docker Desktop (&lt;a href="https://docs.docker.com/desktop/mac/install/"&gt;mac&lt;/a&gt; / &lt;a href="https://docs.docker.com/desktop/windows/install/"&gt;windows&lt;/a&gt;). This will install both the &lt;code&gt;docker&lt;/code&gt; and &lt;code&gt;docker-compose&lt;/code&gt; tools. &lt;/p&gt;

&lt;p&gt;For Linux users, you have to first install &lt;a href="https://docs.docker.com/engine/install/"&gt;Docker Engine&lt;/a&gt;, and then install &lt;a href="https://docs.docker.com/compose/install/"&gt;Docker Compose&lt;/a&gt; separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the Docker File
&lt;/h3&gt;

&lt;p&gt;First, create an empty file in the root of your repo called &lt;code&gt;Dockerfile&lt;/code&gt; (no file extension). This file will contain a list of repeatable instructions that tells Docker how to build our container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# select a starting image to build off&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rust as build&lt;/span&gt;

&lt;span class="c"&gt;# set our working directory in the container as /repo&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /repo&lt;/span&gt;

&lt;span class="c"&gt;# copy all our files across from our local repo to the /repo directory in the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Cargo.lock .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Cargo.toml .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;

&lt;span class="c"&gt;# build the release&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; .

&lt;span class="c"&gt;# allow requests to port 8000&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;

&lt;span class="c"&gt;# this command is run when we actually start the container&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["aws-rust-api"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Building and running the container
&lt;/h3&gt;

&lt;p&gt;We can build the Docker image with the following command (make sure to run it from the root of the repo). This can take a while - we'll work on optimizing build times later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; url-shortener &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-t url-shortener&lt;/code&gt; part tags our image so that we can run it in the next step, whilst the &lt;code&gt;.&lt;/code&gt; indicates the Dockerfile is in the current directory.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Ensure that the Docker daemon is running, or the Docker commands may fail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once the container has been built, we can start it with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; my-running-app &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 url-shortener
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: the &lt;code&gt;-p 8000:8000&lt;/code&gt; means that we are binding port 8000 of our local machine to port 8000 of the Docker container.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application should appear to start as normal - however, you will notice that you cannot connect. This is because our program is listening on &lt;code&gt;127.0.0.1&lt;/code&gt;, but we need it to listen on all available network interfaces (&lt;code&gt;0.0.0.0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;We can fix this using a &lt;code&gt;Rocket.toml&lt;/code&gt; configuration file to configure the address and port for Release mode.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[release]&lt;/span&gt;
&lt;span class="py"&gt;address&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.0.0.0"&lt;/span&gt;
&lt;span class="py"&gt;port&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file is read by the Rocket instance on program start up, as long as it is in the directory where the program is run. We can put it in there by adding the following line to the Dockerfile, just before the &lt;code&gt;CMD&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Rocket.toml . &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should also change the &lt;code&gt;EXPOSE&lt;/code&gt; line to expose port 80 (rather than 8000).&lt;/p&gt;

&lt;p&gt;We can  build the image and run it again, and you should be able to connect to it by going to &lt;a href="http://127.0.0.1"&gt;http://127.0.0.1&lt;/a&gt;. Remember to bind to port &lt;code&gt;80&lt;/code&gt; instead of &lt;code&gt;8000&lt;/code&gt; in the &lt;code&gt;docker run&lt;/code&gt; command this time!&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Compose
&lt;/h3&gt;

&lt;p&gt;To simplify the process of creating and running the Docker images, we will create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file in the root of the repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.9"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;url-shortener&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting our container is now as simple as running &lt;code&gt;docker-compose up&lt;/code&gt;, but make sure to append &lt;code&gt;--build&lt;/code&gt; if you want to force an image rebuild.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency Caching
&lt;/h3&gt;

&lt;p&gt;If you try and change a small part of your code, you may notice that a tiny change requires downloading and installing every dependency again when building the image. This is because of how Docker's cache works - if a copied file changes at all, then every step after that copy must be recalculated.&lt;/p&gt;

&lt;p&gt;We can fix this by splitting our Docker file into two builds - the first build to install dependencies without copying our code, and the second to build the code without reinstalling dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;

&lt;span class="c"&gt;# copy all our files across from our local repo to the /repo directory in the container&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Cargo.lock .&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Cargo.toml .&lt;/span&gt;

&lt;span class="c"&gt;# cache dependencies by creating an empty&lt;/span&gt;
&lt;span class="c"&gt;# lib.rs file and building the project&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;src
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"// empty file"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; src/lib.rs
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt;

&lt;span class="c"&gt;# now copy the code over&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src src&lt;/span&gt;

&lt;span class="c"&gt;# build the release&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--offline&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; .

&lt;span class="c"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: remember the &lt;code&gt;--offline&lt;/code&gt; flag for the second build stage, or dependencies may be fetched again!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This means that we should only have to reinstall dependencies when either of our &lt;code&gt;Cargo.toml&lt;/code&gt; or &lt;code&gt;Cargo.lock&lt;/code&gt; files change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reducing Bloat
&lt;/h3&gt;

&lt;p&gt;This step isn't as noticeable as the previous step, but it can help reduce the bloat of our image. We can do this by using two separate images - one purely for building, and the other for running our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# ...&lt;/span&gt;

&lt;span class="c"&gt;# build the release&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--offline&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; .

&lt;span class="c"&gt;# use a slim image for actually running the container.&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; rust:slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# allow requests to port 80&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;

&lt;span class="c"&gt;# install the program onto the current image&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/local/cargo/bin/aws-rust-api /usr/local/bin/aws-rust-api&lt;/span&gt;

&lt;span class="c"&gt;# copy config file&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Rocket.toml .&lt;/span&gt;

&lt;span class="c"&gt;# this command is run when we actually start the container&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["aws-rust-api"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations! Your program is almost ready to be deployed on AWS Elastic Beanstalk. If you have any issues, you compare your code with the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-4"&gt;part-4 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;p&gt;In the next post, we will create a statically-served frontend for our application with Svelte and Bulma. Make sure to click the "Follow" button if you want to be alerted when the next part is available!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>aws</category>
      <category>docker</category>
      <category>svelte</category>
    </item>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (3/): Testing</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Wed, 22 Sep 2021 18:19:47 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-3-testing-1c2j</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-3-testing-1c2j</guid>
      <description>&lt;p&gt;In the last post, we created a simple URL-shortener API and tested it manually with curl and a browser. In this post, we will use Rust's integrated unit-testing features to allow testing with a single command, and then automate testing with GitHub Actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a test module
&lt;/h3&gt;

&lt;p&gt;In Rust, we can create unit-tests which allow us to test individual parts of our application. To get started, create a module called &lt;code&gt;tests&lt;/code&gt; in your &lt;code&gt;main.rs&lt;/code&gt; file, and add the &lt;code&gt;cfg(test)&lt;/code&gt; macro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;tests&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have created a tests module, we can add tests inside it with the &lt;code&gt;test&lt;/code&gt; macro.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;simple_demo_test&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By running &lt;code&gt;cargo test&lt;/code&gt;, you should see that the test fails as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;running 1 &lt;span class="nb"&gt;test
test &lt;/span&gt;tests::simple_demo_test ... FAILED
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By changing the &lt;code&gt;3&lt;/code&gt; to &lt;code&gt;2&lt;/code&gt; and rerunning &lt;code&gt;cargo test&lt;/code&gt;, you should be able to see it pass as expected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Valid Request Testing
&lt;/h3&gt;

&lt;p&gt;The Rocket crate includes functionality which allows us to write unit tests for our applications (you can find the full docs &lt;a href="https://rocket.rs/v0.5-rc/guide/testing/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In particular, we will use the &lt;code&gt;rocket::local::blocking::Client&lt;/code&gt; struct to simulate requests to our API. We will first use it to check that valid requests are accepted correctly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;valid_requests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we create a client that is able to make requests to our Rocket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid rocket instance"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we make a POST request to shorten a url, and check that the response status is Ok.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
    &lt;span class="nf"&gt;.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/shorten?url=https://duck.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.dispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then attempt to extract the key which was returned from the response body, panicking if the key could not be parsed successfully.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
    &lt;span class="nf"&gt;.into_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid u32"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can make a GET request to the shortened URL, and check that the response is a redirect to the original URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="nf"&gt;.dispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeeOther&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;redirect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;
    &lt;span class="nf"&gt;.headers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.get_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Location"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"location header"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"https://duck.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the full test with &lt;code&gt;cargo run&lt;/code&gt; should result in a successfull pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Invalid Request Testing
&lt;/h3&gt;

&lt;p&gt;In the current edition of our API, there are two ways that a request can fail - we should check these both.&lt;/p&gt;

&lt;p&gt;First, we will create a test to check that a missing URL parameter throws an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;empty_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid rocket instance"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/shorten?url="&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.dispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally we will create a test to ensure that the server returns Not Found to an invalid shortened URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;invalid_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;tracked&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"valid rocket instance"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/123"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.dispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="nf"&gt;.status&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nn"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both these tests should pass without issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Now we have created our tests, we can write a GitHub actions script to automatically run our tests whenever we push to the main branch. Create a file with the path &lt;code&gt;.github/workflows/test.yml&lt;/code&gt;, and add the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;CARGO_TERM_COLOR&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cargo test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you push your code to GitHub, you should be able to see your tests run (and hopefully pass) in the "Actions" tab of your repo.&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%2F6304hpnygz44qv573w0h.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%2F6304hpnygz44qv573w0h.png" alt="alt text"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;If you have an issue, you can compare your code to the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-3" rel="noopener noreferrer"&gt;part-3 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;p&gt;That's all for this post! In the next one, we will work on containerizing our application with Docker. Make sure to click the "Follow" button if you want to be alerted when the next part is available!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>svelte</category>
      <category>rust</category>
      <category>docker</category>
    </item>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (2/): Simple HTTP API</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Mon, 20 Sep 2021 20:32:32 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-2-simple-http-api-3kg6</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-2-simple-http-api-3kg6</guid>
      <description>&lt;p&gt;In the first post of the series, I covered the reasons for choosing Rust and AWS, as well as the process for initialising a new Rust project. If you haven't followed the steps in that article, you can find it &lt;a href="https://dev.toTODO"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we will create a simple URL-shortener API, and serve the endpoint locally. For the web framework, we will be using &lt;a href="https://rocket.rs/"&gt;Rocket&lt;/a&gt; to reduce the amount of boilerplate and help us focus on the application logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Started with Rocket
&lt;/h3&gt;

&lt;p&gt;Before we can use Rocket, we need to add it to our list of dependencies (cargo.toml). We'll be using the JSON feature&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;rocket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.5.0-rc.1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check everything is working, copy the following code to &lt;code&gt;main.rs&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[macro_use]&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;crate&lt;/span&gt; &lt;span class="n"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[get(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nv"&gt;'static&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[launch]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;routes!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you start the program with &lt;code&gt;cargo run&lt;/code&gt;, you should be presented with the following message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;🚀 Rocket has launched from http://127.0.0.1:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you open the link in a web browser, you should be presented with the expected "Hello, World!" message.&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrent HashMap
&lt;/h3&gt;

&lt;p&gt;To store pairings of shortened URLs to full URLs, we will use a hashmap. However, we need to share this map across threads - those familiar with Rust will know that this can be quite tricky due to the restrictions of the borrow checker.&lt;/p&gt;

&lt;p&gt;One approach to solving this would be to simply wrap a &lt;code&gt;HashMap&lt;/code&gt; in a &lt;code&gt;Mutex&lt;/code&gt; for controlling concurrent accesses, and then use an &lt;code&gt;Arc&lt;/code&gt; for referencing counting. However, we can simplify this in two ways.&lt;/p&gt;

&lt;p&gt;Firstly, we can use the &lt;a href="https://docs.rs/dashmap/"&gt;dashmap&lt;/a&gt; crate for a fast, concurrent hashmap (&lt;code&gt;DashMap&lt;/code&gt; implements &lt;code&gt;Sync&lt;/code&gt; so it can be shared safely across threads). Although perhaps overkill for our use-case, dashmap provides better performance than naively using an &lt;code&gt;RwLock&lt;/code&gt;. To install it, add the following dependency to &lt;code&gt;cargo.toml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;dashmap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"4.0.2"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As for sharing this state across threads, we only need to access it from endpoints: therefore we can just let Rocket manage it directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[launch]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;_&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;rocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.manage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;DashMap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="nf"&gt;.mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;routes!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more information on state in Rocket, you can check the &lt;a href="https://rocket.rs/v0.5-rc/guide/state/"&gt;Rocket docs&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the endpoints
&lt;/h3&gt;

&lt;p&gt;Now we need to create the actual endpoints to allow users to create and follow shortened URLs. For random number generation, we will use the &lt;a href="https://docs.rs/rand/"&gt;rand&lt;/a&gt; crate, so add the following to your dependency list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="py"&gt;rand&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.8.4"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first endpoint will listen to POST requests of the form &lt;code&gt;/api/shorten?url=___&lt;/code&gt;, and then generate a random url to return. It will return an error if the url field is empty, or a key if the URL was added to the hashmap.&lt;/p&gt;

&lt;p&gt;Rocket will automatically parse the URL parameter and inject the managed hashmap.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[post(&lt;/span&gt;&lt;span class="s"&gt;"/api/shorten?&amp;lt;url&amp;gt;"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;shorten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BadRequest&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="nf"&gt;.is_empty&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;BadRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"URL is empty!"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;thread_rng&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.gen&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="nf"&gt;.insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The other endpoint will listen to GET requests of the form &lt;code&gt;/&amp;lt;key&amp;gt;&lt;/code&gt; where  is a number. If the key exists in the hashmap, then it will redirect the user to the corresponding URL. Otherwise, it will return an error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[get(&lt;/span&gt;&lt;span class="s"&gt;"/&amp;lt;key&amp;gt;"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;
        &lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
        &lt;span class="nf"&gt;.ok_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid or expired link!"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember to update your &lt;code&gt;rocket&lt;/code&gt; function to mount the new routes!&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Testing
&lt;/h3&gt;

&lt;p&gt;To check that your API is working as expected, you can use a tool like Postman or Curl to make POST requests, then enter the link manually in a browser. To use curl, try the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-G&lt;/span&gt; &lt;span class="nt"&gt;--data-urlencode&lt;/span&gt; &lt;span class="s1"&gt;'url=https://duck.com'&lt;/span&gt; http://localhost:8000/api/shorten
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Warning: In PowerShell, &lt;code&gt;curl&lt;/code&gt; is simply an alias for &lt;code&gt;Invoke-WebRequest&lt;/code&gt;, therefore this command may not work without installing it manually.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should see the endpoint respond with a number - use this in your browser to make the GET request. If your number was 123, for example, you should enter &lt;code&gt;http://127.0.0.1:8000/123&lt;/code&gt; into your address bar. You should be automatically redirected to whatever URL you set in the previous POST request.&lt;/p&gt;

&lt;p&gt;If you are having any issues, check out the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-2"&gt;part-2 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;p&gt;That's all for this post! In the next post, we will create a simple HTTP API with the Rocket web framework. Make sure to click the "Follow" button if you want to be alerted when the next part is available!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>rust</category>
      <category>svelte</category>
      <category>docker</category>
    </item>
    <item>
      <title>URL Shortener with Rust, Svelte, &amp; AWS (1/): Intro + Setup</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Mon, 20 Sep 2021 20:31:53 +0000</pubDate>
      <link>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-1-intro-setup-3fli</link>
      <guid>https://forem.com/mileswatson/url-shortener-with-rust-svelte-aws-1-intro-setup-3fli</guid>
      <description>&lt;p&gt;In this series of posts, I aim to guide you through the process of creating and deploying a public API. Over the course of the series, you will learn how to use the following technologies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rust with Rocket web framework - for handling API requests&lt;/li&gt;
&lt;li&gt;Docker and Docker Compose - for containerizing your application&lt;/li&gt;
&lt;li&gt;Svelte and Bulma - for creating a simple frontend&lt;/li&gt;
&lt;li&gt;Elastic Beanstalk - for hosting your service&lt;/li&gt;
&lt;li&gt;IAM and GitHub Actions - for automating testing + deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rust
&lt;/h3&gt;

&lt;p&gt;Explaining fully the reasons for choosing Rust would be a blog post in itself - instead, I recommend you watch the following video by Jon Gjengset:&lt;/p&gt;

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

&lt;p&gt;If you haven't previously used Rust before, then I &lt;strong&gt;strongly&lt;/strong&gt; recommend you spend some time reading through the &lt;a href="https://doc.rust-lang.org/stable/book/"&gt;Rust book&lt;/a&gt; before attempting to do any of this yourself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/1d24e64022fd725f1896890b3ce14c560f075dc1f80f0b0baae3ece8981c882a/68747470733a2f2f70617065722d6174746163686d656e74732e64726f70626f782e636f6d2f735f353445314239364546464546443239343536323930324443354239393731443335434436423635304243383744313230303341333041343635313737363230315f313538363531343237353631385f696d6167652e706e67" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/1d24e64022fd725f1896890b3ce14c560f075dc1f80f0b0baae3ece8981c882a/68747470733a2f2f70617065722d6174746163686d656e74732e64726f70626f782e636f6d2f735f353445314239364546464546443239343536323930324443354239393731443335434436423635304243383744313230303341333041343635313737363230315f313538363531343237353631385f696d6167652e706e67" alt="Rust learning curve"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Svelte
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://svelte.dev/"&gt;Svelte&lt;/a&gt; is a different kind of web framework - instead of being a library like React or Vue, it is actually a compiler under the hood. This enables you to write really clean, concise, and performant code (it does surgical DOM updates instead of using VDOM diffing+reconciliation).&lt;/p&gt;

&lt;p&gt;If you want to learn more (or even if you don't), I can highly recommend watching this excellent presentation by the creator of Svelte.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  AWS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; (AWS) is the world's biggest cloud service provider. They provide over 200 services that allow organizations and individuals to rent resources from one of AWS' many data centers.&lt;/p&gt;

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

&lt;p&gt;Cloud computing is becoming increasingly popular, as more and more companies prioritize agility and elasticity (which cloud platforms offer) over control and cost-efficiency (which traditional, managed infrastructure provides).&lt;/p&gt;

&lt;p&gt;For beginners, AWS offer a &lt;a href="https://aws.amazon.com/free/"&gt;free tier&lt;/a&gt;, which should allow you to complete this tutorial without spending any money. &lt;strong&gt;However&lt;/strong&gt;, accidentally spending money is an easy mistake for beginners to make - I recommend &lt;a href="https://youtu.be/MKNtSOQXFrY"&gt;following this video&lt;/a&gt; to minimize any surprise bills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before moving on...
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install the latest stable Rust version by following &lt;a href="https://doc.rust-lang.org/book/ch01-01-installation.html"&gt;these instructions&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a Github repo for storing your code (commit + push whenever you see fit)&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;cargo init --bin&lt;/code&gt; to create a new Rust project, and check it works with &lt;code&gt;cargo run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Install Yarn with &lt;code&gt;npm install --global yarn&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you have any issues, compare your code with the &lt;a href="https://github.com/mileswatson/url-shortener/tree/part-1"&gt;part-1 tag&lt;/a&gt; of my repo.&lt;/p&gt;

&lt;p&gt;That's all for this post! In the next post, we will create a simple HTTP API with the Rocket web framework. Make sure to click the "Follow" button if you want to be alerted when the next part is available!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologize in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>aws</category>
      <category>svelte</category>
      <category>docker</category>
    </item>
    <item>
      <title>Creating Better Applications with MVVM</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Sat, 09 Jan 2021 20:12:48 +0000</pubDate>
      <link>https://forem.com/mileswatson/a-beginners-guide-to-mvvm-using-c-wpf-241b</link>
      <guid>https://forem.com/mileswatson/a-beginners-guide-to-mvvm-using-c-wpf-241b</guid>
      <description>&lt;p&gt;In this article, I explain what MVVM is and how it can help you create better web/desktop applications. I use C#/WPF in my examples, although you should be able to follow along with basic knowledge of OOP and HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context
&lt;/h3&gt;

&lt;p&gt;Until a month ago, my experience of creating graphical user interfaces was limited to plain HTML/CSS websites and some basic python applications using &lt;a href="http://appjar.info/" rel="noopener noreferrer"&gt;appJar&lt;/a&gt;. I always felt intimidated by the concept of having to work with GUIs: as a backend-oriented programmer, my way of thinking never seemed to mesh well with the popular frameworks. &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%2Fi%2F0y0wn1tir17hd2fbl2zz.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0y0wn1tir17hd2fbl2zz.jpg" alt="Scared of frontend meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently, I have had to started working on a desktop client for my &lt;a href="https://github.com/mileswatson/hosta/" rel="noopener noreferrer"&gt;decentralized social media&lt;/a&gt;. Most people would agree that this is an intimidating project, especially for an inexperienced frontend developer. Initially, I found making progress hard - until I learnt about MVVM.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is MVVM?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;MVVM&lt;/strong&gt; stands for &lt;strong&gt;M&lt;/strong&gt;odel, &lt;strong&gt;V&lt;/strong&gt;iew, &lt;strong&gt;V&lt;/strong&gt;iew-&lt;strong&gt;M&lt;/strong&gt;odel. These form the three main parts of an MVVM application.&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%2Fi%2Fqxemn0ty0ktiuw0lwns2.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%2Fi%2Fqxemn0ty0ktiuw0lwns2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Models
&lt;/h3&gt;

&lt;p&gt;Models contain core algorithms and data structures to be used by the application - the "business logic". These are often written in a "pure" programming language, without using any special libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  View-Models
&lt;/h3&gt;

&lt;p&gt;View-models are special classes to represent the state of a view. For example, they have properties to represent displayed text, user-input textboxes, or even other view models. They should also have functions / commands which represent events (such as when a button is clicked).&lt;/p&gt;

&lt;p&gt;View models often have some boilerplate code, so that they can integrate with whatever MVVM framework you are using. However, they should work on their own, with no dependency on the view.&lt;/p&gt;

&lt;h3&gt;
  
  
  Views
&lt;/h3&gt;

&lt;p&gt;Views contain the code that is used by the UI. They are often written with a markup language (e.g. XAML or HTML). The views outline the structure (and styling) of the view, and their content is set with &lt;em&gt;bindings&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Bindings allow content to be linked to a property of the view-model. Changing the property in the view-model will automatically update the shown content in the view. The binding can also work the other way, using a two-way binding. This is useful for textboxes, as you can have the view-model property update on each keystroke (this can be used for real-time input validation).&lt;/p&gt;

&lt;h2&gt;
  
  
  A Quick Example
&lt;/h2&gt;

&lt;p&gt;To demonstrate the ideas I've talked about, I will quickly guide you through the process of creating an application using MVVM. The application will allow the user to click through a list of people.&lt;/p&gt;

&lt;p&gt;I'll be using WPF (Windows Presentation Framework). If you want to follow along, create a new &lt;code&gt;WPF App (.NET)&lt;/code&gt; project in Visual Studio. I've called mine &lt;code&gt;Demo&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a model
&lt;/h3&gt;

&lt;p&gt;First, we'll create a class to represent a person. It will contain two fields - &lt;code&gt;Name&lt;/code&gt; and &lt;code&gt;Age&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've put the class in the &lt;code&gt;Demo.Models&lt;/code&gt; namespace, and saved it as &lt;code&gt;Models/PersonModel.cs&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonModel&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Creating the view model
&lt;/h3&gt;

&lt;p&gt;Next, we will create the View Model. There will be four properties - two strings, and two commands. The strings will represent the name and age of the currently displayed person, whilst the buttons will allow us to click through the people.&lt;/p&gt;

&lt;p&gt;Whenever we change a property, we have to alert the framework (so that the view can be updated). In WPF, this is achieved by implementing &lt;code&gt;INotifyPropertyChanged&lt;/code&gt; and then calling &lt;code&gt;NotifyPropertyChanged&lt;/code&gt; whenever a property is set.&lt;/p&gt;

&lt;p&gt;I've put the class in the &lt;code&gt;Demo.ViewModels&lt;/code&gt; namespace, and saved it as &lt;code&gt;ViewModels/PeopleViewModel.cs&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PeopleViewModel&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;INotifyPropertyChanged&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//// Bindable properties&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;NotifyPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;_age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Age&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="nf"&gt;NotifyPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt; &lt;span class="n"&gt;Previous&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt; &lt;span class="n"&gt;Next&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//// Implementation&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PersonModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Charlie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PeopleViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="n"&gt;Previous&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RelayCommand&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;--;&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="n"&gt;Next&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RelayCommand&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;Age&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;people&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Age&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//// Boilerplate code to satisfy INotifyPropertyChanged&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;event&lt;/span&gt; &lt;span class="n"&gt;PropertyChangedEventHandler&lt;/span&gt; &lt;span class="n"&gt;PropertyChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;NotifyPropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PropertyChanged&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;PropertyChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PropertyChangedEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propertyName&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;In this example, the &lt;code&gt;RelayCommand&lt;/code&gt; class is used to wrap functions as an &lt;code&gt;ICommand&lt;/code&gt;. An explanation of this (and the code for the class) can be found &lt;a href="https://docs.microsoft.com/en-us/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why isn't the age an integer?
&lt;/h4&gt;

&lt;p&gt;The age property isn't an integer, because it isn't representing the age of the person: it is representing the displayed content. The view will be displaying a string, therefore the property should be of type string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating the view
&lt;/h3&gt;

&lt;p&gt;Now that the view-model has been created, we will create a &lt;code&gt;UserControl&lt;/code&gt; to act as the view. It will have two labels and two buttons - the labels will be bound to the Name and Age strings, and the buttons will bound to the Previous and Next commands.&lt;/p&gt;

&lt;p&gt;In WPF, each view has a &lt;code&gt;DataContext&lt;/code&gt;. By including the &lt;code&gt;Demo.ViewModels&lt;/code&gt; namespace, we can set the data context of the user control to be a &lt;code&gt;PersonViewModel&lt;/code&gt;. Then, we can bind to a property &lt;code&gt;X&lt;/code&gt; of the &lt;code&gt;UserControl.DataContext&lt;/code&gt; by using the &lt;code&gt;"{Binding X}"&lt;/code&gt; syntax.&lt;/p&gt;

&lt;p&gt;I've saved the user control as &lt;code&gt;Views/PeopleView.xaml&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;UserControl&lt;/span&gt; &lt;span class="na"&gt;x:Class=&lt;/span&gt;&lt;span class="s"&gt;"Demo.Views.PeopleView"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:x=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:mc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.openxmlformats.org/markup-compatibility/2006"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:d=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/expression/blend/2008"&lt;/span&gt;
             &lt;span class="na"&gt;xmlns:viewmodels=&lt;/span&gt;&lt;span class="s"&gt;"clr-namespace:Demo.ViewModels"&lt;/span&gt;
             &lt;span class="na"&gt;mc:Ignorable=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;
             &lt;span class="na"&gt;d:DesignHeight=&lt;/span&gt;&lt;span class="s"&gt;"450"&lt;/span&gt; &lt;span class="na"&gt;d:DesignWidth=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;UserControl.DataContext&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;viewmodels:PeopleViewModel&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/UserControl.DataContext&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;StackPanel&lt;/span&gt; &lt;span class="na"&gt;Background=&lt;/span&gt;&lt;span class="s"&gt;"White"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Content=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Name}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="na"&gt;Content=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Age}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;StackPanel&lt;/span&gt; &lt;span class="na"&gt;Orientation=&lt;/span&gt;&lt;span class="s"&gt;"Horizontal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Content=&lt;/span&gt;&lt;span class="s"&gt;"Previous"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Previous}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Label&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;Button&lt;/span&gt; &lt;span class="na"&gt;Content=&lt;/span&gt;&lt;span class="s"&gt;"Next"&lt;/span&gt; &lt;span class="na"&gt;Command=&lt;/span&gt;&lt;span class="s"&gt;"{Binding Next}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/UserControl&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  What about the code-behind?
&lt;/h4&gt;

&lt;p&gt;The code-behind is rarely used in WPF applications that use MVVM. All the UI logic should be contained in the view-model, not the code-behind. This separation of concerns is what makes MVVM such a versatile architecture!&lt;/p&gt;
&lt;h3&gt;
  
  
  Finishing up
&lt;/h3&gt;

&lt;p&gt;Now that we've created our view, we can display it in &lt;code&gt;MainWindow.xaml&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;Window&lt;/span&gt; &lt;span class="na"&gt;x:Class=&lt;/span&gt;&lt;span class="s"&gt;"Demo.MainWindow"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:x=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:d=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/expression/blend/2008"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:mc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.openxmlformats.org/markup-compatibility/2006"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:views=&lt;/span&gt;&lt;span class="s"&gt;"clr-namespace:Demo.Views"&lt;/span&gt;
        &lt;span class="na"&gt;mc:Ignorable=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;
        &lt;span class="na"&gt;Title=&lt;/span&gt;&lt;span class="s"&gt;"MainWindow"&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"450"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;StackPanel&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;views:PeopleView&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Upon running, you should see the application working as expected:&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%2Fi%2Flj6858fkoz3m5i94ycvm.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flj6858fkoz3m5i94ycvm.gif" alt="demo1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why all the effort?
&lt;/h2&gt;

&lt;p&gt;You may be wondering why we should go through all this effort. There are three main reasons that MVVM is better than the standard "code-behind" approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testability
&lt;/h3&gt;

&lt;p&gt;Because your view-model is entirely decoupled from your view, you can use a testing framework (e.g. MSTest) to check that your interface logic is correct, without the need to manually test the UI yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modularity
&lt;/h3&gt;

&lt;p&gt;Now that you have created your model and view-model pair, you can can reuse them as a component across your code. For example, you can add a second instance of the component like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;StackPanel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;views:PeopleView&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;views:PeopleView&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;


&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%2Fi%2Fpf41538m0vewp3tyu8dg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpf41538m0vewp3tyu8dg.gif" alt="demo2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By nesting components within each other, you can build up complex, modular user interfaces with minimal effort.&lt;/p&gt;

&lt;p&gt;You can even create multiple views bound to the same view-model! I've done this by setting the &lt;code&gt;DataContext&lt;/code&gt; of the &lt;code&gt;MainWindow&lt;/code&gt; to be a new &lt;code&gt;PersonViewModel&lt;/code&gt;, and then binding both of the views to it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;Window&lt;/span&gt; &lt;span class="na"&gt;x:Class=&lt;/span&gt;&lt;span class="s"&gt;"Demo.MainWindow"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml/presentation"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:x=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/winfx/2006/xaml"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:d=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.microsoft.com/expression/blend/2008"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:mc=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.openxmlformats.org/markup-compatibility/2006"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:viewmodels=&lt;/span&gt;&lt;span class="s"&gt;"clr-namespace:Demo.ViewModels"&lt;/span&gt;
        &lt;span class="na"&gt;xmlns:views=&lt;/span&gt;&lt;span class="s"&gt;"clr-namespace:Demo.Views"&lt;/span&gt;
        &lt;span class="na"&gt;mc:Ignorable=&lt;/span&gt;&lt;span class="s"&gt;"d"&lt;/span&gt;
        &lt;span class="na"&gt;Title=&lt;/span&gt;&lt;span class="s"&gt;"MainWindow"&lt;/span&gt; &lt;span class="na"&gt;Height=&lt;/span&gt;&lt;span class="s"&gt;"450"&lt;/span&gt; &lt;span class="na"&gt;Width=&lt;/span&gt;&lt;span class="s"&gt;"800"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;Window.DataContext&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;viewmodels:PeopleViewModel&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Window.DataContext&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;StackPanel&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;views:PeopleView&lt;/span&gt; &lt;span class="na"&gt;DataContext=&lt;/span&gt;&lt;span class="s"&gt;"{Binding}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;views:PeopleView&lt;/span&gt; &lt;span class="na"&gt;DataContext=&lt;/span&gt;&lt;span class="s"&gt;"{Binding}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/StackPanel&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Window&amp;gt;&lt;/span&gt;


&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%2Fi%2Fnu66nokd098yyanaql11.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnu66nokd098yyanaql11.gif" alt="demo3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Note: You would normally bind the &lt;code&gt;DataContext&lt;/code&gt; property of a view to a property of the current view-model. However, the main window doesn't have a view-model, and so I've bound it straight to &lt;code&gt;Window.DataContext&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Platform Agnosticism
&lt;/h3&gt;

&lt;p&gt;Splitting your application into the three parts allows you to reuse models and view-models across multiple platforms. This is made easy by using cross-platform frameworks like &lt;a href="https://www.mvvmcross.com/" rel="noopener noreferrer"&gt;MvvmCross&lt;/a&gt; (which supports Windows, Mac, iOS and Android).&lt;/p&gt;

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

&lt;p&gt;MVVM is an application architecture which allows you to develop testable, modular, and cross-platform applications. It splits code into three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;model&lt;/li&gt;
&lt;li&gt;view-model&lt;/li&gt;
&lt;li&gt;view&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The separation of concerns improves code maintainability and readability. Furthermore, the model and view-model can be unit-tested and shared across platforms, allowing for quicker development of cross-platform applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. I apologise in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>csharp</category>
      <category>wpf</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Programming is Ruining My Life - What I'm Doing About It</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Sat, 19 Dec 2020 21:06:47 +0000</pubDate>
      <link>https://forem.com/mileswatson/programming-is-ruining-my-life-what-i-m-doing-about-it-5b7c</link>
      <guid>https://forem.com/mileswatson/programming-is-ruining-my-life-what-i-m-doing-about-it-5b7c</guid>
      <description>&lt;p&gt;Okay, the title might have been a slight exaggeration - programming has played a very beneficial role in both my academic and professional development. I have noticed recently, however, that programming has caused a significant decrease to my quality of life.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Situation
&lt;/h2&gt;

&lt;p&gt;Hi! My name's Miles, and I'm a teenager living in the UK. I've been programming in one way or another for over five years, but have recently been stepping up my workload (mostly due to my &lt;a href="https://github.com/mileswatson/hosta/" rel="noopener noreferrer"&gt;school computer science project&lt;/a&gt;, among other things). A typical school day over the past month has looked like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;wake up, breakfast&lt;/li&gt;
&lt;li&gt;school (5 hours of lessons, most of lunch break programming)&lt;/li&gt;
&lt;li&gt;homework / Advent Of Code until dinner&lt;/li&gt;
&lt;li&gt;project work after dinner until bed
The weekends are fairly similar, except with more homework / programming in the place of lessons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This schedule has been fairly consistent for a few months now, and I wanted to share some of the issues I've had (as well as some of the methods I'm using to cope).&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Eyesight
&lt;/h3&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%2Fimages.unsplash.com%2Fphoto-1456081101716-74e616ab23d8%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1355%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1456081101716-74e616ab23d8%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1355%26q%3D80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Over the past year or so, I have seen a noticeable decrease in my ability to discern details at distances further than a few metres. The impacts were most felt when I started school after lockdown, and had to move closer to the front of the classroom in order to make out questions.&lt;/p&gt;

&lt;p&gt;I believe that this was caused long periods working at a computer, rather than simply due to genetics - mostly due to the fact that my eyesight felt quite a bit worse after my more "productive" days.&lt;/p&gt;

&lt;p&gt;In addition to having developed short-sightedness, I have recently experienced some of the joys of eye strain. The discomfort persisted for a couple days, forcing me to take a break from computer work. It was after this particular event that I realised that something had to change.&lt;/p&gt;

&lt;h3&gt;
  
  
  Posture and Back Discomfort
&lt;/h3&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%2Fimages.unsplash.com%2Fphoto-1462145523241-05dd5bae9ada%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1331%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1462145523241-05dd5bae9ada%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1331%26q%3D80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sitting at a computer has caused a slight discomfort in my lower back and rounded shoulders. Although minor, I assume this discomfort will only become worse as I age.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lethargy
&lt;/h3&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%2Fimages.unsplash.com%2Fphoto-1448454050639-2f8d4bf26975%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1267%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1448454050639-2f8d4bf26975%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1267%26q%3D80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one's quite simple - do you lack energy, or feel tired/weak/fatigued after small amounts of exercise? Being sedentary for long periods of time is not healthy, and can lead to both mental and physical illness. I personally noticed myself getting out of breath after flights of stairs, and feeling unfit caused a drop in my self-confidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Burnout and Irritability
&lt;/h3&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%2Fimages.unsplash.com%2Fphoto-1561053338-af94db55eb9b%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1356%26q%3D80" 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%2Fimages.unsplash.com%2Fphoto-1561053338-af94db55eb9b%3Fixid%3DMXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%253D%26ixlib%3Drb-1.2.1%26auto%3Dformat%26fit%3Dcrop%26w%3D1356%26q%3D80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a long day of problem solving, I noticed that I felt both mentally and physically exhausted. This exhaustion destroyed my motivation for other hobbies, and made me more irritable (and therefore unsociable). Instead of spending my time reading, playing games, or talking with friends, I instead tried to numb my stress by endlessly scrolling through Reddit and other social media platforms until I fell asleep.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tilting
&lt;/h3&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%2Fmedia1.giphy.com%2Fmedia%2F9o9dh1JRGThC1qxGTJ%2Fgiphy.gif%3Fcid%3Decf05e4750l4dt5rphfuo6111ph2gr8ttfkppt59dilqcjqw%26rid%3Dgiphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia1.giphy.com%2Fmedia%2F9o9dh1JRGThC1qxGTJ%2Fgiphy.gif%3Fcid%3Decf05e4750l4dt5rphfuo6111ph2gr8ttfkppt59dilqcjqw%26rid%3Dgiphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.urbandictionary.com/define.php?term=Tilting" rel="noopener noreferrer"&gt;Urban Dictionary&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Although mostly used to describe a feeling in videogames, I find that the experience translates well to problem solving. Getting frustrated at a bug leads my mental clarity to decrease, causing a feedback loop that ends in me spending hours on a problem (often until late at night, causing irregular sleep patterns).&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Doing About It
&lt;/h2&gt;

&lt;p&gt;Here are some methods that I have found particularly helpful for dealing with and preventing the issues I've talked about:&lt;/p&gt;

&lt;h3&gt;
  
  
  20-20-20 Rule
&lt;/h3&gt;

&lt;p&gt;I've recently started using the &lt;a href="https://www.healthline.com/health/eye-health/20-20-20-rule" rel="noopener noreferrer"&gt;20-20-20 rule&lt;/a&gt;. The rule says that, for every 20 minutes of computer work, you should focus on something 20 feet away for 20 seconds. I've found this to give good (albeit temporary) relief, although I usually do it for longer than 20 seconds.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regular Breaks
&lt;/h3&gt;

&lt;p&gt;Taking short breaks every hour or so has been very beneficial. During these breaks, I make an effort to move as much as possible - either a short walk outside, a few press-ups/pull-ups, or even just walking around the house.&lt;/p&gt;

&lt;h3&gt;
  
  
  Posture Exercises
&lt;/h3&gt;

&lt;p&gt;I've been doing daily posture exercises to help fix my posture. So far, I've made noticeable progress.&lt;/p&gt;

&lt;p&gt;Here are some good resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=SYr6lbx68n8" rel="noopener noreferrer"&gt;Jeremy Ethier&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.healthline.com/health/rounded-shoulders-exercises" rel="noopener noreferrer"&gt;Healthline&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.wikihow.com/Fix-Rounded-Shoulders" rel="noopener noreferrer"&gt;WikiHow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Gym Routine
&lt;/h3&gt;

&lt;p&gt;You've probably heard this one a lot. There's a reason - it really works. Getting regular exercise at the gym (three days a week) has made me both fitter and happier&lt;sup&gt;&lt;sup&gt;;)&lt;/sup&gt;&lt;/sup&gt;. It has the combined effect of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improving overall health&lt;/li&gt;
&lt;li&gt;Providing a way to relax&lt;/li&gt;
&lt;li&gt;Clearing my head&lt;/li&gt;
&lt;li&gt;Increasing my self confidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Important note: There is a tendency among gym-goers to focus on "push" actions. These can create a natural tension in the chest, leading to the shoulders being drawn in. Make sure to perform the posture exercises mentioned above, and balance your workout with exercises that target the back - think "pull" actions (deadlifts are also good for general posture, but can be dangerous if performed with bad technique).&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning How to "Give Up"
&lt;/h3&gt;

&lt;p&gt;Being able to recognise when I am "tilting", and having the self control to force myself to put a problem to the side has been very beneficial. I've found that clearing my head before trying again produces better results with less total time spent when compared to stubbornly grinding away at it.&lt;/p&gt;

&lt;p&gt;This is probably the thing which I've found the hardest to do on this list - I have (like many other programmers) a natural tendency to obsess over problems until they are solved. Realising that putting a problem on hold is NOT admitting defeat was a major milestone in getting more consistent sleep and maintaining a better work/life balance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting Kittens
&lt;/h3&gt;

&lt;p&gt;I don't think this one needs much explanation :) Pets can be a great way to destress - just make sure they don't interrupt your Zoom calls (grrr).&lt;/p&gt;

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

&lt;p&gt;As a developer, maintaining your physical and mental health is crucial to staying both productive and happy. Take frequent breaks, regularly exercise, and ensure that you are eating/drinking/sleeping well - your mind will thank you.&lt;/p&gt;

&lt;p&gt;Have you been having any issues with burnout, work-life balance, or physical health? How have you been coping? Let me know in the comments below!&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologise in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mentalhealth</category>
      <category>productivity</category>
      <category>community</category>
    </item>
    <item>
      <title>Why You Should Be Doing Advent of Code (it's not too late to start)</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Wed, 02 Dec 2020 20:18:54 +0000</pubDate>
      <link>https://forem.com/mileswatson/why-you-should-be-doing-advent-of-code-it-s-not-too-late-to-start-3n83</link>
      <guid>https://forem.com/mileswatson/why-you-should-be-doing-advent-of-code-it-s-not-too-late-to-start-3n83</guid>
      <description>&lt;p&gt;You may have recently heard some talk about Advent of Code - every developer's favourite advent calendar. In this article, I'm going to try and explain why &lt;em&gt;everyone&lt;/em&gt; can get something out of it.&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Advent of Code?
&lt;/h2&gt;

&lt;p&gt;Advent of Code is a website that sets daily challenges for each day of advent. The context for each challenge tells part of a story that spans the full 25 days.&lt;/p&gt;

&lt;p&gt;Each day, you are presented with two problems that are designed to be challenging whilst remaining accessible to those without much programming experience. &lt;/p&gt;

&lt;p&gt;Solving a problem rewards a gold star - to complete the challenge, you need to collect all 50 of them. Whilst this sounds simple, the challenges vary in difficulty (with an upwards trend as the event progresses).&lt;/p&gt;

&lt;h2&gt;
  
  
  What languages can I use?
&lt;/h2&gt;

&lt;p&gt;You can use any language! None of the problems involve uploading your own code - you can solve all of them locally, and then copy/paste the answer into the submission box. You can even solve them with an &lt;a href="https://en.wikipedia.org/wiki/Esoteric_programming_language" rel="noopener noreferrer"&gt;esolang&lt;/a&gt; if you want a challenge!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I be taking part?
&lt;/h2&gt;

&lt;p&gt;Almost everyone has a reason to take part in this competition! However, the most compelling reason depends on where you are in your programming journey.&lt;/p&gt;

&lt;h4&gt;
  
  
  If you are just starting out
&lt;/h4&gt;

&lt;p&gt;This is an opportunity for you to start using some of the basic skills you may have been learning. If your programming experience is limited to online courses or video tutorials, then AoC is a great way to practice applying your knowledge to solve problems by yourself. The story is a nice touch too!&lt;/p&gt;

&lt;h4&gt;
  
  
  If have been programming for a bit
&lt;/h4&gt;

&lt;p&gt;Advent of Code is a great way to practice your problem solving skills. It can be used as an introduction to competitive programming - perhaps you might get a hobby out of it! At the very least, you can expect to improve your interview skills.&lt;/p&gt;

&lt;p&gt;I would recommend timing yourself to see how quick you can solve the problems, and then try and compete with your friends / colleagues.&lt;/p&gt;

&lt;h4&gt;
  
  
  If are an experienced programmer
&lt;/h4&gt;

&lt;p&gt;As you might have some competitive programming experience, you can take this challenge a little more seriously. If you are fast enough at completing them from when the challenge launches, you might even be able to make it onto the leaderboard!&lt;/p&gt;

&lt;p&gt;Alternatively, you can take AoC as an opportunity to try and get some experience with that new programming language you have been eyeing for a while. I personally have chosen &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;, because I want to be familiar with the syntax before experimenting with the various web frameworks that it offers.&lt;/p&gt;

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

&lt;p&gt;Advent of Code is a great idea that can really get you thinking. It is on its sixth year now, and is continuing to grow. In fact, there was so much traffic on the first day this year that it brought down the servers!&lt;/p&gt;

&lt;p&gt;You can get started at the following link: &lt;a href="https://adventofcode.com/" rel="noopener noreferrer"&gt;https://adventofcode.com/&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologise in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>adventofcode</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>What is Async Programming, and Why Should You Care?</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Fri, 27 Nov 2020 20:05:41 +0000</pubDate>
      <link>https://forem.com/mileswatson/what-is-async-programming-and-why-should-you-care-58il</link>
      <guid>https://forem.com/mileswatson/what-is-async-programming-and-why-should-you-care-58il</guid>
      <description>&lt;p&gt;Async programming is a style of programming that allows you to increase performance when handling events &lt;em&gt;independent of the main program flow&lt;/em&gt;. For example, some common tasks that benefit from being asynchronous include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;handling user interface events&lt;/li&gt;
&lt;li&gt;communicating over a network&lt;/li&gt;
&lt;li&gt;reading / writing to a secondary storage device&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's the problem?
&lt;/h2&gt;

&lt;p&gt;As programmers, we are used to working with &lt;em&gt;synchronous&lt;/em&gt; code. Synchronous functions are easy to understand - we call them, they do some work, and they return a value. &lt;/p&gt;

&lt;p&gt;There are situations where this leads to very bad performance. Imagine we want to get the contents of every page given by a list of URLs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllPages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;GetPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will be very slow for large lists of URLs, as the for loop has to wait for each page request to finish before starting the next one. We can therefore say that each function call is &lt;em&gt;blocking&lt;/em&gt; - it blocks the entire thread until the result is returned.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can we fix it?
&lt;/h2&gt;

&lt;p&gt;Async programming helps fix this issue by separating the function call and the function result. For example, we can start all the requests, and then wait for the results to arrive. Pseudocode might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;GetAllPages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;StartRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WaitForResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is rather clunky, as you have to define a start and an end function for each operation you want to make asynchronous. Thankfully, C# has a nice syntax to make this easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work in C#?
&lt;/h2&gt;

&lt;p&gt;In C#, asynchronous operations are represented using the &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt; type. The "start" function returns a &lt;code&gt;Task&lt;/code&gt; object, from which the result can be obtained. If the function GetPage() was written using &lt;em&gt;Task Awaitable Programming&lt;/em&gt; (TAP), you could write the program as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllPages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// starts the asynchronous operation&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// blocks the thread to wait for the result&lt;/span&gt;
        &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whilst this works, it isn't ideal. Although the individual calls to &lt;code&gt;GetPage&lt;/code&gt; aren't blocking the function, any external code that calls &lt;code&gt;GetAllPages&lt;/code&gt; will be blocked until all the requests have finished.&lt;/p&gt;

&lt;p&gt;To combat this, we can write the function in an asynchronous style. This usually takes three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;async&lt;/code&gt; keyword&lt;/li&gt;
&lt;li&gt;Change the return type to &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Replace synchronous waits (&lt;code&gt;Task.Wait()&lt;/code&gt;, &lt;code&gt;Task.Result&lt;/code&gt;) with the &lt;code&gt;await&lt;/code&gt; keyword&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The previous function would now look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllPages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;urls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// starts the asynchronous operation&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// doesn't block the thread&lt;/span&gt;
        &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;await&lt;/code&gt; VS &lt;code&gt;.Result&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;When you call &lt;code&gt;.Result&lt;/code&gt;, the system thread remains blocked &lt;em&gt;even when waiting&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, using &lt;code&gt;await&lt;/code&gt; frees up the thread to allow other tasks to run. For example, this means that a server can use only 4 system threads to handle 100 clients (as opposed to the 100 system threads in a naive approach).&lt;/p&gt;

&lt;p&gt;Therefore, &lt;code&gt;await&lt;/code&gt; should be used in place of &lt;code&gt;.Result&lt;/code&gt; whenever possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: A function must be marked &lt;code&gt;async&lt;/code&gt; for the &lt;code&gt;await&lt;/code&gt; keyword to be used.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What's the catch?
&lt;/h2&gt;

&lt;p&gt;Async programming can be very useful in certain situations. As a rule of thumb, it is only increases performance when the program is IO-bound. You shouldn't use async functions to do CPU-bound calculations, as it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provides almost no useful functionality&lt;/li&gt;
&lt;li&gt;makes the code less readable&lt;/li&gt;
&lt;li&gt;might decrease performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One exception to this rule is the &lt;code&gt;Task.Run()&lt;/code&gt; function, which allows CPU-bound work to be performed on a background thread.&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologise in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>csharp</category>
      <category>tutorial</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Why You Should Migrate to .NET 5 (and why you shouldn't)</title>
      <dc:creator>Miles Watson</dc:creator>
      <pubDate>Sat, 14 Nov 2020 11:09:10 +0000</pubDate>
      <link>https://forem.com/mileswatson/why-you-should-migrate-to-net-5-0-and-why-you-shouldn-t-4hdp</link>
      <guid>https://forem.com/mileswatson/why-you-should-migrate-to-net-5-0-and-why-you-shouldn-t-4hdp</guid>
      <description>&lt;p&gt;.NET 5 is the latest and greatest version of .NET from the folks over at Microsoft, and it's better than ever. &lt;em&gt;Almost&lt;/em&gt; everyone should migrate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's all the fuss?
&lt;/h2&gt;

&lt;p&gt;Up until now, .NET has been fragmented into 4 different platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Framework&lt;/li&gt;
&lt;li&gt;Core&lt;/li&gt;
&lt;li&gt;Standard&lt;/li&gt;
&lt;li&gt;Xamarin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can imagine, this leads to issues with code compatibility, especially when developing cross-platform applications. .NET 5 is an evolution of Core which replaces the need for Standard. It provides a unified platform on which you can build any application.&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%2Fi%2Fgf33dzppdwjqq7azxdyo.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%2Fi%2Fgf33dzppdwjqq7azxdyo.png" alt="dotnet_new"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why should I care?
&lt;/h2&gt;

&lt;p&gt;There are three main reasons you should switch over:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unified platform helps with code reuse across multiple platforms&lt;/li&gt;
&lt;li&gt;Language updates to C#, F#, and VB&lt;/li&gt;
&lt;li&gt;Performance improvements across the board&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Is migrating my applications difficult?
&lt;/h2&gt;

&lt;p&gt;In most cases, migrating to .NET 5 can be done in two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update to the latest version of the SDK (this can be done by updating VS)&lt;/li&gt;
&lt;li&gt;Change the target framework in your project file (.csproj for C#).
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Make sure to check any breaking issues before updating - &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/compatibility/3.1-5.0" rel="noopener noreferrer"&gt;here are breaking changes for .NET Core 3.1 to .NET 5.0&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why shouldn't I migrate?
&lt;/h2&gt;

&lt;p&gt;There are some older technologies that are no longer supported in .NET 5:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Forms&lt;/li&gt;
&lt;li&gt;Windows Communication Foundation&lt;/li&gt;
&lt;li&gt;Windows Workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Newer alternatives to these can be found on &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/dotnet-five#net-50-doesnt-replace-net-framework" rel="noopener noreferrer"&gt;Microsoft Docs&lt;/a&gt;, but they may take time to implement.&lt;/p&gt;

&lt;h4&gt;
  
  
  Footnote
&lt;/h4&gt;

&lt;p&gt;If you enjoyed reading this, then consider dropping a like or following me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mileswatson"&gt;DEV&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/in/watsonmiles" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/miles__watson" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mileswatson" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm just starting out, so the support is greatly appreciated!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer - I'm a (mostly) self-taught programmer, and I use my blog to share things that I've learnt on my journey to becoming a better developer. Because of this, I apologise in advance for any inaccuracies I might have made - criticism and corrections are welcome!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
