<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[|MW|]]></title><description><![CDATA[Hi! I'm an aspiring computer scientist with interests in quantum computing and distributed systems. In this blog, I write about the useful things I've learned d]]></description><link>https://blog.mileswatson.net</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 13:49:47 GMT</lastBuildDate><atom:link href="https://blog.mileswatson.net/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (6/): Deploying to AWS]]></title><description><![CDATA[In the last post, we created a static front-end application with Svelte + Bulma, and then integrated it into our Rust code + Dockerfile. In this final post, we will cover the process of actually deploying the app to AWS Elastic Beanstalk.
What is Ela...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-6-deploying-to-aws</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-6-deploying-to-aws</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Fri, 08 Oct 2021 15:34:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1633707227549/nJ0rn5Eib.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last post, we created a static front-end application with <a target="_blank" href="https://svelte.dev/">Svelte</a> + <a target="_blank" href="https://bulma.io/">Bulma</a>, and then integrated it into our Rust code + Dockerfile. In this final post, we will cover the process of actually deploying the app to <a target="_blank" href="https://aws.amazon.com/elasticbeanstalk/">AWS Elastic Beanstalk</a>.</p>
<h3 id="what-is-elastic-beanstalk">What is Elastic Beanstalk?</h3>
<p>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. </p>
<h3 id="manual-deployment">Manual Deployment</h3>
<p>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 <code>git archive</code> (this has the added benefit of automatically ignoring anything in the gitignore).</p>
<pre><code class="lang-sh">git archive --format=zip HEAD -o ./target/repo.zip
</code></pre>
<p>This will place a zip of our repo into the <code>target</code> folder.</p>
<p>Now we have the zip file, you should following the following steps:</p>
<ol>
<li>Login to <a target="_blank" href="console.aws.amazon.com/">AWS Console</a></li>
<li>Use the search bar to go to the "Elastic Beanstalk" page, and make sure you are in the "Elastic Beanstalk &gt; Environments page"</li>
<li>Select your desired region using the dropdown menu in the top right</li>
<li>Click the "Create application" button (alternatively, click "Create Environment, and then select "Web server environment")</li>
<li>Give your application a suitable name
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j53b4wr1bah9x7nkidn5.png" alt="AWS console" /></li>
<li>Give the application environment (the collection of services that will run your application) the name "production"
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iwhwnllbbxmh6kewvjgs.png" alt="AWS console" /></li>
<li>Select the following platform options: 
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqv9phv0fqjigtl439ji.png" alt="AWS console" /></li>
<li>Upload your zip file, and then click "Create environment"
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jf3e10lf095kv1t7hqdj.png" alt="AWS console" /></li>
</ol>
<p>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 <code>docker-compose.yml</code> file to build the images from scratch on the underlying EC2 instance).</p>
<p>Once the environment health transitions to "Ready", you should be able to go to the provided URL (HTTP <em>only</em>, as setting up HTTPS is beyond the scope of this series).</p>
<h3 id="creating-a-deployment-pipeline">Creating a Deployment Pipeline</h3>
<p>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.</p>
<p>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".</p>
<p>We will be using the <a target="_blank" href="https://github.com/marketplace/actions/beanstalk-deploy">Beanstalk Deploy</a>, which requires the <code>AWSElasticBeanstalkWebTier</code> and <code>AWSElasticBeanstalkManagedUpdatesCustomerRolePolicy</code> permissions. Make sure to attach these to the IAM role, and then create the user.</p>
<p>Once you have clicked <code>Create user</code>, 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 &gt; Secrets &gt; New repository secret):</p>
<ul>
<li>AWS_ACCESS_KEY_ID</li>
<li>AWS_SECRET_ACCESS_KEY
You should set these to the corresponding credentials of your <code>url-shortener-deploy</code> user, and then close the credential view on the AWS console.</li>
</ul>
<p>Next, create a new workflow called <code>deploy.yml</code> (this should be in the same directory as <code>test.yml</code>). This action will use the secrets we set in the last step to deploy our code to AWS whenever code is pushed to production.</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">AWS</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">production</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">Latest</span> <span class="hljs-string">Repo</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@master</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">ref:</span> <span class="hljs-string">"production"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Generate</span> <span class="hljs-string">Deployment</span> <span class="hljs-string">Package</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">mkdir</span> <span class="hljs-string">target</span> <span class="hljs-string">&amp;&amp;</span> <span class="hljs-string">git</span> <span class="hljs-string">archive</span> <span class="hljs-string">--format=zip</span> <span class="hljs-string">HEAD</span> <span class="hljs-string">-o</span> <span class="hljs-string">./target/repo.zip</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Get</span> <span class="hljs-string">timestamp</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">gerred/actions/current-time@master</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">current-time</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">string</span> <span class="hljs-string">replace</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">frabert/replace-string-action@master</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">format-time</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">pattern:</span> <span class="hljs-string">'[:\.]+'</span>
          <span class="hljs-attr">string:</span> <span class="hljs-string">"$<span class="hljs-template-variable">{{ steps.current-time.outputs.time }}</span>"</span>
          <span class="hljs-attr">replace-with:</span> <span class="hljs-string">"-"</span>
          <span class="hljs-attr">flags:</span> <span class="hljs-string">"g"</span>

      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">EB</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">einaregilsson/beanstalk-deploy@v18</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">aws_access_key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_ACCESS_KEY_ID</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">aws_secret_key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AWS_SECRET_ACCESS_KEY</span> <span class="hljs-string">}}</span>
          <span class="hljs-attr">application_name:</span> <span class="hljs-string">url-shortener</span>
          <span class="hljs-attr">environment_name:</span> <span class="hljs-string">production</span>
          <span class="hljs-attr">version_label:</span> <span class="hljs-string">"url-shortener-$<span class="hljs-template-variable">{{ steps.format-time.outputs.replaced }}</span>"</span>
          <span class="hljs-attr">region:</span> <span class="hljs-string">eu-west-2</span>
          <span class="hljs-attr">deployment_package:</span> <span class="hljs-string">target/repo.zip</span>
</code></pre>
<blockquote>
<p>Note: The string replacement step simply sets the code version to the current time.</p>
</blockquote>
<h3 id="testing-auto-deployment">Testing Auto-Deployment</h3>
<p>Now that we have created the workflow, we need to push to the <code>production</code> 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:</p>
<pre><code class="lang-sh">git branch production
git push origin production
</code></pre>
<p>If all goes correctly, your workflow should take about 15 minutes to deploy your code to AWS.</p>
<h3 id="now-its-your-turn">Now it's your turn!</h3>
<p>Now that you have the barebones structure up and running, perhaps you could try adding the following features:</p>
<ul>
<li>persistance with an AWS-provided database (like Aurora or DynamoDB)</li>
<li>expiring links, so that a given memory / storage limit isn't exceeded</li>
<li>a fully fleshed-out frontend with common pages (such as an FAQ, contact us)</li>
<li>a custom domain name + https support for EB</li>
</ul>
<p>That's all for this series! If you have any issues, make sure to check out the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-6">part-6 tag</a> of my repo.</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (5/): Frontend]]></title><description><![CDATA[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 Svelte + Bulma, and then integrate it into our Rust code + ...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-5-frontend</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-5-frontend</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Thu, 30 Sep 2021 10:00:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632995996028/rM4gJ5BN6.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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 <a target="_blank" href="https://svelte.dev/">Svelte</a> + <a target="_blank" href="https://bulma.io/">Bulma</a>, and then integrate it into our Rust code + Dockerfile. I will be using the <a target="_blank" href="https://yarnpkg.com/">Yarn</a> package manager, but feel free to use <code>npm</code> if you prefer.</p>
<h3 id="cloning-the-template">Cloning the Template</h3>
<p>First, run the following command in the root of your repo. This will create a directory called <code>svelte</code> which contains a template that we'll use to build a simple frontend for our API.</p>
<pre><code class="lang-sh">npm init svelte@next svelte
</code></pre>
<p>Select the <code>Skeleton project</code> template, <code>Yes</code> to Typescript, and then <code>No</code> to all the other questions.</p>
<p>Inside the <code>svelte</code> directory, run <code>yarn install</code> to install dependencies, and then <code>yarn dev</code> to start a dev server. By going to http://localhost:3000/ you should see a simple message:
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jrnua1zzka9velle7acb.png" alt="template welcome page" /></p>
<h3 id="adding-a-static-adapter">Adding a Static Adapter</h3>
<p>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 <code>adapter-static</code> to prerender our entire site. </p>
<p>First, we need to install the adapter using Yarn.</p>
<pre><code class="lang-sh">yarn add --dev @sveltejs/adapter-static@next
</code></pre>
<p>Next, we need to change the <code>svelte.config.js</code> file to configure the adapter. Import the adapter...</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> adapter <span class="hljs-keyword">from</span> <span class="hljs-string">'@sveltejs/adapter-static'</span>;
</code></pre>
<p>...then update <code>config.kit</code>.</p>
<pre><code class="lang-js">{
    <span class="hljs-comment">// hydrate the &lt;div id="svelte"&gt; element in src/app.html</span>
    <span class="hljs-attr">target</span>: <span class="hljs-string">'#svelte'</span>,
    <span class="hljs-comment">// prerender the pages so they can be served statically</span>
    <span class="hljs-attr">adapter</span>: adapter()
}
</code></pre>
<p>By running <code>yarn build</code>, you should see that the <code>/svelte/build</code> directory is populated with an <code>index.html</code> file (among some other files / folders).</p>
<h3 id="serving-with-rocket">Serving with Rocket</h3>
<p>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:</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[launch]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">rocket</span></span>() -&gt; _ {
    rocket::build()
        .manage(DashMap::&lt;<span class="hljs-built_in">u32</span>, <span class="hljs-built_in">String</span>&gt;::new())
        .mount(<span class="hljs-string">"/"</span>, routes![shorten, redirect])
        .mount(
            <span class="hljs-string">"/"</span>,
            <span class="hljs-keyword">if</span> <span class="hljs-built_in">cfg!</span>(debug_assertions) {
                <span class="hljs-comment">// debug mode, therefore serve relative to crate root</span>
                FileServer::from(rocket::fs::relative!(<span class="hljs-string">"/svelte/build"</span>))
            } <span class="hljs-keyword">else</span> {
                <span class="hljs-comment">// dockerized, therefore serve from absolute path</span>
                FileServer::from(<span class="hljs-string">"/app/static"</span>)
            },
        )
}
</code></pre>
<p>The <code>if cfg!(debug...</code> statement will become clearer later on, when we update the Dockerfile.</p>
<h3 id="fixing-tests">Fixing Tests</h3>
<p>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 <code>FileServer</code> 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:</p>
<pre><code class="lang-yml"><span class="hljs-attr">steps:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Rust</span>
    <span class="hljs-attr">run:</span> <span class="hljs-string">cargo</span> <span class="hljs-string">build</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Yarn</span>
    <span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">--global</span> <span class="hljs-string">yarn</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Dependencies</span>
    <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">--cwd</span> <span class="hljs-string">svelte</span> <span class="hljs-string">install</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Svelte</span>
    <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">--cwd</span> <span class="hljs-string">svelte</span> <span class="hljs-string">run</span> <span class="hljs-string">build</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Tests</span>
    <span class="hljs-attr">run:</span> <span class="hljs-string">cargo</span> <span class="hljs-string">test</span>
</code></pre>
<p>For the sake of completion, I also added a simple test to check that the static site is being served as expected.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">static_site</span></span>() {
    <span class="hljs-keyword">let</span> client = Client::tracked(rocket()).expect(<span class="hljs-string">"valid rocket instance"</span>);
    <span class="hljs-keyword">let</span> response = client.get(<span class="hljs-string">"/"</span>).dispatch();
    <span class="hljs-built_in">assert_eq!</span>(response.status(), Status::<span class="hljs-literal">Ok</span>);
}
</code></pre>
<p>Tests should now pass as expected.</p>
<h3 id="updating-the-dockerfile">Updating the Dockerfile</h3>
<p>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.</p>
<pre><code class="lang-docker">
# ...
RUN cargo install --offline --path .

# use a node image for building the site
FROM node:16 as static

WORKDIR /svelte

COPY ./svelte .

RUN yarn install &amp;&amp; yarn build

# use a slim image for actually running the container.
FROM rust:slim

# ...

COPY --from=build /usr/local/cargo/bin/aws-rust-api /usr/local/bin/aws-rust-api
COPY --from=static /svelte/build/ ./static

# ...
</code></pre>
<p>You should now be able to start your application using <code>docker-compose --build</code> and see your site when you go to http://127.0.0.1.</p>
<h3 id="adding-functionality">Adding Functionality</h3>
<p>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 <code>app.html</code> <code>&lt;head&gt;&lt;/head&gt;</code> tags.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"</span>&gt;</span>
</code></pre>
<p>We will be using <a target="_blank" href="https://www.npmjs.com/package/superagent">SuperAgent</a> for making API requests, so let's add it to our dependency list.
<code>yarn add superagent</code>
Next, we will create a <code>routes/__layout.svelte</code> file, which will wrap around any of the routes in the directory.</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"svelte"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container is-fluid my-5"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar is-dark"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"navigation"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-item ml-5 is-dark"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/favicon.png"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"32"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"32"</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"logo"</span> /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"title is-2 navbar-item"</span>&gt;</span>URL Shortener<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>This will give us a simple, function-less navbar to go across the top of the screen.
Next, change the <code>index.svelte</code> file to contain the following script. </p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
    <span class="hljs-keyword">import</span> superagent <span class="hljs-keyword">from</span> <span class="hljs-string">"superagent"</span>;

    <span class="hljs-keyword">let</span> url = <span class="hljs-string">""</span>;
    <span class="hljs-keyword">let</span> request = <span class="hljs-literal">null</span>;

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">click</span>(<span class="hljs-params"></span>) </span>{
        request = superagent.post(<span class="hljs-string">`/api/shorten?url=<span class="hljs-subst">${url}</span>`</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUrl</span>(<span class="hljs-params">key</span>) </span>{
        <span class="hljs-keyword">return</span> <span class="hljs-string">`http://<span class="hljs-subst">${<span class="hljs-built_in">window</span>.location.host}</span>/<span class="hljs-subst">${key}</span>`</span>;
    }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Finally, we can bind to these variables / functions by appending the following to the <code>index.svelte</code> file:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"box"</span>&gt;</span>
    {#if request == null}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"field has-addons"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                    <span class="hljs-attr">class</span>=<span class="hljs-string">"input"</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
                    <span class="hljs-attr">bind:value</span>=<span class="hljs-string">{url}</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"URL"</span>
                /&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"control"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"button is-info"</span> <span class="hljs-attr">on:click</span>=<span class="hljs-string">{click}</span>&gt;</span>Shorten<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    {:else}
        {#await request}
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Loading...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {:then response}
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">header</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-header"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-header-title"</span>&gt;</span>Done!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-content"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                        <span class="hljs-attr">class</span>=<span class="hljs-string">"content"</span>
                        <span class="hljs-attr">href</span>=<span class="hljs-string">{getUrl(response.text)}</span>
                        <span class="hljs-attr">target</span>=<span class="hljs-string">"_blank"</span>&gt;</span>{getUrl(response.text)}<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>
                    &gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                        <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer-item button"</span>
                        <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span> (request = null)}&gt;Back<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>
                    &gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                        <span class="hljs-attr">class</span>=<span class="hljs-string">"card-footer-item button is-info"</span>
                        <span class="hljs-attr">on:click</span>=<span class="hljs-string">{()</span> =&gt;</span>
                            navigator.clipboard.writeText(
                                getUrl(response.text)
                            )}&gt;Copy<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>
                    &gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        {:catch}
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Something went wrong!<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
        {/await}
    {/if}
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<p>The <code>bind:value={url}</code> is one of Svelte's special two-way bindings - updating the textbox will update the variable, and vice versa.</p>
<p>When the user clicks the button, the <code>click</code> function will start an asynchronous request to the API, and set the <code>request</code> variable to the uncompleted promise.</p>
<p>This will then cause the page to show <code>Loading...</code> until the request completes, at which point the shortened URL is displayed (with some buttons).</p>
<h3 id="final-product">Final Product</h3>
<p>If you did everything correctly, you should be able to run <code>docker-compose up --build</code> and use your site at http://127.0.0.1!</p>
<p><img src="https://i.imgur.com/GmSKZx4.gif" alt="URL Shortener Demo" /></p>
<p>That's all for this post! If you have any issues, make sure to check out the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-5">part-5 tag</a> of my repo.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (4/): Dockerizing]]></title><description><![CDATA[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.
What is Docker?
Exp...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-4-dockerizing</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-4-dockerizing</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Thu, 30 Sep 2021 09:57:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632995829272/WlJecfy8r.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h3 id="what-is-docker">What is Docker?</h3>
<p>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:</p>
<p>{% youtube _dfLOzuIg2o %}</p>
<h3 id="installing-docker">Installing Docker</h3>
<p>The easiest way to use Docker is with Docker Desktop (<a target="_blank" href="https://docs.docker.com/desktop/mac/install/">mac</a> / <a target="_blank" href="https://docs.docker.com/desktop/windows/install/">windows</a>). This will install both the <code>docker</code> and <code>docker-compose</code> tools. </p>
<p>For Linux users, you have to first install <a target="_blank" href="https://docs.docker.com/engine/install/">Docker Engine</a>, and then install <a target="_blank" href="https://docs.docker.com/compose/install/">Docker Compose</a> separately.</p>
<h3 id="creating-the-docker-file">Creating the Docker File</h3>
<p>First, create an empty file in the root of your repo called <code>Dockerfile</code> (no file extension). This file will contain a list of repeatable instructions that tells Docker how to build our container. </p>
<pre><code class="lang-docker"># select a starting image to build off
FROM rust as build

# set our working directory in the container as /repo
WORKDIR /repo

# copy all our files across from our local repo to the /repo directory in the container
COPY Cargo.lock .
COPY Cargo.toml .
COPY src src

# build the release
RUN cargo install --path .

# allow requests to port 8000
EXPOSE 8000

# this command is run when we actually start the container
CMD ["aws-rust-api"]
</code></pre>
<h3 id="building-and-running-the-container">Building and running the container</h3>
<p>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.</p>
<pre><code class="lang-sh">docker build -t url-shortener .
</code></pre>
<p>The <code>-t url-shortener</code> part tags our image so that we can run it in the next step, whilst the <code>.</code> indicates the Dockerfile is in the current directory.</p>
<blockquote>
<p>Note: Ensure that the Docker daemon is running, or the Docker commands may fail.</p>
</blockquote>
<p>Once the container has been built, we can start it with the following command:</p>
<pre><code class="lang-sh">docker run -it --rm --name my-running-app -p 8000:8000 url-shortener
</code></pre>
<blockquote>
<p>Note: the <code>-p 8000:8000</code> means that we are binding port 8000 of our local machine to port 8000 of the Docker container.</p>
</blockquote>
<p>The application should appear to start as normal - however, you will notice that you cannot connect. This is because our program is listening on <code>127.0.0.1</code>, but we need it to listen on all available network interfaces (<code>0.0.0.0</code>).</p>
<p>We can fix this using a <code>Rocket.toml</code> configuration file to configure the address and port for Release mode.</p>
<pre><code class="lang-toml"><span class="hljs-section">[release]</span>
<span class="hljs-attr">address</span> = <span class="hljs-string">"0.0.0.0"</span>
<span class="hljs-attr">port</span> = <span class="hljs-number">80</span>
</code></pre>
<p>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 <code>CMD</code> command.</p>
<pre><code class="lang-docker">COPY Rocket.toml .
</code></pre>
<p>You should also change the <code>EXPOSE</code> line to expose port 80 (rather than 8000).</p>
<p>We can  build the image and run it again, and you should be able to connect to it by going to http://127.0.0.1. Remember to bind to port <code>80</code> instead of <code>8000</code> in the <code>docker run</code> command this time!</p>
<h3 id="docker-compose">Docker Compose</h3>
<p>To simplify the process of creating and running the Docker images, we will create a <code>docker-compose.yml</code> file in the root of the repo.</p>
<pre><code class="lang-yml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3.9"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">url-shortener:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
</code></pre>
<p>Starting our container is now as simple as running <code>docker-compose up</code>, but make sure to append <code>--build</code> if you want to force an image rebuild.</p>
<h3 id="dependency-caching">Dependency Caching</h3>
<p>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.</p>
<p>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.</p>
<pre><code class="lang-docker"># ...

# copy all our files across from our local repo to the /repo directory in the container
COPY Cargo.lock .
COPY Cargo.toml .

# cache dependencies by creating an empty
# lib.rs file and building the project
RUN mkdir src
RUN echo "// empty file" &gt; src/lib.rs
RUN cargo build --release

# now copy the code over
COPY src src

# build the release
RUN cargo install --offline --path .

# ...
</code></pre>
<blockquote>
<p>Note: remember the <code>--offline</code> flag for the second build stage, or dependencies may be fetched again!</p>
</blockquote>
<p>This means that we should only have to reinstall dependencies when either of our <code>Cargo.toml</code> or <code>Cargo.lock</code> files change.</p>
<h3 id="reducing-bloat">Reducing Bloat</h3>
<p>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.</p>
<pre><code class="lang-docker"># ...

# build the release
RUN cargo install --offline --path .

# use a slim image for actually running the container.
FROM rust:slim

WORKDIR /app

# allow requests to port 80
EXPOSE 80

# install the program onto the current image
COPY --from=build /usr/local/cargo/bin/aws-rust-api /usr/local/bin/aws-rust-api

# copy config file
COPY Rocket.toml .

# this command is run when we actually start the container
CMD ["aws-rust-api"]
</code></pre>
<p>Congratulations! Your program is almost ready to be deployed on AWS Elastic Beanstalk. If you have any issues, you compare your code with the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-4">part-4 tag</a> of my repo.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (3/): Testing]]></title><description><![CDATA[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 Ac...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-3-testing</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-3-testing</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Thu, 30 Sep 2021 09:49:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632995287885/lBlt48psF.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h3 id="creating-a-test-module">Creating a test module</h3>
<p>In Rust, we can create unit-tests which allow us to test individual parts of our application. To get started, create a module called <code>tests</code> in your <code>main.rs</code> file, and add the <code>cfg(test)</code> macro.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[cfg(test)]</span>
<span class="hljs-keyword">mod</span> tests {
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>Now we have created a tests module, we can add tests inside it with the <code>test</code> macro.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">simple_demo_test</span></span>() {
    <span class="hljs-keyword">let</span> x = <span class="hljs-number">1</span> + <span class="hljs-number">1</span>;
    <span class="hljs-built_in">assert_eq!</span>(x, <span class="hljs-number">3</span>)
}
</code></pre>
<p>By running <code>cargo test</code>, you should see that the test fails as expected:</p>
<pre><code class="lang-sh">running 1 <span class="hljs-built_in">test</span>
<span class="hljs-built_in">test</span> tests::simple_demo_test ... FAILED
</code></pre>
<p>By changing the <code>3</code> to <code>2</code> and rerunning <code>cargo test</code>, you should be able to see it pass as expected.</p>
<h3 id="valid-request-testing">Valid Request Testing</h3>
<p>The Rocket crate includes functionality which allows us to write unit tests for our applications (you can find the full docs <a target="_blank" href="https://rocket.rs/v0.5-rc/guide/testing/">here</a>.</p>
<p>In particular, we will use the <code>rocket::local::blocking::Client</code> struct to simulate requests to our API. We will first use it to check that valid requests are accepted correctly.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">valid_requests</span></span>() {
    <span class="hljs-comment">// ...</span>
}
</code></pre>
<p>First, we create a client that is able to make requests to our Rocket.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> client = Client::tracked(rocket())
    .expect(<span class="hljs-string">"valid rocket instance"</span>);
</code></pre>
<p>Next, we make a POST request to shorten a url, and check that the response status is Ok.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> response = client
    .post(<span class="hljs-string">"/api/shorten?url=https://duck.com"</span>)
    .dispatch();
<span class="hljs-built_in">assert_eq!</span>(response.status(), Status::<span class="hljs-literal">Ok</span>);
</code></pre>
<p>We can then attempt to extract the key which was returned from the response body, panicking if the key could not be parsed successfully.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> key: <span class="hljs-built_in">u32</span> = response
    .into_string()
    .expect(<span class="hljs-string">"body"</span>)
    .parse()
    .expect(<span class="hljs-string">"valid u32"</span>);
</code></pre>
<p>Now we can make a GET request to the shortened URL, and check that the response is a redirect to the original URL.</p>
<pre><code class="lang-rust"><span class="hljs-keyword">let</span> response = client.get(<span class="hljs-built_in">format!</span>(<span class="hljs-string">"/{}"</span>, key)).dispatch();

<span class="hljs-built_in">assert_eq!</span>(response.status(), Status::SeeOther);

<span class="hljs-keyword">let</span> redirect = response
    .headers()
    .get_one(<span class="hljs-string">"Location"</span>)
    .expect(<span class="hljs-string">"location header"</span>);

<span class="hljs-built_in">assert_eq!</span>(redirect, <span class="hljs-string">"https://duck.com"</span>)
</code></pre>
<p>Running the full test with <code>cargo run</code> should result in a successfull pass.</p>
<h3 id="invalid-request-testing">Invalid Request Testing</h3>
<p>In the current edition of our API, there are two ways that a request can fail - we should check these both.</p>
<p>First, we will create a test to check that a missing URL parameter throws an error.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">empty_url</span></span>() {
    <span class="hljs-keyword">let</span> client = Client::tracked(rocket())
        .expect(<span class="hljs-string">"valid rocket instance"</span>);
    <span class="hljs-keyword">let</span> response = client.post(<span class="hljs-string">"/api/shorten?url="</span>).dispatch();
    <span class="hljs-built_in">assert_eq!</span>(response.status(), Status::BadRequest);
}
</code></pre>
<p>And finally we will create a test to ensure that the server returns Not Found to an invalid shortened URL.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[test]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">invalid_url</span></span>() {
    <span class="hljs-keyword">let</span> client = Client::tracked(rocket())
        .expect(<span class="hljs-string">"valid rocket instance"</span>);
    <span class="hljs-keyword">let</span> response = client.post(<span class="hljs-string">"/123"</span>).dispatch();
    <span class="hljs-built_in">assert_eq!</span>(response.status(), Status::NotFound);
}
</code></pre>
<p>Both these tests should pass without issue.</p>
<h3 id="github-actions">GitHub Actions</h3>
<p>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 <code>.github/workflows/test.yml</code>, and add the following script:</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Test</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">main</span>]
<span class="hljs-attr">env:</span>
  <span class="hljs-attr">CARGO_TERM_COLOR:</span> <span class="hljs-string">always</span>
<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">cargo</span> <span class="hljs-string">build</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">cargo</span> <span class="hljs-string">test</span>
</code></pre>
<p>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.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6304hpnygz44qv573w0h.png" alt="alt text" /> </p>
<p>If you have an issue, you can compare your code to the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-3">part-3 tag</a> of my repo.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (2/): Simple HTTP API]]></title><description><![CDATA[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 here.
In this article, we will create a s...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-2-simple-http-api</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-2-simple-http-api</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Thu, 30 Sep 2021 09:33:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632994384501/EIec1y8h1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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 <a target="_blank" href="TODO">here</a>.</p>
<p>In this article, we will create a simple URL-shortener API, and serve the endpoint locally. For the web framework, we will be using <a target="_blank" href="https://rocket.rs/">Rocket</a> to reduce the amount of boilerplate and help us focus on the application logic.</p>
<h3 id="getting-started-with-rocket">Getting Started with Rocket</h3>
<p>Before we can use Rocket, we need to add it to our list of dependencies (cargo.toml). We'll be using the JSON feature</p>
<pre><code class="lang-toml"><span class="hljs-section">[dependencies]</span>
<span class="hljs-attr">rocket</span> = <span class="hljs-string">"0.5.0-rc.1"</span>
</code></pre>
<p>To check everything is working, copy the following code to <code>main.rs</code>.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[macro_use]</span>
<span class="hljs-keyword">extern</span> <span class="hljs-keyword">crate</span> rocket;

<span class="hljs-meta">#[get(<span class="hljs-meta-string">"/"</span>)]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">index</span></span>() -&gt; &amp;<span class="hljs-symbol">'static</span> <span class="hljs-built_in">str</span> {
    <span class="hljs-string">"Hello, world!"</span>
}

<span class="hljs-meta">#[launch]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">rocket</span></span>() -&gt; _ {
    rocket::build().mount(<span class="hljs-string">"/"</span>, routes![index])
}
</code></pre>
<p>When you start the program with <code>cargo run</code>, you should be presented with the following message:</p>
<pre><code class="lang-sh">🚀 Rocket has launched from http://127.0.0.1:8000
</code></pre>
<p>If you open the link in a web browser, you should be presented with the expected "Hello, World!" message.</p>
<h3 id="concurrent-hashmap">Concurrent HashMap</h3>
<p>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.</p>
<p>One approach to solving this would be to simply wrap a <code>HashMap</code> in a <code>Mutex</code> for controlling concurrent accesses, and then use an <code>Arc</code> for referencing counting. However, we can simplify this in two ways.</p>
<p>Firstly, we can use the <a target="_blank" href="https://docs.rs/dashmap/">dashmap</a> crate for a fast, concurrent hashmap (<code>DashMap</code> implements <code>Sync</code> so it can be shared safely across threads). Although perhaps overkill for our use-case, dashmap provides better performance than naively using an <code>RwLock</code>. To install it, add the following dependency to <code>cargo.toml</code>.</p>
<pre><code class="lang-toml"><span class="hljs-attr">dashmap</span> = <span class="hljs-string">"4.0.2"</span>
</code></pre>
<p>As for sharing this state across threads, we only need to access it from endpoints: therefore we can just let Rocket manage it directly.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[launch]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">rocket</span></span>() -&gt; _ {
    rocket::build()
        .manage(DashMap::&lt;<span class="hljs-built_in">u32</span>, <span class="hljs-built_in">String</span>&gt;::new())
        .mount(<span class="hljs-string">"/"</span>, routes![index])
}
</code></pre>
<p>For more information on state in Rocket, you can check the <a target="_blank" href="https://rocket.rs/v0.5-rc/guide/state/">Rocket docs</a>.</p>
<h3 id="creating-the-endpoints">Creating the endpoints</h3>
<p>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 <a target="_blank" href="https://docs.rs/rand/">rand</a> crate, so add the following to your dependency list.</p>
<pre><code class="lang-toml"><span class="hljs-attr">rand</span> = <span class="hljs-string">"0.8.4"</span>
</code></pre>
<p>The first endpoint will listen to POST requests of the form <code>/api/shorten?url=___</code>, 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.</p>
<p>Rocket will automatically parse the URL parameter and inject the managed hashmap.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[post(<span class="hljs-meta-string">"/api/shorten?&lt;url&gt;"</span>)]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">shorten</span></span>(url: <span class="hljs-built_in">String</span>, state: &amp;State&lt;DashMap&lt;<span class="hljs-built_in">u32</span>, <span class="hljs-built_in">String</span>&gt;&gt;) -&gt; <span class="hljs-built_in">Result</span>&lt;<span class="hljs-built_in">String</span>, BadRequest&lt;&amp;<span class="hljs-built_in">str</span>&gt;&gt; {
    <span class="hljs-keyword">if</span> url.is_empty() {
        <span class="hljs-literal">Err</span>(BadRequest(<span class="hljs-literal">Some</span>(<span class="hljs-string">"URL is empty!"</span>)))
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">let</span> key: <span class="hljs-built_in">u32</span> = thread_rng().gen();
        state.insert(key, url);
        <span class="hljs-literal">Ok</span>(key.to_string())
    }
}
</code></pre>
<p>The other endpoint will listen to GET requests of the form <code>/&lt;key&gt;</code> 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.</p>
<pre><code class="lang-rust"><span class="hljs-meta">#[get(<span class="hljs-meta-string">"/&lt;key&gt;"</span>)]</span>
<span class="hljs-function"><span class="hljs-keyword">fn</span> <span class="hljs-title">redirect</span></span>(key: <span class="hljs-built_in">u32</span>, state: &amp;State&lt;DashMap&lt;<span class="hljs-built_in">u32</span>, <span class="hljs-built_in">String</span>&gt;&gt;) -&gt; <span class="hljs-built_in">Result</span>&lt;Redirect, NotFound&lt;&amp;<span class="hljs-built_in">str</span>&gt;&gt; {
    state
        .get(&amp;key)
        .map(|url| Redirect::to(url.clone()))
        .ok_or(NotFound(<span class="hljs-string">"Invalid or expired link!"</span>))
}
</code></pre>
<p>Remember to update your <code>rocket</code> function to mount the new routes!</p>
<h3 id="manual-testing">Manual Testing</h3>
<p>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:</p>
<pre><code class="lang-sh">curl -X POST -G --data-urlencode <span class="hljs-string">'url=https://duck.com'</span> http://localhost:8000/api/shorten
</code></pre>
<blockquote>
<p>Warning: In PowerShell, <code>curl</code> is simply an alias for <code>Invoke-WebRequest</code>, therefore this command may not work without installing it manually.</p>
</blockquote>
<p>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 <code>http://127.0.0.1:8000/123</code> into your address bar. You should be automatically redirected to whatever URL you set in the previous POST request.</p>
<p>If you are having any issues, check out the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-2">part-2 tag</a> of my repo.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[URL Shortener with Rust, Svelte, & AWS (1/): Intro + Setup]]></title><description><![CDATA[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:

Rust with Rocket web framework - for handling API requests
D...]]></description><link>https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-1-intro-setup</link><guid isPermaLink="true">https://blog.mileswatson.net/url-shortener-with-rust-svelte-and-aws-1-intro-setup</guid><category><![CDATA[Rust]]></category><category><![CDATA[Svelte]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Docker]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Thu, 30 Sep 2021 09:29:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632994215681/SMdOlyz50.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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:</p>
<ul>
<li>Rust with Rocket web framework - for handling API requests</li>
<li>Docker and Docker Compose - for containerizing your application</li>
<li>Svelte and Bulma - for creating a simple frontend</li>
<li>Elastic Beanstalk - for hosting your service</li>
<li>IAM and GitHub Actions - for automating testing + deployment</li>
</ul>
<h3 id="rust">Rust</h3>
<p>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:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=DnT-LUQgc7s">https://www.youtube.com/watch?v=DnT-LUQgc7s</a></div>
<p>If you haven't previously used Rust before, then I <strong>strongly</strong> recommend you spend some time reading through the <a target="_blank" href="https://doc.rust-lang.org/stable/book/">Rust book</a> before attempting to do any of this yourself.</p>
<p><img src="https://camo.githubusercontent.com/1d24e64022fd725f1896890b3ce14c560f075dc1f80f0b0baae3ece8981c882a/68747470733a2f2f70617065722d6174746163686d656e74732e64726f70626f782e636f6d2f735f353445314239364546464546443239343536323930324443354239393731443335434436423635304243383744313230303341333041343635313737363230315f313538363531343237353631385f696d6167652e706e67" alt="Rust learning curve" /></p>
<h3 id="svelte">Svelte</h3>
<p><a target="_blank" href="https://svelte.dev/">Svelte</a> 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).</p>
<p>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.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=AdNJ3fydeao">https://www.youtube.com/watch?v=AdNJ3fydeao</a></div>
<h3 id="aws">AWS</h3>
<p><a target="_blank" href="https://aws.amazon.com/">Amazon Web Services</a> (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.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=-xanQ3aUWms">https://www.youtube.com/watch?v=-xanQ3aUWms</a></div>
<p>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).</p>
<p>For beginners, AWS offer a <a target="_blank" href="https://aws.amazon.com/free/">free tier</a>, which should allow you to complete this tutorial without spending any money. <strong>However</strong>, accidentally spending money is an easy mistake for beginners to make - I recommend <a target="_blank" href="https://youtu.be/MKNtSOQXFrY">following this video</a> to minimize any surprise bills.</p>
<h3 id="before-moving-on">Before moving on...</h3>
<ol>
<li>Install the latest stable Rust version by following <a target="_blank" href="https://doc.rust-lang.org/book/ch01-01-installation.html">these instructions</a></li>
<li>Create a Github repo for storing your code (commit + push whenever you see fit)</li>
<li>Use <code>cargo init --bin</code> to create a new Rust project, and check it works with <code>cargo run</code></li>
<li>Install <a target="_blank" href="https://nodejs.org/en/">Node.js</a></li>
<li>Install Yarn with <code>npm install --global yarn</code></li>
</ol>
<p>If you have any issues, compare your code with the <a target="_blank" href="https://github.com/mileswatson/url-shortener/tree/part-1">part-1 tag</a> of my repo.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://www.linkedin.com/in/watsonmiles">LinkedIn</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[Creating Better Applications with MVVM]]></title><description><![CDATA[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.
Context
Until a month ago, my exper...]]></description><link>https://blog.mileswatson.net/creating-better-applications-with-mvvm</link><guid isPermaLink="true">https://blog.mileswatson.net/creating-better-applications-with-mvvm</guid><category><![CDATA[C#]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[MVVM]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Sat, 09 Jan 2021 19:38:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1632335864826/87F-X2dmm.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h3 id="context">Context</h3>
<p>Until a month ago, my experience of creating graphical user interfaces was limited to plain HTML/CSS websites and some basic python applications using <a target="_blank" href="http://appjar.info/">appJar</a>. 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. </p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/0y0wn1tir17hd2fbl2zz.jpg" alt="Scared of frontend meme" /></p>
<p>Recently, I have had to started working on a desktop client for my <a target="_blank" href="https://github.com/mileswatson/hosta/">decentralized social media</a>. 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.</p>
<h2 id="what-is-mvvm">What is MVVM?</h2>
<p><strong>MVVM</strong> stands for <strong>M</strong>odel, <strong>V</strong>iew, <strong>V</strong>iew-<strong>M</strong>odel. These form the three main parts of an MVVM application.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/qxemn0ty0ktiuw0lwns2.png" alt="Alt Text" /></p>
<h3 id="models">Models</h3>
<p>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.</p>
<h3 id="view-models">View-Models</h3>
<p>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).</p>
<p>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.</p>
<h3 id="views">Views</h3>
<p>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 <em>bindings</em>.</p>
<p>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).</p>
<h2 id="a-quick-example">A Quick Example</h2>
<p>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.</p>
<p>I'll be using WPF (Windows Presentation Framework). If you want to follow along, create a new <code>WPF App (.NET)</code> project in Visual Studio. I've called mine <code>Demo</code>.</p>
<h3 id="creating-a-model">Creating a model</h3>
<p>First, we'll create a class to represent a person. It will contain two fields - <code>Name</code> and <code>Age</code>.</p>
<p>I've put the class in the <code>Demo.Models</code> namespace, and saved it as <code>Models/PersonModel.cs</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PersonModel</span>
{
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Age { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">set</span>; }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PersonModel</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> name, <span class="hljs-keyword">int</span> age</span>)</span>
    {
        Name = name;
        Age = age;
    }
}
</code></pre>
<h3 id="creating-the-view-model">Creating the view model</h3>
<p>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.</p>
<p>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 <code>INotifyPropertyChanged</code> and then calling <code>NotifyPropertyChanged</code> whenever a property is set.</p>
<p>I've put the class in the <code>Demo.ViewModels</code> namespace, and saved it as <code>ViewModels/PeopleViewModel.cs</code>:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">PeopleViewModel</span> : <span class="hljs-title">INotifyPropertyChanged</span>
{
    <span class="hljs-comment"><span class="hljs-doctag">///</span>/ Bindable properties</span>

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _name;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Name
    {
        <span class="hljs-keyword">get</span> =&gt; _name;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>
        {
            _name = <span class="hljs-keyword">value</span>;
            NotifyPropertyChanged(<span class="hljs-keyword">nameof</span>(Name));
        }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">string</span> _age;
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Age
    {
        <span class="hljs-keyword">get</span> =&gt; _age;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">set</span>
        {
            _age = <span class="hljs-keyword">value</span>;
            NotifyPropertyChanged(<span class="hljs-keyword">nameof</span>(Age));
        }
    }

    <span class="hljs-keyword">public</span> ICommand Previous { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }
    <span class="hljs-keyword">public</span> ICommand Next { <span class="hljs-keyword">get</span>; <span class="hljs-keyword">init</span>; }

    <span class="hljs-comment"><span class="hljs-doctag">///</span>/ Implementation</span>

    <span class="hljs-keyword">private</span> PersonModel[] people = <span class="hljs-keyword">new</span> PersonModel[] {
        <span class="hljs-keyword">new</span> PersonModel(<span class="hljs-string">"Alice"</span>, <span class="hljs-number">20</span>),
        <span class="hljs-keyword">new</span> PersonModel(<span class="hljs-string">"Bob"</span>, <span class="hljs-number">25</span>),
        <span class="hljs-keyword">new</span> PersonModel(<span class="hljs-string">"Charlie"</span>, <span class="hljs-number">30</span>)
    };

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> index = <span class="hljs-number">0</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PeopleViewModel</span>(<span class="hljs-params"></span>)</span>
    {
        Name = people[index].Name;
        Age = people[index].Age.ToString();
        Previous = <span class="hljs-keyword">new</span> RelayCommand(() =&gt;
        {
            <span class="hljs-keyword">if</span> (index &gt; <span class="hljs-number">0</span>)
            {
                index--;
                Name = people[index].Name;
                Age = people[index].Age.ToString();
            }
        });
        Next = <span class="hljs-keyword">new</span> RelayCommand(() =&gt;
        {
            <span class="hljs-keyword">if</span> (index &lt; people.Length - <span class="hljs-number">1</span>)
            {
                index++;
                Name = people[index].Name;
                Age = people[index].Age.ToString();
            }
        });
    }

    <span class="hljs-comment"><span class="hljs-doctag">///</span>/ Boilerplate code to satisfy INotifyPropertyChanged</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">event</span> PropertyChangedEventHandler PropertyChanged;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">NotifyPropertyChanged</span>(<span class="hljs-params"><span class="hljs-keyword">string</span> propertyName</span>)</span>
    {
        <span class="hljs-keyword">if</span> (PropertyChanged <span class="hljs-keyword">is</span> <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span>;
        PropertyChanged(<span class="hljs-keyword">this</span>, <span class="hljs-keyword">new</span> PropertyChangedEventArgs(propertyName));
    }
}
</code></pre>
<p>In this example, the <code>RelayCommand</code> class is used to wrap functions as an <code>ICommand</code>. An explanation of this (and the code for the class) can be found <a target="_blank" href="https://docs.microsoft.com/en-us/archive/msdn-magazine/2009/february/patterns-wpf-apps-with-the-model-view-viewmodel-design-pattern">here</a>.</p>
<h4 id="why-isnt-the-age-an-integer">Why isn't the age an integer?</h4>
<p>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.</p>
<h3 id="creating-the-view">Creating the view</h3>
<p>Now that the view-model has been created, we will create a <code>UserControl</code> 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.</p>
<p>In WPF, each view has a <code>DataContext</code>. By including the <code>Demo.ViewModels</code> namespace, we can set the data context of the user control to be a <code>PersonViewModel</code>. Then, we can bind to a property <code>X</code> of the <code>UserControl.DataContext</code> by using the <code>"{Binding X}"</code> syntax.</p>
<p>I've saved the user control as <code>Views/PeopleView.xaml</code>:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">UserControl</span> <span class="hljs-attr">x:Class</span>=<span class="hljs-string">"Demo.Views.PeopleView"</span>
             <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
             <span class="hljs-attr">xmlns:x</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
             <span class="hljs-attr">xmlns:mc</span>=<span class="hljs-string">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
             <span class="hljs-attr">xmlns:d</span>=<span class="hljs-string">"http://schemas.microsoft.com/expression/blend/2008"</span>
             <span class="hljs-attr">xmlns:viewmodels</span>=<span class="hljs-string">"clr-namespace:Demo.ViewModels"</span>
             <span class="hljs-attr">mc:Ignorable</span>=<span class="hljs-string">"d"</span>
             <span class="hljs-attr">d:DesignHeight</span>=<span class="hljs-string">"450"</span> <span class="hljs-attr">d:DesignWidth</span>=<span class="hljs-string">"800"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">UserControl.DataContext</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">viewmodels:PeopleViewModel</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">UserControl.DataContext</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">StackPanel</span> <span class="hljs-attr">Background</span>=<span class="hljs-string">"White"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> <span class="hljs-attr">Content</span>=<span class="hljs-string">"{Binding Name}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> <span class="hljs-attr">Content</span>=<span class="hljs-string">"{Binding Age}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">StackPanel</span> <span class="hljs-attr">Orientation</span>=<span class="hljs-string">"Horizontal"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">Content</span>=<span class="hljs-string">"Previous"</span> <span class="hljs-attr">Command</span>=<span class="hljs-string">"{Binding Previous}"</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Label</span> /&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">Button</span> <span class="hljs-attr">Content</span>=<span class="hljs-string">"Next"</span> <span class="hljs-attr">Command</span>=<span class="hljs-string">"{Binding Next}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">StackPanel</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">StackPanel</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">UserControl</span>&gt;</span>
</code></pre>
<h4 id="what-about-the-code-behind">What about the code-behind?</h4>
<p>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!</p>
<h3 id="finishing-up">Finishing up</h3>
<p>Now that we've created our view, we can display it in <code>MainWindow.xaml</code>.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Window</span> <span class="hljs-attr">x:Class</span>=<span class="hljs-string">"Demo.MainWindow"</span>
        <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
        <span class="hljs-attr">xmlns:x</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
        <span class="hljs-attr">xmlns:d</span>=<span class="hljs-string">"http://schemas.microsoft.com/expression/blend/2008"</span>
        <span class="hljs-attr">xmlns:mc</span>=<span class="hljs-string">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
        <span class="hljs-attr">xmlns:views</span>=<span class="hljs-string">"clr-namespace:Demo.Views"</span>
        <span class="hljs-attr">mc:Ignorable</span>=<span class="hljs-string">"d"</span>
        <span class="hljs-attr">Title</span>=<span class="hljs-string">"MainWindow"</span> <span class="hljs-attr">Height</span>=<span class="hljs-string">"450"</span> <span class="hljs-attr">Width</span>=<span class="hljs-string">"800"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">StackPanel</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">views:PeopleView</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">StackPanel</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Window</span>&gt;</span>
</code></pre>
<p>Upon running, you should see the application working as expected:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/lj6858fkoz3m5i94ycvm.gif" alt="demo1" /></p>
<h2 id="why-all-the-effort">Why all the effort?</h2>
<p>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.</p>
<h3 id="testability">Testability</h3>
<p>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.</p>
<h3 id="modularity">Modularity</h3>
<p>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:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">StackPanel</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">views:PeopleView</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">views:PeopleView</span> /&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">StackPanel</span>&gt;</span>
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/pf41538m0vewp3tyu8dg.gif" alt="demo2" /></p>
<p>By nesting components within each other, you can build up complex, modular user interfaces with minimal effort.</p>
<p>You can even create multiple views bound to the same view-model! I've done this by setting the <code>DataContext</code> of the <code>MainWindow</code> to be a new <code>PersonViewModel</code>, and then binding both of the views to it.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">Window</span> <span class="hljs-attr">x:Class</span>=<span class="hljs-string">"Demo.MainWindow"</span>
        <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
        <span class="hljs-attr">xmlns:x</span>=<span class="hljs-string">"http://schemas.microsoft.com/winfx/2006/xaml"</span>
        <span class="hljs-attr">xmlns:d</span>=<span class="hljs-string">"http://schemas.microsoft.com/expression/blend/2008"</span>
        <span class="hljs-attr">xmlns:mc</span>=<span class="hljs-string">"http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
        <span class="hljs-attr">xmlns:viewmodels</span>=<span class="hljs-string">"clr-namespace:Demo.ViewModels"</span>
        <span class="hljs-attr">xmlns:views</span>=<span class="hljs-string">"clr-namespace:Demo.Views"</span>
        <span class="hljs-attr">mc:Ignorable</span>=<span class="hljs-string">"d"</span>
        <span class="hljs-attr">Title</span>=<span class="hljs-string">"MainWindow"</span> <span class="hljs-attr">Height</span>=<span class="hljs-string">"450"</span> <span class="hljs-attr">Width</span>=<span class="hljs-string">"800"</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">Window.DataContext</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">viewmodels:PeopleViewModel</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Window.DataContext</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">StackPanel</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">views:PeopleView</span> <span class="hljs-attr">DataContext</span>=<span class="hljs-string">"{Binding}"</span> /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">views:PeopleView</span> <span class="hljs-attr">DataContext</span>=<span class="hljs-string">"{Binding}"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">StackPanel</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">Window</span>&gt;</span>
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/i/nu66nokd098yyanaql11.gif" alt="demo3" /></p>
<p>Note: You would normally bind the <code>DataContext</code> 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 <code>Window.DataContext</code>.</p>
<h3 id="platform-agnosticism">Platform Agnosticism</h3>
<p>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 <a target="_blank" href="https://www.mvvmcross.com/">MvvmCross</a> (which supports Windows, Mac, iOS and Android).</p>
<h2 id="conclusion">Conclusion</h2>
<p>MVVM is an application architecture which allows you to develop testable, modular, and cross-platform applications. It splits code into three parts:</p>
<ul>
<li>model</li>
<li>view-model</li>
<li>view</li>
</ul>
<p>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.</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://hashnode.com/@mileswatson">Hashnode</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[Programming is Ruining My Life - What I'm Doing About It]]></title><description><![CDATA[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...]]></description><link>https://blog.mileswatson.net/programming-is-ruining-my-life-what-im-doing-about-it</link><guid isPermaLink="true">https://blog.mileswatson.net/programming-is-ruining-my-life-what-im-doing-about-it</guid><category><![CDATA[mentalhealth]]></category><category><![CDATA[community]]></category><category><![CDATA[Productivity]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Sat, 19 Dec 2020 21:14:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1608412433502/H4y6i0S5A.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p>
<h2 id="my-situation">My Situation</h2>
<p>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 <a target="_blank" href="https://github.com/mileswatson/hosta/">school computer science project</a>, among other things). A typical school day over the past month has looked like:</p>
<ul>
<li>wake up, breakfast</li>
<li>school (5 hours of lessons, most of lunch break programming)</li>
<li>homework / Advent Of Code until dinner</li>
<li>project work after dinner until bed
The weekends are fairly similar, except with more homework / programming in the place of lessons.</li>
</ul>
<p>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).</p>
<h2 id="issues">Issues</h2>
<h3 id="eyesight">Eyesight</h3>
<p><img src="https://images.unsplash.com/photo-1456081101716-74e616ab23d8?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1355&amp;q=80" alt /></p>
<p>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.</p>
<p>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.</p>
<p>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.</p>
<h3 id="posture-and-back-discomfort">Posture and Back Discomfort</h3>
<p><img src="https://images.unsplash.com/photo-1462145523241-05dd5bae9ada?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1331&amp;q=80" alt /></p>
<p>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.</p>
<h3 id="lethargy">Lethargy</h3>
<p><img src="https://images.unsplash.com/photo-1448454050639-2f8d4bf26975?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1267&amp;q=80" alt /></p>
<p>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.</p>
<h3 id="burnout-and-irritability">Burnout and Irritability</h3>
<p><img src="https://images.unsplash.com/photo-1561053338-af94db55eb9b?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=1356&amp;q=80" alt /></p>
<p>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.</p>
<h3 id="tilting">Tilting</h3>
<p><img src="https://media1.giphy.com/media/9o9dh1JRGThC1qxGTJ/giphy.gif?cid=ecf05e4750l4dt5rphfuo6111ph2gr8ttfkppt59dilqcjqw&amp;rid=giphy.gif" alt /></p>
<p><a target="_blank" href="https://www.urbandictionary.com/define.php?term=Tilting">Urban Dictionary</a> </p>
<p>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).</p>
<h2 id="what-im-doing-about-it">What I'm Doing About It</h2>
<p>Here are some methods that I have found particularly helpful for dealing with and preventing the issues I've talked about:</p>
<h3 id="20-20-20-rule">20-20-20 Rule</h3>
<p>I've recently started using the <a target="_blank" href="https://www.healthline.com/health/eye-health/20-20-20-rule">20-20-20 rule</a>. 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.</p>
<h3 id="regular-breaks">Regular Breaks</h3>
<p>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.</p>
<h3 id="posture-exercises">Posture Exercises</h3>
<p>I've been doing daily posture exercises to help fix my posture. So far, I've made noticeable progress.</p>
<p>Here are some good resources:</p>
<ul>
<li><a target="_blank" href="https://www.youtube.com/watch?v=SYr6lbx68n8">Jeremy Ethier</a></li>
<li><a target="_blank" href="https://www.healthline.com/health/rounded-shoulders-exercises">Healthline</a></li>
<li><a target="_blank" href="https://www.wikihow.com/Fix-Rounded-Shoulders">WikiHow</a></li>
</ul>
<h3 id="gym-routine">Gym Routine</h3>
<p>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;). It has the combined effect of:</p>
<ul>
<li>Improving overall health</li>
<li>Providing a way to relax</li>
<li>Clearing my head</li>
<li>Increasing my self confidence</li>
</ul>
<p>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).</p>
<h3 id="learning-how-to-give-up">Learning How to "Give Up"</h3>
<p>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.</p>
<p>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.</p>
<h3 id="getting-kittens">Getting Kittens</h3>
<p>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).</p>
<h2 id="conclusion">Conclusion</h2>
<p>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.</p>
<p>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!</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://hashnode.com/@mileswatson">Hashnode</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[Why You Should Be Doing Advent of Code (it's not too late to start)]]></title><description><![CDATA[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 everyone can get something out of it.
https://twitter.com/jdonszelmann/status/1333646123001634...]]></description><link>https://blog.mileswatson.net/why-you-should-be-doing-advent-of-code-its-not-too-late-to-start</link><guid isPermaLink="true">https://blog.mileswatson.net/why-you-should-be-doing-advent-of-code-its-not-too-late-to-start</guid><category><![CDATA[challenge]]></category><category><![CDATA[algorithms]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Sat, 05 Dec 2020 17:18:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607188565364/APqdnEb9Q.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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 <em>everyone</em> can get something out of it.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/jdonszelmann/status/1333646123001634816">https://twitter.com/jdonszelmann/status/1333646123001634816</a></div>
<h2 id="what-is-advent-of-code">What is Advent of Code?</h2>
<p>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.</p>
<p>Each day, you are presented with two problems that are designed to be challenging whilst remaining accessible to those without much programming experience. </p>
<p>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).</p>
<h2 id="what-languages-can-i-use">What languages can I use?</h2>
<p>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 <a target="_blank" href="https://en.wikipedia.org/wiki/Esoteric_programming_language">esolang</a> if you want a challenge!</p>
<h2 id="why-should-i-be-taking-part">Why should I be taking part?</h2>
<p>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.</p>
<h4 id="if-you-are-just-starting-out">If you are just starting out</h4>
<p>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!</p>
<h4 id="if-have-been-programming-for-a-bit">If have been programming for a bit</h4>
<p>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.</p>
<p>I would recommend timing yourself to see how quick you can solve the problems, and then try and compete with your friends / colleagues.</p>
<h4 id="if-are-an-experienced-programmer">If are an experienced programmer</h4>
<p>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!</p>
<p>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 <a target="_blank" href="https://golang.org/">Go</a>, because I want to be familiar with the syntax before experimenting with the various web frameworks that it offers.</p>
<h2 id="conclusion">Conclusion</h2>
<p>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!</p>
<p>You can get started at the following link: https://adventofcode.com/</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://hashnode.com/@mileswatson">Hashnode</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[What is Async Programming, and Why Should You Care?]]></title><description><![CDATA[Async programming is a style of programming that allows you to increase performance when handling events independent of the main program flow. For example, some common tasks that benefit from being asynchronous include:

handling user interface event...]]></description><link>https://blog.mileswatson.net/what-is-async-programming-and-why-should-you-care</link><guid isPermaLink="true">https://blog.mileswatson.net/what-is-async-programming-and-why-should-you-care</guid><category><![CDATA[Beginner Developers]]></category><category><![CDATA[C#]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[.NET]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Fri, 27 Nov 2020 16:47:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607187045590/OB7Zhqwj9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Async programming is a style of programming that allows you to increase performance when handling events <em>independent of the main program flow</em>. For example, some common tasks that benefit from being asynchronous include:</p>
<ul>
<li>handling user interface events</li>
<li>communicating over a network</li>
<li>reading / writing to a secondary storage device</li>
</ul>
<h2 id="whats-the-problem">What's the problem?</h2>
<p>As programmers, we are used to working with <em>synchronous</em> code. Synchronous functions are easy to understand - we call them, they do some work, and they return a value. </p>
<p>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.</p>
<pre><code class="lang-C#"><span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">GetAllPages</span>(<span class="hljs-params">List&lt;<span class="hljs-keyword">string</span>&gt; urls</span>)</span>
{
    <span class="hljs-keyword">var</span> pages = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> url <span class="hljs-keyword">in</span> urls)
    {
        pages.Add(GetPage(url));
    }
    <span class="hljs-keyword">return</span> pages;
}
</code></pre>
<p>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 <em>blocking</em> - it blocks the entire thread until the result is returned.</p>
<h2 id="how-can-we-fix-it">How can we fix it?</h2>
<p>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:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">GetAllPages</span>(<span class="hljs-params">urls</span>):</span>
    pages = list()

    <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> urls:
        StartRequest(url)

    <span class="hljs-keyword">for</span> url <span class="hljs-keyword">in</span> urls:
        pages.Append(WaitForResponse(url))
</code></pre>
<p>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.</p>
<h2 id="how-does-it-work-in-c">How does it work in C#?</h2>
<p>In C#, asynchronous operations are represented using the <code>Task&lt;T&gt;</code> type. The "start" function returns a <code>Task</code> object, from which the result can be obtained. If the function GetPage() was written using <em>Task Awaitable Programming</em> (TAP), you could write the program as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">GetAllPages</span>(<span class="hljs-params">List&lt;<span class="hljs-keyword">string</span>&gt; urls</span>)</span>
{
    <span class="hljs-keyword">var</span> tasks = <span class="hljs-keyword">new</span> List&lt;Task&lt;<span class="hljs-keyword">string</span>&gt;&gt;();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> url <span class="hljs-keyword">in</span> urls)
    {
        <span class="hljs-comment">// starts the asynchronous operation</span>
        <span class="hljs-keyword">var</span> task = GetPage(url);
        tasks.Add(task);
    }

    <span class="hljs-keyword">var</span> pages = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> task <span class="hljs-keyword">in</span> tasks)
    {
        <span class="hljs-comment">// blocks the thread to wait for the result</span>
        pages.Add(task.Result);
    }

    <span class="hljs-keyword">return</span> pages;
}
</code></pre>
<p>Whilst this works, it isn't ideal. Although the individual calls to <code>GetPage</code> aren't blocking the function, any external code that calls <code>GetAllPages</code> will be blocked until all the requests have finished.</p>
<p>To combat this, we can write the function in an asynchronous style. This usually takes three steps:</p>
<ol>
<li>Add the <code>async</code> keyword</li>
<li>Change the return type to <code>Task&lt;T&gt;</code></li>
<li>Replace synchronous waits (<code>Task.Wait()</code>, <code>Task.Result</code>) with the <code>await</code> keyword</li>
</ol>
<p>The previous function would now look as follows:</p>
<pre><code class="lang-csharp"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task&lt;List&lt;<span class="hljs-keyword">string</span>&gt;&gt; GetAllPages(List&lt;<span class="hljs-keyword">string</span>&gt; urls)
{
    <span class="hljs-keyword">var</span> tasks = <span class="hljs-keyword">new</span> List&lt;Task&lt;<span class="hljs-keyword">string</span>&gt;&gt;();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> url <span class="hljs-keyword">in</span> urls)
    {
        <span class="hljs-comment">// starts the asynchronous operation</span>
        <span class="hljs-keyword">var</span> task = GetPage(url);
        tasks.Add(task);
    }

    <span class="hljs-keyword">var</span> pages = <span class="hljs-keyword">new</span> List&lt;<span class="hljs-keyword">string</span>&gt;();
    <span class="hljs-keyword">foreach</span> (<span class="hljs-keyword">var</span> task <span class="hljs-keyword">in</span> tasks)
    {
        <span class="hljs-comment">// doesn't block the thread</span>
        pages.Add(<span class="hljs-keyword">await</span> task);
    }

    <span class="hljs-keyword">return</span> pages;
}
</code></pre>
<h4 id="await-vs-result"><code>await</code> VS <code>.Result</code></h4>
<p>When you call <code>.Result</code>, the system thread remains blocked <em>even when waiting</em>.</p>
<p>On the other hand, using <code>await</code> 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).</p>
<p>Therefore, <code>await</code> should be used in place of <code>.Result</code> whenever possible.</p>
<blockquote>
<p>Note: A function must be marked <code>async</code> for the <code>await</code> keyword to be used.</p>
</blockquote>
<h2 id="whats-the-catch">What's the catch?</h2>
<p>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:</p>
<ul>
<li>provides almost no useful functionality</li>
<li>makes the code less readable</li>
<li>might decrease performance</li>
</ul>
<p>One exception to this rule is the <code>Task.Run()</code> function, which allows CPU-bound work to be performed on a background thread.</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://hashnode.com/@mileswatson">Hashnode</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item><item><title><![CDATA[Why You Should Migrate to .NET 5 (and why you shouldn't)]]></title><description><![CDATA[.NET 5 is the latest and greatest version of .NET from the folks over at Microsoft, and it's better than ever. Almost everyone should migrate.
What's all the fuss?
Up until now, .NET has been fragmented into 4 different platforms:

Framework
Core
Sta...]]></description><link>https://blog.mileswatson.net/why-you-should-migrate-to-net-5-and-why-you-shouldnt</link><guid isPermaLink="true">https://blog.mileswatson.net/why-you-should-migrate-to-net-5-and-why-you-shouldnt</guid><category><![CDATA[C#]]></category><category><![CDATA[dotnet]]></category><category><![CDATA[Tutorial]]></category><dc:creator><![CDATA[Miles Watson]]></dc:creator><pubDate>Sat, 14 Nov 2020 16:36:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1607186064508/vPwK6sF8c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>.NET 5 is the latest and greatest version of .NET from the folks over at Microsoft, and it's better than ever. <em>Almost</em> everyone should migrate.</p>
<h2 id="whats-all-the-fuss">What's all the fuss?</h2>
<p>Up until now, .NET has been fragmented into 4 different platforms:</p>
<ul>
<li>Framework</li>
<li>Core</li>
<li>Standard</li>
<li>Xamarin</li>
</ul>
<p>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.</p>
<p> <img src="https://dev-to-uploads.s3.amazonaws.com/i/gf33dzppdwjqq7azxdyo.png" alt="dotnet_new" /></p>
<h2 id="why-should-i-care">Why should I care?</h2>
<p>There are three main reasons you should switch over:</p>
<ol>
<li>Unified platform helps with code reuse across multiple platforms</li>
<li>Language updates to C#, F#, and VB</li>
<li>Performance improvements across the board</li>
</ol>
<h2 id="is-migrating-my-applications-difficult">Is migrating my applications difficult?</h2>
<p>In most cases, migrating to .NET 5 can be done in two steps:</p>
<ol>
<li>Update to the latest version of the SDK (this can be done by updating VS)</li>
<li>Change the target framework in your project file (.csproj for C#).<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="85517f59ee3fe7473ba6a8ad6c76a854"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/mileswatson/85517f59ee3fe7473ba6a8ad6c76a854" class="embed-card">https://gist.github.com/mileswatson/85517f59ee3fe7473ba6a8ad6c76a854</a></div></li>
</ol>
<p>Make sure to check any breaking issues before updating - <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/core/compatibility/3.1-5.0">here are breaking changes for .NET Core 3.1 to .NET 5.0</a>.</p>
<h2 id="why-shouldnt-i-migrate">Why shouldn't I migrate?</h2>
<p>There are some older technologies that are no longer supported in .NET 5:</p>
<ul>
<li>Web Forms</li>
<li>Windows Communication Foundation</li>
<li>Windows Workflow</li>
</ul>
<p>Newer alternatives to these can be found on <a target="_blank" href="https://docs.microsoft.com/en-us/dotnet/core/dotnet-five#net-50-doesnt-replace-net-framework">Microsoft Docs</a>, but they may take time to implement.</p>
<h4 id="footnote">Footnote</h4>
<p>If you enjoyed reading this, then consider dropping a like or following me:</p>
<ul>
<li><a target="_blank" href="https://dev.to/mileswatson">DEV</a></li>
<li><a target="_blank" href="https://hashnode.com/@mileswatson">Hashnode</a></li>
<li><a target="_blank" href="https://twitter.com/miles__watson">Twitter</a></li>
<li><a target="_blank" href="https://github.com/mileswatson">Github</a></li>
</ul>
<p>I'm just starting out, so the support is greatly appreciated!</p>
<p><em>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!</em></p>
]]></content:encoded></item></channel></rss>