<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Scott</title>
    <description>The latest articles on DEV Community by Scott (@iamscottcab).</description>
    <link>https://dev.to/iamscottcab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F513568%2F133de9f5-5f80-41f8-b3d8-286ab7604f87.png</url>
      <title>DEV Community: Scott</title>
      <link>https://dev.to/iamscottcab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/iamscottcab"/>
    <language>en</language>
    <item>
      <title>Performing an in-place Git Rebase</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Wed, 16 Feb 2022 03:44:21 +0000</pubDate>
      <link>https://dev.to/iamscottcab/performing-an-in-place-git-rebase-2ii4</link>
      <guid>https://dev.to/iamscottcab/performing-an-in-place-git-rebase-2ii4</guid>
      <description>&lt;p&gt;&lt;em&gt;It's not common but sometimes we have uses for rewriting our git history. This post may (or may not) have been inspired by starting at a new job and not wanting my peers to know I completely misread one of my first programming tickets.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Many organisations approach their git commit standards differently. Some have strict adherence to commit message formats, while others are more lax. For traceability of past work it is often common to use a ticket (or some other reference) number in commit messages. That's fine, but what happens if you are new at a company, taking on a little too much information at once, and typo one of your first ticket numbers, only to realise as you go to submit a Pull Request?&lt;/p&gt;

&lt;p&gt;You try and fix your mistake of course! Learning is always fun and git is surprisingly hard to break so let's see how we can fix the problem.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Setup
&lt;/h2&gt;

&lt;p&gt;Let's assume we have a repository that uses trunk based development and some sort of feature branching strategy. We might have something like below.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Working on a Feature Branch
&lt;/h2&gt;

&lt;p&gt;We start working away while others continue to merge work into our trunk. For brevity I've commited directly to the main branch but I suggest in real world scenarios you have branch policies that prevent this behaviour. As a result we might be in a state similar to below.&lt;/p&gt;

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

&lt;p&gt;In this example we have "Ticket Number 123" appended to the start of the commits in the form &lt;strong&gt;[T123]&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Whoops! We were actually working on "Ticket Number 234", not only do I look silly but we might also break integrations with other work tracking tools, we might want to try and fix this ASAP.&lt;/p&gt;

&lt;p&gt;To fix this particular mistake we are going to take advantage of the &lt;code&gt;rebase&lt;/code&gt; command. Normally I would suggest that best practice would be to just rebase the branch off your current parent as preserving the commit it branched from isn't super useful. However there might be cases (other than pride) where doing an in-place rebase is useful. So how can we rebase this branch in-place and also re-write all of our commit history?&lt;/p&gt;

&lt;h2&gt;
  
  
  Rebasing
&lt;/h2&gt;

&lt;p&gt;We first want to find the parent commit for this branch, given we are attempting to do it in-place. There are a few ways to do this and I will show them in my preferred order.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Merge-Base Command
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://git-scm.com/docs/git-merge-base" rel="noopener noreferrer"&gt;merge-base command&lt;/a&gt; attempts to find the base commit of the supplied branches. For a feature branching strategy where that should be one commit (and not some hypothetical commit based off a multi-branch merge) this yields the fastest results. In context of our example this is what it looks like.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Using a Visual Git Tool
&lt;/h3&gt;

&lt;p&gt;Using a visual git tool provides you with a good overview of how your branches look in relation to the rest of the repository and can be easily scanned to find the parent commit. Naturally the longer your branch the harder this might be.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Using Git Log
&lt;/h3&gt;

&lt;p&gt;Much like a visual git tool &lt;a href="https://git-scm.com/docs/git-log" rel="noopener noreferrer"&gt;git log&lt;/a&gt; can be a little cumbersome if your feature branch or parent branch are long, however the following command gives us a very similar analogue to our visual tool.&lt;/p&gt;

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

&lt;p&gt;Now that we have our commit hash we can start an &lt;strong&gt;interactive&lt;/strong&gt; rebase that not only replays our commits it lets us choose how we want to handle each commit.&lt;/p&gt;

&lt;p&gt;Start the rebase command.&lt;/p&gt;

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

&lt;p&gt;We are now prompted with the history of the commits on our branch as well as some instructions on what we can do in interactive mode to change our previous commits.&lt;/p&gt;

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

&lt;p&gt;You will notice that one of the options below is &lt;code&gt;reword&lt;/code&gt; or &lt;code&gt;r&lt;/code&gt; for short. We still want to use this commit but we definitely want to change that commit message. Below is what it looks like once we have changed this file. You will not change the commit message here just the command, changing the message comes later.&lt;/p&gt;

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

&lt;p&gt;You can see that we have changed the word &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;reword&lt;/code&gt; for each commit as they all contain the wrong ticket number. Depending on your text editor the process for this might be different. I am using nano so I can save and close the file.&lt;/p&gt;

&lt;p&gt;Once you close the initial rebase file you will be prompted with a new file for each commit on your branch. The longer the branch the longer this will take, sorry.&lt;/p&gt;

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

&lt;p&gt;Very similarly to our initial rebase file we can now edit the commit message here, replace the incorrect ticket number.&lt;/p&gt;

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

&lt;p&gt;We have changed &lt;strong&gt;[T123]&lt;/strong&gt; to read &lt;strong&gt;[T234]&lt;/strong&gt;. Save and close the file and repeat the process for every commit.&lt;/p&gt;

&lt;p&gt;When done check your git log again and you should see updated commits with the correct messages, also referencing the original commit.&lt;/p&gt;

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

&lt;p&gt;Assuming this branch is already in an upstream, which for me it was, you will need to force push over this branch to completely rewrite the history using &lt;code&gt;git push -f&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Congratulations! You have now successfully updated all the commit messages on your feature branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Branches with Ticket Numbers
&lt;/h2&gt;

&lt;p&gt;In my example my branch name didn't include a ticket number, sometimes they do. In this case you &lt;em&gt;might&lt;/em&gt; want to also change the branch name, again if it makes sense. We can perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;git checkout &amp;lt;your_branch&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git branch -m &amp;lt;new_branch_name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin -u &amp;lt;new_branch_name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git push origin --delete &amp;lt;old_branch_name&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Profit.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  A Note on Rewriting History
&lt;/h2&gt;

&lt;p&gt;In general it is not great practice to rewrite history, the git log exists for a reason and rebasing in particular (which rewrites commits) might cause issues if other developers are relying on those commits. If you're working on a public repository, or are generally unsure about how to handle a situation like this, it is better to reach out to your repo owner for advice.&lt;/p&gt;

&lt;p&gt;In my case it was a feature branch only I was going to touch and having correct commit messages on the branch was more useful for the team than trying to come up with a different solution that maintained the git history with the wrong commit messages preserved.&lt;/p&gt;

&lt;p&gt;The same goes for branches too, I was comfortable to rename and delete the upstream branch for this particular piece of work but other repo owners might want to keep the wrongly named branch stale, or you might not have access to delete branches, so double check before making changes you might not be able to reverse.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Do you have any git success or horror stories? I would love to hear about them on Twitter.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>From The Archives: De/Serializing Top Level Arrays in JSON with Unity</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Thu, 08 Apr 2021 07:10:21 +0000</pubDate>
      <link>https://dev.to/iamscottcab/from-the-archives-de-serializing-top-level-arrays-in-json-with-unity-1n14</link>
      <guid>https://dev.to/iamscottcab/from-the-archives-de-serializing-top-level-arrays-in-json-with-unity-1n14</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;From the archives celebrates the good and bad of my journey in software development. It's a chance to dredge up hundreds of hours of older work. Some I am proud of, some not. But it's with self reflection that we get to understand how far we have come.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The Problem (&amp;amp; Solution) Circa. 2016
&lt;/h2&gt;

&lt;p&gt;Well it has been a while since my last tutorial. I’ve been experimenting with video tutorials and working on my game and also doing some paid project work at the same time. At least I am not bored!&lt;/p&gt;

&lt;p&gt;That being said I like to note something down when I find something new or tricky that I get stuck on and today’s is simple but effective. For those that don’t know Unity actually has a nifty built in tool to serialize and de-serialize objects through the &lt;code&gt;JsonUtility&lt;/code&gt; class. This is super useful for creating more human-readable data quickly and then adding it into your game. There is only one tiny problem for me, it doesn’t handle top level arrays. By that I mean the following won’t work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[{"myvar";"myvalue"},{"myvar":"myothervalue"}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’m not sure the reasoning but my searches online did reveal from Unity staff that they currently do not support this feature. The easiest way to fix this is just wrap the array in a top level object like below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{[{"myvar";"myvalue"},{"myvar":"myothervalue"}]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a simple fix but it is annoying if you want to serialize or deserialize straight to (or from) an array, which is what I needed to do. So let’s look at making a JsonHelper class that fixes this issue for us by wrapping up top level arrays in a Wrapper class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System;

public static class JsonHelper {

    public static T[] FromJson&amp;lt;T&amp;gt;(string json) {
        Wrapper&amp;lt;T&amp;gt; wrapper = UnityEngine.JsonUtility.FromJson&amp;lt;Wrapper&amp;lt;T&amp;gt;&amp;gt;(json);
        return wrapper.Items;
    }

    public static string ToJson&amp;lt;T&amp;gt;(T[] array) {
        Wrapper&amp;lt;T&amp;gt; wrapper = new Wrapper&amp;lt;T&amp;gt;();
        wrapper.Items = array;
        return UnityEngine.JsonUtility.ToJson(wrapper);
    }

    [Serializable]
    private class Wrapper&amp;lt;T&amp;gt; {
        public T[] Items;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code provides a simple black box to allow you to serialize or de-serialize those top level arrays but how does it work? The Wrapper is a &lt;code&gt;[Serializable]&lt;/code&gt; class that is essentially empty, in fact it only holds a generic array. The generic array is for all intents and purposes our top level array. The thing we actually want to work with.&lt;/p&gt;

&lt;p&gt;When de-serializing an array from Json it simply loads the &lt;code&gt;Wrapper&lt;/code&gt; class, ignores the wrapper itself and returns the array. Conversely when serializing into Json we create a wrapper so that we have something to hold our array in. We then assign the array passed in to our function as the wrapper’s local variable. Lastly we use the built in &lt;code&gt;JsonUtility&lt;/code&gt; to return the string back for writing.&lt;/p&gt;

&lt;p&gt;There is now only one slight change to our Json file, the array is actually named therefore we should tweak it to suit. In any situations where you want to use a top level array instead  of using our first example instead wrap it in an object and label the array “Items” as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"Items":[{"myvar";"myvalue"},{"myvar":"myothervalue"}]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; &lt;em&gt;This only applies if you are ever manually creating the json you want to de-serialize. If for some reason you’re only ever going to be loading objects you’ve previously saved the JsonUtility does this for you.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Easy? You bet, but that was the whole point!&lt;/p&gt;




&lt;p&gt;This "From the Archives" was super interesting because I actually had to look this one for one of my own personal game "Project Zap" only this week. In the original article I mentioned that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I’m not sure the reasoning...(behind why it behaves this way)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I guess &lt;strong&gt;technically&lt;/strong&gt; I still don't know why, obviously that is just their implementation but the &lt;a href="https://docs.unity3d.com/Manual/JSONSerialization.html"&gt;Unity documentation&lt;/a&gt; probably listed this constraint all along. It's funny how something I tackled so long ago came to front of mind so quickly simply because I took the effort to write it down in the past.&lt;/p&gt;

&lt;p&gt;I still don't love this solution, having to set a top level array to an arbitrary key feels fraught with danger to me. Though it has proven effective for me on the projects in which I've used it because I can easily control the data format on import. Also it made for a super simple copy &amp;amp; paste solution for my current project!&lt;/p&gt;

&lt;p&gt;It's strange to me that this requirement still exists and a more feature rich solution doesn't exist out-of-the-box, though I assume Newtonsoft JSON or something else could be leveraged if you have more robust JSON parsing requirements.&lt;/p&gt;

&lt;p&gt;Anyway, here is to remembering to write things down 👍&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>unity3d</category>
      <category>json</category>
    </item>
    <item>
      <title>Locally Ignoring Git Files</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Wed, 17 Mar 2021 06:47:10 +0000</pubDate>
      <link>https://dev.to/iamscottcab/locally-ignoring-git-files-4gao</link>
      <guid>https://dev.to/iamscottcab/locally-ignoring-git-files-4gao</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Have you ever wanted to maintain some local files in your git repository? Have you had to try juggling not staging those files so as not to effect the project configuration settings? What if you could add those files, have them ignored, but not touch your &lt;code&gt;.gitignore&lt;/code&gt; file? Let's take a quick dive into how (and why) we might do that!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why Exclude Local Files
&lt;/h2&gt;

&lt;p&gt;Let's start with the why? There are a number of reasons you might want to investigate ignoring local files in your repository that are specific to you but not the project as a whole.&lt;/p&gt;

&lt;p&gt;My use case is using containers to run my development environments. They simplify dependency management, are easy to setup and even easier to completely remove &lt;em&gt;(completely)&lt;/em&gt; and let me take advantage of a Linux based environment on my Windows PC.&lt;/p&gt;

&lt;p&gt;The easiest way to do this in VS Code is to add a &lt;code&gt;.devcontainer&lt;/code&gt; folder in the project root. You can find the documentation about development containers in the &lt;a href="https://code.visualstudio.com/docs/remote/containers"&gt;VS Code Documentation&lt;/a&gt; if this is something you might be interested in.&lt;/p&gt;

&lt;p&gt;Our project however might not be set up for development containerization (for any number of reasons) and we certainly don't need to throw that requirement to the rest of the team if this workflow is something unique to me.&lt;/p&gt;

&lt;p&gt;So now I have a &lt;code&gt;.devcontainer&lt;/code&gt; folder (and its associated files) in VS Code but don't want to accidentally commit it, now what?&lt;/p&gt;

&lt;h2&gt;
  
  
  Git Handles Local Ignores
&lt;/h2&gt;

&lt;p&gt;There is already a solution to handle this very problem in git which we can read more about in the &lt;a href="https://git-scm.com/docs/gitignore"&gt;Git Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All you need to do is open &lt;code&gt;/path/to/project/.git/info/exclude&lt;/code&gt;. The file will already be there and follows the same syntax as the standard &lt;code&gt;.gitignore&lt;/code&gt;, so editing it is a breeze.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Windows users may need to show hidden files and folders if editing this via the Explorer.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This file exists for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Patterns which are specific to a particular repository but which do not need to be shared with other related repositories (e.g., auxiliary files that live inside the repository but are specific to one user’s workflow)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For my use-case I have added &lt;code&gt;.devcontainer&lt;/code&gt; to this file and now don't worry about having to check this one into the shared team repository. Nice!&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Persisting UI Customizations in Strapi</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Mon, 15 Mar 2021 23:01:57 +0000</pubDate>
      <link>https://dev.to/iamscottcab/persisting-ui-customizations-in-strapi-hk4</link>
      <guid>https://dev.to/iamscottcab/persisting-ui-customizations-in-strapi-hk4</guid>
      <description>&lt;p&gt;Today we will be looking at a Headless CMS called &lt;a href="https://strapi.io/" rel="noopener noreferrer"&gt;Strapi&lt;/a&gt;. To keep this post on topic I am going to assume some prior knowledge on Strapi. If you're new to the technology and would like some intro guides, let me know and I will make a short series on this. Generally speaking though their documentation should be enough to get you up to speed quickly, I've leaned on them heavily to learn the platform.&lt;/p&gt;

&lt;p&gt;What I would like to address today however is a multi-environment setup for this tool, specifically around UI customization in the admin panel and persisting these changes across each environment.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8s6kd73w4wc40rk2ekx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8s6kd73w4wc40rk2ekx.jpg"&gt;&lt;/a&gt;&lt;br&gt;
If you've ever run Strapi in a multi-environment setup you will notice that whenever you spin up a new instance of your site you lose a lot of the UI customization in your application. By this I mean the "list" and "edit" views in your admin panel for a particular content type are set back to their default structure. It would be tempting to just set these back up manually in each environment because "It only needs to be done once". While this is true (and honestly probably not a deal breaker) it does present a possibilty for configuration drift between environments and just generally adds more potential places for there to be an error or misconfiguration.&lt;/p&gt;

&lt;p&gt;While there are no out-of-the-box solutions to persist this customization it can easily be achieved by using the &lt;code&gt;bootstrap&lt;/code&gt; functionality baked into Strapi. Let's disect that one below.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Initial Content Type
&lt;/h2&gt;

&lt;p&gt;For the example today we are going to stick with the blog format where we create a &lt;code&gt;Post&lt;/code&gt; content type. This type will have the basic building blocks that we need to render our posts on whatever website is consuming our Strapi API. A basic blog content type might look like below.&lt;/p&gt;
&lt;h3&gt;
  
  
  Post Content Type
&lt;/h3&gt;

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

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

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

&lt;p&gt;Now we have the option to go in and manually configure some of these views, for example in the &lt;em&gt;Post Edit View&lt;/em&gt; we can clearly see the button on the right marked "Configure the view".&lt;/p&gt;

&lt;p&gt;Let's do that now so we can change the order of some of the items, perhaps move the featured image to the top (to mimic the actual blog post structure) and rename some labels or add descriptions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Configured Post Edit View
&lt;/h3&gt;

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

&lt;p&gt;As you can see we have changed &lt;code&gt;Featured_image&lt;/code&gt; to read &lt;code&gt;Featured Image&lt;/code&gt; and moved it's position. We have also supplied an arbitrary description to the &lt;code&gt;Slug&lt;/code&gt; field. That's great and all but what happens when I spin up a new environment? I would have to do that all again manually. In this instance for two fields I would say that's probably OK, for a complicated data type that has additional logic or a hierarchy of information this isn't an overly acceptable solution.&lt;/p&gt;

&lt;p&gt;Thankfully Strapi saves this configuration in the database and we can pull it out as JSON, let's do that now!&lt;/p&gt;
&lt;h2&gt;
  
  
  UI Customiztion via JSON
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Connect to your local database instance. I am using Azure Data Studio with their PostgreSQL plugin. Feel free to use whatever tools you're comfortable with.&lt;/li&gt;
&lt;li&gt;Select all entries from &lt;code&gt;core_store&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;Look for a row labelled &lt;code&gt;plugin_content_manager_configuration_content_types::application::{content_type}.{content_type}&lt;/code&gt;. In this instance &lt;code&gt;plugin_content_manager_configuration_content_types::application::post.post&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copy the &lt;code&gt;value&lt;/code&gt; field. It should look something like below.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The data structure should be fairly self explanatory, we can make some tweaks the the &lt;code&gt;settings&lt;/code&gt; of this content type, whether it is filterable or searchable for example. Under &lt;code&gt;metadatas&lt;/code&gt; we can change details about each value in the content type. For example you can see the change we have made in &lt;code&gt;featured_image&lt;/code&gt; to change the label to &lt;code&gt;Featured Image&lt;/code&gt; when in the &lt;strong&gt;edit&lt;/strong&gt; view, though you can see that same change hasn't propogated over to the &lt;strong&gt;list&lt;/strong&gt; view.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;layouts&lt;/code&gt; key shows the heirarchy of our &lt;strong&gt;edit&lt;/strong&gt; view, I find that making these changes is easier in the UI and then exporting out the associated JSON however once you have the file the first time you can definitely move these around in code. Lastly the &lt;strong&gt;list&lt;/strong&gt; key under layouts specifies which keys, and the order of the keys gets shown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tweaking the UI Customization
&lt;/h2&gt;

&lt;p&gt;Now we have our JSON file and understand the structure we can go ahead and make some changes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We are going to make sure that the &lt;code&gt;created_at&lt;/code&gt; key says &lt;code&gt;Created At&lt;/code&gt; in the &lt;strong&gt;list&lt;/strong&gt; view as well as the &lt;strong&gt;edit&lt;/strong&gt; view.&lt;/li&gt;
&lt;li&gt;We are going to make the &lt;code&gt;featured_image&lt;/code&gt; media picker take up the full width of the admin panel (a change you seem to only be able to make via JSON)&lt;/li&gt;
&lt;li&gt;We are going to remove &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;featured_image&lt;/code&gt; from the &lt;strong&gt;list&lt;/strong&gt; view and replace it a &lt;code&gt;created_at&lt;/code&gt; column instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The differences are minor but can be seen below.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In order to test these changes the simplest way to it do (for now) is to edit the database directly and replace the current string with your current data and restart the server.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final List View
&lt;/h3&gt;

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

&lt;p&gt;As you can see our changes have worked, &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;featured_image&lt;/code&gt; have been removed and &lt;code&gt;created_at&lt;/code&gt; added in place with the correct label.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final Edit View
&lt;/h3&gt;

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

&lt;p&gt;As you can see our image picker now takes up the full width of the admin panel even though we only had the option to move it in the editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Persisting the Changes
&lt;/h2&gt;

&lt;p&gt;Now we know how to edit our UI customization file lets persist it. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Save that JSON file somewhere in your project so that it stays in source control and is easily referenced later.&lt;/li&gt;
&lt;li&gt;Create a file under &lt;code&gt;config/functions/bootstrap.js&lt;/code&gt; as per their docs on &lt;a href="https://strapi.io/documentation/developer-docs/latest/setup-deployment-guides/configurations.html#functions" rel="noopener noreferrer"&gt;Functions&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;bootstrap&lt;/code&gt; function call some code to update the corresponding database row with the file you have saved in your project. Here is an example utility function I have written that lets me pass in a json file location that corresponds to &lt;code&gt;&amp;lt;contentType&amp;gt;.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;As you can see I am using knex for this because I am familiar with it. That being said you could use the bookshelf or any other adaptor, or the suitable connector for your database type.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Now whenever your application starts (or hot reload fires in your dev environment) your UI customization is updated in the database and now your UI is configured across multiple environments.&lt;/p&gt;

&lt;p&gt;With some extra tweaks you can do the same with components that are within a more complex data type. The syntax is slightly different so I suggest a cool extension to this post, if you want to dig into it, is to work out how to persist UI Customization in components too. I do this in my current project and it's really handy.&lt;/p&gt;

&lt;p&gt;For those wondering when spinning up an entirely fresh environment the &lt;code&gt;bootstrap&lt;/code&gt; code gets run &lt;strong&gt;AFTER&lt;/strong&gt; strapi does a bunch of set up. That means your content type, even if it is "brand new" will still be in the database and your SQL query will run so you shouldn't need to do any complicated checks for rows or do some weird double-deploy nonsense. I have seen some back and forth on the Strapi Issue Tracker as the whether bootstrap should run before or after Strapi initializes, howevever given it provides us access to the database connector (and makes sure our data types are set up correctly) I am all for after as the default, as it currently is.&lt;/p&gt;

&lt;p&gt;Now you can worry less about your UI customization and more about the logic required to run your application. What's great is this method can be used whenever, so if you have to make changes through the UI you can easily pull out the updated files as required and persist them in your database. You could even find ways to automate that process, or pull your customization from a master database that it used for this purpose. Whatever your setup, by storing your UI customization in the database you have a wealth of opportunities to streamline your multi-environment customization.&lt;/p&gt;

</description>
      <category>node</category>
      <category>webdev</category>
      <category>strapi</category>
    </item>
    <item>
      <title>My Experiences Jammin' The Stack</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Thu, 11 Mar 2021 01:30:22 +0000</pubDate>
      <link>https://dev.to/iamscottcab/my-experiences-jammin-the-stack-40l6</link>
      <guid>https://dev.to/iamscottcab/my-experiences-jammin-the-stack-40l6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is an open letter to the JAMStack community about my experiences with the technologies so far. What I love, and more importantly what I don't love about the experience. While I am likely to be critical here I don't know how else to share this in long form. If you've come across this on social media and have any thoughts please share them as I'd love to iterate on what I have experienced already.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Stop trying to put jam in there...
&lt;/h2&gt;

&lt;p&gt;There are a number of things in this world I want to love. Either because I just think they are cool or because I think they fit the vision that I have of myself. Whenever I can't enjoy one of these things, particularly the ones that deviate from my own internal picture of myself, it makes me question if I really know what drives me. There are a number of these such things but a few that I keep trying and failing to fall in love with are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux as a full time OS&lt;/li&gt;
&lt;li&gt;Drawing&lt;/li&gt;
&lt;li&gt;Being super into a franchise&lt;/li&gt;
&lt;li&gt;Making physical things &lt;em&gt;(with my soft hands that always get hurt because I only require enough dexterity to hit these keys in roughly the right order every day)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And lately I've been able to add the JAMStack to that list.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a JAMStack?
&lt;/h2&gt;

&lt;p&gt;In case you have stumbled across this post and wonder why anyone would want to put jam anywhere near their tech stack let's get out of the way what this acronym is all about. JAMStack stands for a stack made up of Javascript, API's and Markup. Strictly speaking this typically means applications that have been developed by static site generators (or similar) that can be served out of a file storage location such as &lt;a href="https://aws.amazon.com/s3/"&gt;Amazon's S3&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The proposed benefits of the JAMStack are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better Performance&lt;/li&gt;
&lt;li&gt;Higher Security&lt;/li&gt;
&lt;li&gt;Cheaper, Easier Scaling&lt;/li&gt;
&lt;li&gt;Better Development Experience&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information I'd visit &lt;a href="https://jamstack.org/"&gt;jamstack.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it really better?
&lt;/h2&gt;

&lt;p&gt;I completely agree with the notion that serving static files from a Content Delivery Network (CDN) makes for better end user performance and provides a much cheaper way to scale website throughput.&lt;/p&gt;

&lt;p&gt;I can even get behind the notion that the site is more secure, although I still firmly believe you can misconfigure anything. I wouldn't be using this solely for its security benefits and rather consider it as a defense-in-depth mechanism along with your other tooling and build processes.&lt;/p&gt;

&lt;p&gt;What I am struggling to get behind in practice is the Better Development Experience. Naturally everyone creates content differently and for different reasons. I chose to create my own little corner of the internet and create blog content outside of the larger centralized blogging platforms. I risk a smaller reader base but I get to grow something that is my own and enjoy writing about things that make me happy and not necessary to watch the stats in my admin panel get better.&lt;/p&gt;

&lt;p&gt;Because of that my experience running my website now is largely about content creation. While I can (and definitely will) re-do this site again at some point, the design is purely driven by intrinsic motivation and a need to spice things up. What is most important to me is being able to jump into my browser and create blog content either on a whim, when motivation strikes, or as a planned endeavour (like today). Despite there being tooling out there to fit this exact purpose I've had a really hard time adopting the JAMStack when all I want to do is regularly author content.&lt;/p&gt;




&lt;p&gt;The following experiences aren't going to be presented in any sort of chronological or hierarchical format. They are just different things, that as the sum of their parts, put me off of JAMStack given my current workflow. I would love advice on how this could be changed, if for nothing more than my adding to my "not for me" list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown is fine, I guess.
&lt;/h2&gt;

&lt;p&gt;Markdown is great. Let me just get that out of the way. I know that in the editor I am using right now it's all getting stored / parsed out as Markdown. However for publishing I still find a What You See Is What You Get (WYSIWYG) editor to be my preferred method of blog writing. It's the closest analogue I get the final result in my browser and it largely matches my experiences in other non-tech editor spaces such as Microsoft Word.&lt;/p&gt;

&lt;p&gt;I also don't really want to work in VSCode if I can work in my browser. I write code in VSCode and I want separate tools for separate responsibilities.&lt;/p&gt;

&lt;p&gt;So I had a look at &lt;a href="https://www.netlifycms.org/"&gt;Netlify CMS&lt;/a&gt; and am yet to try (but am eagerly looking forward to trying) &lt;a href="https://forestry.io/"&gt;Forestry&lt;/a&gt;. These do somewhat fill the gaps I am looking for, but I'd rather not be tied to an authentication provider to make these work if I am going to be moving to static site generation. I'm not sure this is an odd opinion to have, or one that even makes sense. The goal of moving to static site generation allows for flexibility of hosting options, from S3 to Azure, Google Cloud or even self hosting off a Raspberry Pi. Thus, it feels counter to me to lock myself into an auth provider for my server-less CMS. Perhaps this is my major hurdle to enlightenment, letting go and creating "yet another login™".&lt;/p&gt;

&lt;h2&gt;
  
  
  Oh, I have to make that now...
&lt;/h2&gt;

&lt;p&gt;The benefit of using a CMS is (in my opinion) being able to leverage the combined efforts of a larger team. If I want tags, they exist. If I want to schedule a post my server can do that too. If I want multiple authors I can make that work as well.&lt;/p&gt;

&lt;p&gt;Now I can do all those things myself too. But like the rest of us I have limited time resources and I like to use those doing a myriad of things. I don't want to spend 10's of hours writing new features for my site or debugging ones when they go wrong. I don't want over complicated GitHub Actions or serverless Lamba style functions that send dummy commits to my repository to simulate scheduling posts. It's fine but it all seems like a workaround, with far limited user (and developer) experience just to replace something that doesn't seem that bad to me.&lt;/p&gt;

&lt;p&gt;If I want to preview my website before it goes live I don't want to jump into a GitHub Pull Request to see it, I want to just open the preview in a new tab. It's not just about when I want my content to come out but how I can best manage it while it is in draft also.&lt;/p&gt;

&lt;p&gt;The JAMStack promises flexibility and no reliance on any particular technology. A blank canvas is daunting and easily leads to over-engineering of things that really should be intuitive and simple. I'd argue that for most personal blogging platforms the 1-Click style installers that live on most shared hosting solutions are far less a barrier to entry, even to developers, than using the JAMStack.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XH2-4dcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/niy4fkdrdjuxhoa6xkoi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XH2-4dcv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/niy4fkdrdjuxhoa6xkoi.jpg" alt="" width="682" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Static Sites &amp;amp; Headless CMS
&lt;/h2&gt;

&lt;p&gt;I feel like there is some nice middle ground where I have a headless CMS, connected via webhooks to go and trigger a new static website build. It feels like a nice marriage between many of the perceived benefits of a JAMStack site with the added benefit of a better publishing user experience.&lt;/p&gt;

&lt;p&gt;There is just one catch though, if I have a headless CMS that I am paying for I might as well use it to also serve my content. It's true that paying for a VPS is a relatively cheap exercise these days, particularly for low traffic blogs like mine. But they still do incur a cost so if I were to suddenly get famous (maybe off this very post) the cost for me to scale sufficiently would be problematic. I could, as an interim solution, split between serving my website statically but generating content on my headless CMS but now I am paying for two resources and not consolidating to one.&lt;/p&gt;

&lt;p&gt;I know it's not all roses over here on the Headless CMS side. In some respects I feel locked into my current provider even though I self host. By writing content in a WYSIWYG Editor my posts are now not portable. If I do need to pick them up and move them tomorrow, or cross post them elsewhere I really don't have a good solution for that. I think in this respect the JAMStack shines and is one of my key motivators for moving.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where to from here?
&lt;/h2&gt;

&lt;p&gt;Dear JAMStack community. Where should I be going from here? My goal would is and &lt;a href="https://www.11ty.dev/"&gt;11ty&lt;/a&gt; based site running either Forestry or a competing serverless CMS. I could fairly easily port this website over the 11ty, in part because Ghost uses the same markup language. I could either port all my posts over and try Forestry, or I could continue to use Ghost with the 11ty starter.&lt;/p&gt;

&lt;p&gt;For regular content authors what was your approach to moving to the JAMStack and was it worth the effort? I'd love your feedback.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Instantiating MonoBehaviours in Unity</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Thu, 03 Dec 2020 00:11:41 +0000</pubDate>
      <link>https://dev.to/iamscottcab/instantiating-monobehaviours-in-unity-5c2g</link>
      <guid>https://dev.to/iamscottcab/instantiating-monobehaviours-in-unity-5c2g</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article is intended for novice programmers who are looking at using Unity in a repeatable and less tightly coupled way than they currently are. I assume a basic understanding of inheritance and generics as well as Unity functions such as &lt;code&gt;AddComponent&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The backbone of Unity games are GameObjects and MonoBehaviours. One of the complications with using them is that we cannot utilise constructors when creating an instance of these objects. So there is a fine balancing act instantiating and seeding MonoBehaviours when they are being added to a scene dynamically via code.&lt;/p&gt;

&lt;p&gt;This article will explore different design patterns that attempt to provide constructor-like functionality to MonoBehaviours to make them a little more user-friendly for programmers used to the Object-Oriented programming paradigm.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;For the purposes of this article we want to create a new &lt;strong&gt;Projectile&lt;/strong&gt; which will be used by a &lt;strong&gt;Gun&lt;/strong&gt; and when we create that projectile we want to give it an initial speed. Ideally, in an Object-Oriented paradigm we would pass this value in through the constructor like so.&lt;/p&gt;

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

&lt;p&gt;However in Unity we are forbidden from using constructors on MonoBehaviours because they are utilised by the Editor before and after serialisation. Using them can lead to editor and engine breaking side effects when used improperly. In 2016 Unity introduced errors whenever trying to call Unity &lt;strong&gt;“main thread”&lt;/strong&gt; API endpoints from constructors (and pretty much everything is a main thread API endpoint). If you’d like to read about it here is a short &lt;a href="https://blogs.unity3d.com/2016/06/06/serialization-monobehaviour-constructors-and-unity-5-4/" rel="noopener noreferrer"&gt;Official Unity Blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Unity way to create our projectile and set it’s speed would look something like the following.&lt;/p&gt;

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

&lt;p&gt;Not only is there a lot more boilerplate code here but we have broken the encapsulation on the Projectile by making the speed float public. We also have no good way to make sure the projectile has a valid speed when it is created.&lt;/p&gt;

&lt;p&gt;This is the crux of most of the Unity pattern. It is super flexible, values can be added in the Editor or via code, but because of that a lot code based implementations feel very tightly coupled. If we want to change the projectile to use a prefab instead of a new game object any class that makes a Projectile has to go and implement these changes. *&lt;strong&gt;&lt;em&gt;EVERYWHERE.&lt;/em&gt;&lt;/strong&gt;* The gun probably shouldn’t even know how a projectile goes together, it should just be able to make one. What are some ways we can get around this?&lt;/p&gt;




&lt;h3&gt;
  
  
  Init Method
&lt;/h3&gt;

&lt;p&gt;The Init Method is the most simple implementation which, likely because of its simplicity, is also the most useful in most situations. Simply add an Init method to any class that needs to be set up with values as soon as it is created.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flexible&lt;/li&gt;
&lt;li&gt;Easy to implement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unable to enforce use of the Init Method (we will discuss this later)&lt;/li&gt;
&lt;li&gt;Unable to use the Awake Method to set up anything else that relies on speed (this will also be a common theme moving forward)&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Static Create Method
&lt;/h3&gt;

&lt;p&gt;I like the Static Create Method approach because it is like the Init method above wrapped in some syntactic sugar. For basic instantiation we often want to repeat the same code over and over again. By leveraging a common base class we can do a lot of that repeatable code in one place. We can even generic out the base class, perhaps like below.&lt;/p&gt;

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

&lt;p&gt;We could then add our own custom Create implementation in the child class, which we were doing with our Init function anyway…&lt;/p&gt;

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

&lt;p&gt;Except now we don’t have to worry too much about actually creating and naming our GameObjects which is nice. We have also preserved encapsulation in our Projectile because the static method can work on the private members of that instance when it creates it. Then lastly our gun can create the projectile.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some nice syntactic sugar around Init&lt;/li&gt;
&lt;li&gt;Core implementation changes can happen in one place&lt;/li&gt;
&lt;li&gt;Obfuscates the need for Gun to know how to make a projectile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unable to enforce use of the Create Method&lt;/li&gt;
&lt;li&gt;Unable to use the Awake Method to set up anything else that relies on speed&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Nested Private Class
&lt;/h3&gt;

&lt;p&gt;This was about the weirdest and most restrictive use case I could come up with. It was derived from the idea that if we decide on a non-standard instantiation method for Monobehaviours it needs to be enforcable. My requirements for &lt;strong&gt;“enforcing”&lt;/strong&gt; a code style (without git hooks or linting or anything crazy) was to make it so that you could not manually add the Component to a GameObject in the scene and also not randomly call AddComponent from anywhere in the game and improperly set up the MonoBehaviour.&lt;/p&gt;

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

&lt;p&gt;Thus the Nested Private Class solution. How does this work, why does this work and should I use it?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This works by abusing encapsulation. Despite the speed float being public in the ProjectileBehaviour class, because that class itself is a private helper of the Projectile class, we can never get it’s values from outside of the parent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This boils down to how Unity handles MonoBehaviours. If a MonoBehaviour does not contain the same name as the file in which it resides (private or otherwise) then you cannot add it to a GameObject in the Editor.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Should I use it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Probably not. One neat little trick though was to add some implicit operators so if I really wanted I could do something like this…&lt;/p&gt;

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

&lt;p&gt;There are many cases where you might want to make a new Component but only care about it’s Transform, or some other general type. For example you may want to track it’s position, or see if it still exists in the scene. Although we created a new class of type Projectile we can implicitly operate on it as if it were a Transform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enforces creation via class constructors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can’t get the actual MonoBehaviour type (in this case ProjectileBehaviour) back out due to encapsulation. You would need to wrap everything at the class level&lt;/li&gt;
&lt;li&gt;Not easily repeatable, at least, I’ve not found a good way to generic this out&lt;/li&gt;
&lt;li&gt;Implicit operators aren’t overly verbose and can make for hard to read code later&lt;/li&gt;
&lt;li&gt;Unable to use the Awake Method to set up anything else that relies on speed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wouldn’t really recommend this pattern, but it does work!&lt;/p&gt;




&lt;h3&gt;
  
  
  Making Your Own MonoBehaviour
&lt;/h3&gt;

&lt;p&gt;If I was willing to nest a private MonoBehaviour class inside a normal class, could I not just wrap the entire GameObject class? Of course I could! I shouldn’t, and for the sake of stopping this article getting too long I won’t show you the whole thing. But if you were nuts about attempting to enforce this pattern everywhere you could do something crazy like this.&lt;/p&gt;

&lt;p&gt;I don’t suggest you try this at home, but for the curious…..&lt;/p&gt;

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

&lt;p&gt;Making my Projectile:&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Able to enforce constructor based instantiation&lt;/li&gt;
&lt;li&gt;It feels “GameObjecty” when coding in the Projectile class because it utilises the Unity Lifecycle methods&lt;/li&gt;
&lt;li&gt;It is super over-engineered (and isn’t that what this is all about)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is super over-engineered&lt;/li&gt;
&lt;li&gt;You would need to expose and maintain all the functions that MonoBehaviours expose (which seems entirely pointless)&lt;/li&gt;
&lt;li&gt;All those &lt;strong&gt;“magic”&lt;/strong&gt; functions that Unity looks for, such as Update, will not be optimised out of your build and each one of your ScottoBehaviours will be creating unnecessary calls to empty functions&lt;/li&gt;
&lt;li&gt;I didn’t performance check it but all those delegates would surely cause lots of issues down the track&lt;/li&gt;
&lt;li&gt;I couldn’t get the Finalizer to fire on my ScottoBehaviour either?&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Prefabs &amp;amp; Factory Method
&lt;/h3&gt;

&lt;p&gt;Prefabs are pre-made GameObjects with preset values that can be reused over and over again like a template in your game. You can make them in the editor and then save them into the project hierarchy for re-use within your project.&lt;/p&gt;

&lt;p&gt;If you wanted to implement something that was the &lt;strong&gt;MOST&lt;/strong&gt; Unity I would suggest creating Prefabs and using a class to return an instance of that Prefab at run-time. The specific implementation is up to you. A singleton instance would allow you to drag and drop the Prefabs into your game at run-time. A static class would allow you to load Prefabs from either an Asset Bundle or the Resources folder or you could come up with your own serialisation and deserialisation methods. Perhaps look at combining with a pool for even better performance! As an example I have written a simple static class that loads assets from the Resources folder based on a string value. Please don’t use string values in production code, use an enum or something else that can’t easily be typed incorrectly. The code below is merely supposed to demonstrate the concept.&lt;/p&gt;

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

&lt;p&gt;Our Gun would then create a Projectile in the following fashion.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilises all the Unity tools rather than trying to fight them&lt;/li&gt;
&lt;li&gt;Allows for tweaks to be done in editor rather than always in the code base&lt;/li&gt;
&lt;li&gt;No weird class wrapping&lt;/li&gt;
&lt;li&gt;Gun doesn’t need to concern itself with the speed of a bullet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can’t enforce creation through the factory method&lt;/li&gt;
&lt;li&gt;Can’t use the Awake function in projectile&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;Most game developers that I talk to that work on larger projects seem to spend most of their time fighting with Unity rather than embracing it’s paradigms. Sometimes there is good reason to do that but often I think it’s to try and do things a “better” way. Which, aside from being totally subjective, takes a lot of time away from making the actual product.&lt;/p&gt;

&lt;p&gt;In almost all my test cases aside from going to everyone I work with and saying &lt;strong&gt;“This is the pattern we use for instantiation on this object now”&lt;/strong&gt; there isn’t a great way to enforce a &lt;strong&gt;“newable”&lt;/strong&gt; pattern on MonoBehaviours. All the solutions above would work in different circumstances but none of them work well in all situations. I tried very hard to do run-time checks to make sure an Init or Create function were called but they are simply too easily overridden and any other service on top just makes these approaches too heavy to manage. I’d like to explore linting rules later around this problem to see if that is an enforcement option.&lt;/p&gt;

&lt;p&gt;Interestingly in all the situations, with exception of the entirely wrapped GameObject class, calling AddComponent on any MonoBehaviour class basically renders the Awake method moot if it needs to use any of the values you want to set via a script. Whether you do that the good old fashioned way, or over-engineer some nonsense like above, Awake is called immediately. You just have to deal with the fact that your MonoBehaviour won’t be set up in time properly to utilise that method so stick with Start if your set up requires these values.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>unity3d</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Debugging Meta Tags On Localhost</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Wed, 25 Nov 2020 22:29:46 +0000</pubDate>
      <link>https://dev.to/iamscottcab/debugging-meta-tags-on-localhost-413c</link>
      <guid>https://dev.to/iamscottcab/debugging-meta-tags-on-localhost-413c</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Meta tags are useful machine parse-able tags that live in the header of your website. As their name might suggest these tags provide extra metadata about your site. That is, data about your data...&lt;/p&gt;

&lt;p&gt;Their usefulness (aside from providing extra metadata about your site) is largely derived from their use on social media. Whenever you see a link shared with a nice preview image and description this information is getting pulled from the meta tags embedded on the site.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The only slightly annoying thing about meta tags is testing them on your local machine, which is imperative if you don't want to do live debugging in production.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reason this is difficult is because your machine is not (typically) accessible to the internet, particularly from localhost, so the sites that you might want to check them against simply can't pull the relevant information to generate the previews you are after.&lt;/p&gt;

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

&lt;p&gt;We need a quick and easy solution to make the website we are hosting locally accessible on the internet without worrying about building it or hosting it elsewhere, or even port forwarding. To do that we are going to use a product called &lt;a href="https://ngrok.com/"&gt;ngrok&lt;/a&gt;. This tool provides &lt;em&gt;"...secure introspectable tunnels to localhost..."&lt;/em&gt;. In short we can give our running localhost server a short lived, temporary url to test our meta tags against.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Make sure you have your meta tags set up on your website already. If you don't know where to start you can scroll down to the section &lt;em&gt;"Altering (Or Making) Tags"&lt;/em&gt; and then come back.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ngrok.com/download"&gt;Download ngrok&lt;/a&gt; and follow the setup instructions. (You will need an account but they have a free tier).&lt;/li&gt;
&lt;li&gt;Spin up your local web server.&lt;/li&gt;
&lt;li&gt;Start ngrok on the same port as the server you are running. For my local Ghost CMS that is port 2368.&lt;/li&gt;
&lt;li&gt;Copy the URL from the command line and paste it into your web browser.&lt;/li&gt;
&lt;li&gt;You should see the same web server you had running on localhost. 👍&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Testing the Tags
&lt;/h2&gt;

&lt;p&gt;There are a couple of ways to do this, and I used both of them, to be sure they were working as I intended.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use a website that parses meta tags for you, I have had good luck with both &lt;a href="https://metatags.io/"&gt;metatags.io&lt;/a&gt; and &lt;a href="https://www.heymeta.com/"&gt;heymeta&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can DM yourself on Twitter, or even post your link to yourself in Slack to the Slackbot, and then unfurl the URL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are a few "gotchas" that I noticed with both of these methods.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I am not sure if the above sites cache results locally, but when I was consistently changing the default image for my meta tags I had to test in an incognito window. Otherwise I would often receive the same result over and over.&lt;/li&gt;
&lt;li&gt;If, like me, you are checking your meta tags because a previous share left for a lackluster link preview, just note that in applications like Twitter (which preview the link before you send it) are likely to show your old preview. You are going to want to actually send it properly which seems to resolve whatever caching occurs on the link preview.&lt;/li&gt;
&lt;li&gt;I wanted to use fully qualified asset links to be safe &lt;em&gt;(e.g. &lt;a href="https://site/path/to/image"&gt;https://site/path/to/image&lt;/a&gt;)&lt;/em&gt; rather than relative &lt;em&gt;(e.g. ./path/to/image)&lt;/em&gt;. Because of this quirk I made sure my static assets were available on my production domain before I did the test. If relative links work for you though please let me know so I can update this part of the post.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Altering (Or Making) Tags
&lt;/h2&gt;

&lt;p&gt;If your meta tags aren't quite right, or you aren't even sure where to start the two sites mentioned above (&lt;a href="https://metatags.io/"&gt;metatags.io&lt;/a&gt; and &lt;a href="https://www.heymeta.com/"&gt;heymeta&lt;/a&gt;) allow you to edit the tags directly in the browser and generate the result. This lets you quickly iterate on your design without having to worry too much about the code or missing important tags.&lt;/p&gt;




&lt;p&gt;When you're done close down ngrok, push to production and pat yourself on the back.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
    <item>
      <title>I Contributed to Open Source (and it was hard...)</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Mon, 23 Nov 2020 22:20:43 +0000</pubDate>
      <link>https://dev.to/iamscottcab/i-contributed-to-open-source-and-it-was-hard-57gl</link>
      <guid>https://dev.to/iamscottcab/i-contributed-to-open-source-and-it-was-hard-57gl</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is a look back at my first experience with Open Source prior to &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; 2020.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;With &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; coming up in just over a month I thought now was a great time to share my experience contributing to my first Open Source project (that wasn't my own).&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Open Source?
&lt;/h2&gt;

&lt;p&gt;I don't want to spend too much time on this question from a social perspective because there is already a lot of writing on the value of Open Source tools within the technology community. What I do want to do though is share why I have wanted to contribute to Open Source for so long.&lt;/p&gt;

&lt;p&gt;Just as my Honours year at university was winding down I applied for (and successfully received) a PhD scholarship, which for various reasons I ended up turning down. However, my initial desire to chase a life of academia was born out of a conversation I have replayed with a friend a few times over late nights.&lt;/p&gt;

&lt;p&gt;He shared his passion for the academic system and particularly the PhD path. This idea that we all incrementally make progress by adapting and uplifting each others ideas and ultimately then give that knowledge back to the rest of the world to use in ways that empower and help each other at scale. While I am critical of whether the modern day university fills that romantic notion any more there was something elegant to being able to give back in some small way. That my actions would ultimately be greater than the sum of parts I had to put in to make it possible.&lt;/p&gt;

&lt;p&gt;Open Source represents that same ideal to me. That I am able to make a series of small changes that ultimately, along with my peers, make for a better &lt;em&gt;thing&lt;/em&gt;™ is a really rewarding and empowering idea. I think it captures the essence of what I was searching for in academia but seems to apply it in a more pragmatic and timely approach.&lt;/p&gt;

&lt;p&gt;I lay out the above because for me contributing to Open Source is akin to volunteering. It requires my time to make something better (hopefully) and have others enjoy it. My time has inherent value and so when I chose I was ready to commit to Open Source it needed to be for a project (or projects) that I either used or wanted to support.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iiQCGRfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mw34xv0xc88sk8yb2lfj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iiQCGRfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mw34xv0xc88sk8yb2lfj.jpg" alt="What Now" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Here is the issue though, just because I use certain software doesn't mean I always know how it works, or in some cases, it just doesn't utilise the languages or skills I know. For some people this provides a fantastic place to start learning new skills or pick up a new challenge. But what if you're a relatively new coder, or at the very least, new to collaborating on Open Source projects? You, like me, probably want to tackle a language you know and hopefully a tool where the code base is at least representative of work you have done in the past.&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://hacktoberfest.digitalocean.com/"&gt;Hacktoberfest&lt;/a&gt; coming out soon I took some time out of a quiet work day to do some investigation. What repositories were out there that I knew of and thought were worth supporting? Of those which ones had languages I was comfortable with? Did those repositories have huge communities where issues were either snapped up really quickly (or the sheer volume was overwhelming)? Was there anything that looked small enough that I can conceivably grab and get a small win on in a day or so? There's a lot of things that can be a blocker to getting started that aren't just code related.&lt;/p&gt;

&lt;p&gt;After a while I ran into the &lt;a href="https://ghost.org/"&gt;Ghost&lt;/a&gt; blogging platform (the very platform that powers &lt;a href="https://scott.cab/blog/"&gt;my blog&lt;/a&gt;). It seemed perfect, it was in a language that I was familiar with and it was a product I used. By chance 9 hours earlier a small visual defect in the Admin Panel was raised as an issue which seemed like something I could pick off.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting Up My Development Environment
&lt;/h2&gt;

&lt;p&gt;What I have always taken for granted on my development projects has either been that they are "green-fields" (brand new) or I've worked with someone that I am inheriting the project from so there is a wealth of knowledge on how to set up and maintain those projects. Additionally as most of those have been with similar team members the patterns are the same. Despite Ghost providing &lt;a href="https://ghost.org/docs/install/source/"&gt;robust install from source documentation&lt;/a&gt; it was still frustrating to get it to run locally. For brevity here was roughly the journey:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not wanting to run yarn side-by-side with my npm installs (I thought these were competing platforms, but really they can totally live side-by-side)&lt;/li&gt;
&lt;li&gt;Windows being unfriendly with some Ghost related setup (like having to run Powershell in Admin mode?)&lt;/li&gt;
&lt;li&gt;Trying to circumvent the whole issue by running it in a Docker container.&lt;/li&gt;
&lt;li&gt;Realising that the Ghost install only listens on localhost and having to change default values to listen on all IP addresses so I can access it from my host machine, then worrying I will accidentally commit the file.&lt;/li&gt;
&lt;li&gt;Giving up and just running yarn and npm next to each other...&lt;/li&gt;
&lt;li&gt;Yarn commands not working unless I prepended them with &lt;code&gt;yarn&lt;/code&gt; because npm was trying to take over!!!!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Making The Change
&lt;/h2&gt;

&lt;p&gt;It is really cumbersome looking through a new code base to find where things hang together. There is a feeling of complete loss and confusion. Hacking in a fix is generally pretty easy. Is this the right place, is this where the maintainers would want me to put it? How thoroughly do I need to test the fix, it's three lines of code! What if I cause a regression? Has someone else already fixed it in the time it has taken me to track the fix down?&lt;/p&gt;

&lt;p&gt;About 4 hours after deciding that I was now an Open Source Contributor I was feeling a little tired but glad I took the plunge, now all I had to do was get the PR up and wait...&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the PR
&lt;/h2&gt;

&lt;p&gt;Although I am starting to adopt Github for some of my public side projects I am largely familiar with Bitbucket and Azure DevOps and predominantly on single projects where merges happen internally on branches. So forking repositories and making merges from one repository to another and trying to work out if I can link issue tickets from the main repository to a sub-repository was all a little taxing. It's doable and it's not hard, and almost all of it is reversible but you still want to get it right. Having my first Open Source PR publicly rejected because I missed something silly would have been embarrassing for me. Thankfully the good folks over at Digital Ocean do &lt;a href="https://www.digitalocean.com/community/tutorial_series/an-introduction-to-open-source"&gt;have a good primer on this&lt;/a&gt; if you're new to the wacky world of Open Source Pull Requests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DM8fWgHy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0zliggp5t9ws5rrr2ji.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DM8fWgHy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0zliggp5t9ws5rrr2ji.png" alt="PR Complete" width="880" height="266"&gt;&lt;/a&gt;&lt;/p&gt;
PR Complete



&lt;h2&gt;
  
  
  Using my Changes
&lt;/h2&gt;

&lt;p&gt;In less than 24 hours my change was approved, merged and included in a new build. The following morning I was able to update &lt;a href="https://scott.cab/blog/"&gt;my blog&lt;/a&gt; to Version 3.31.1 (for those of you playing along at home) and my glorious css selector was added to the code editor widget here in the very Admin Panel I use to draft posts. Pretty cool!&lt;/p&gt;




&lt;h2&gt;
  
  
  Where To Next?
&lt;/h2&gt;

&lt;p&gt;I always have a lot of side projects I am keen on and there is one I plan on starting around Hacktoberfest because it seems like a great way to get a free t-shirt and work on something that is both fun and maybe pointless! I'm definitely going to keep an eye on software I use (or think should continue to exist) and try and pick more of these smaller issues up. It was rewarding to give back to the software that I get to use for free.&lt;/p&gt;

&lt;p&gt;With that said I do hope the Open Source maintainers try to find easier ways to get projects up and running for local development. If I could download a docker image, do some minimal set up to that and just connect to it via VSCode to do all my development work that would get me onboard so much faster. Having to stand things up and configure them for what was a three line change was definitely at some points a little frustrating. And if I don't come back and pick up anything soon it was definitely a lot of work for a small reward.&lt;/p&gt;

&lt;p&gt;Perhaps for Hacktoberfest I will get lucky and find some other small PR's or even documentation fixes. If you're like me and looking for a place to start then I found that the &lt;a href="https://github.com/MunGell/awesome-for-beginners"&gt;"Awesome For Beginners" List&lt;/a&gt; was a good place to start.&lt;/p&gt;

&lt;p&gt;With it all said and done it was great to finally break that seal of indecision and get in there and give it a go. It went better than I thought and I am now more confident to try it again in the future. Just don't take the easy tickets from me if you can help it 😉. Happy Open Sourcing!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Exploring the Myth: Calculating Square Root is Expensive</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Fri, 20 Nov 2020 06:11:38 +0000</pubDate>
      <link>https://dev.to/iamscottcab/exploring-the-myth-calculating-square-root-is-expensive-44ka</link>
      <guid>https://dev.to/iamscottcab/exploring-the-myth-calculating-square-root-is-expensive-44ka</guid>
      <description>&lt;p&gt;I know this curious fact about game development that says where possible never to use the magnitude of a vector (unless required) because it involves a costly square-root calculation. Even the &lt;a href="https://docs.unity3d.com/ScriptReference/Vector3-magnitude.html" rel="noopener noreferrer"&gt;Unity documentation&lt;/a&gt; affirms this notion. What’s interesting is that I’ve never officially learned this and I only really see it floating around the internet, most recently on Reddit. It seems to be one of those things aspiring game developers learn through osmosis.&lt;/p&gt;

&lt;p&gt;It is one of those sayings that makes sense on the surface but I wanted to dig into how much slower the square root operation was and if it had any meaningful impact on performance in what I would deem, “normal” circumstances.&lt;/p&gt;




&lt;p&gt;When programmers talk about the cost of an operation they typically mean how many instructions are required to perform the operation. For example a multiplication would typically take three instructions, two reads and one write. For more complex operations (such as division) it often takes many more steps to calculate an accurate representation of the result, thus, the expense in the operation. While square root may have once been an extremely costly exercise I have a hunch that it is now a much less relevant piece of advice than it used to be. Additionally it leads newer programmers to focus on changing the way they write code in order to optimize said code as they go. I am a big believer in writing clean, verbose code and optimizing only when it is absolutely necessary. That can be hard as a new programmer where you often want to write cleaner and more efficient code than your last attempt at solving the same problem. It gives you a sign that you are progressing and allows you to tackle bigger problems.&lt;/p&gt;

&lt;p&gt;I devised some small tests to get some real world numbers on the time it took my machine to complete a large number of square root calculations and then compared them with the alternative.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Experiment
&lt;/h3&gt;

&lt;p&gt;Perform 1,000 loops of 1,000,000 calculations (yes for a total of 1,000,000,000 calculations). Record the minimum, maximum and average time it took to complete each one of these loops in “real world” time. Each loop consisted of either a square root calculation, multiplying a target variable by itself, or raising the same target variable to the power of 2.&lt;/p&gt;

&lt;p&gt;I’m not overly concerned about how long any of these operations actually take. I don’t care about the fastest time, I care about the proportionate time between the operations. The likelihood here is that I may very well be able to get faster times given different set ups. As an example everything was being run in debug mode on a Windows machine, this is likely to effect the overall time it takes to complete each task. Take the actual values with a grain of salt, we can compare the interesting parts further down. To see the code I used to run the tests check out my gists &lt;a href="https://gist.github.com/thescottcabs" rel="noopener noreferrer"&gt;here&lt;/a&gt;. If you want a brief overview of the code I was testing out it really all boils down to comparing the below.&lt;/p&gt;

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



&lt;p&gt;If the prevailing opinion is that square root is slower than simply multiplying our target value by itself then it is obvious to pit those two calculations against each other. I chose to add the power function to my testing because it seems like a simple interchange to make. Instead of using square root I could instead square my target value by raising it to the power of two.&lt;/p&gt;

&lt;p&gt;I’ve also added some Unity specific tests focusing on &lt;code&gt;Vector3.magnitude&lt;/code&gt; vs &lt;code&gt;Vector3.sqrMagnitude&lt;/code&gt; as another metric by which to judge, because quite frankly, that is more important to me as a predominantly Unity developer.&lt;/p&gt;

&lt;p&gt;To make sure this myth is not language specific I tested in &lt;strong&gt;dotnet Core 2.1&lt;/strong&gt;, &lt;strong&gt;Unity 2018.2.14f1 .NET 3.5 Equivalent&lt;/strong&gt;, &lt;strong&gt;Node 8.9.0&lt;/strong&gt; and &lt;strong&gt;Python 2.7.15&lt;/strong&gt;. For reference I am testing on Windows 10 on an i7 8750-H CPU.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;As mentioned above I’m testing that this myth exists across programming languages. However I don’t want to compare between programming languages because the speed of the language in general doesn’t bother me. Let’s see how each language performed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F02szhmnvn8zfzxyrstt3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F02szhmnvn8zfzxyrstt3.png" alt="Time per 1,000,00 calculations."&gt;&lt;/a&gt;&lt;/p&gt;
Time per 1,000,00 calculations.



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gwuxgea3wzmkl93jugh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6gwuxgea3wzmkl93jugh.png" alt="Time per 1,000,000 calculations. Notice the added calculations for Vector magnitude."&gt;&lt;/a&gt;&lt;/p&gt;
Time per 1,000,000 calculations. Notice the added calculations for Vector magnitude.



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftsppkl8ia6vwyi2l8bcz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftsppkl8ia6vwyi2l8bcz.png" alt="Time per 1,000,000 calculations."&gt;&lt;/a&gt;&lt;/p&gt;
Time per 1,000,000 calculations.



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq0uwny12hge8ak4h25ka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fq0uwny12hge8ak4h25ka.png" alt="Time per 1,000,000 calculations."&gt;&lt;/a&gt;&lt;/p&gt;
Time per 1,000,000 calculations.






&lt;p&gt;These results show us that there is a small difference in the speed of calculating a square root when compared to simply multiplying our target value. In c# the power function was considerably slower on average than both the square root and multiplication approaches. We could easily write code that performs worse than just simply using our square root calculation to start with. The latter also happens to be easier to read code.&lt;/p&gt;

&lt;p&gt;Ignoring the fact that performing Vector math is on average slower than float math, which I expected, checking the magnitude operation was not that much slower than checking the square magnitude.&lt;/p&gt;

&lt;p&gt;In an attempt to put this altogether I tried to visualize how much faster, or slower, each approach was than using a square root.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjhzlbpt1uwcgxanwq4e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjhzlbpt1uwcgxanwq4e4.png" alt="Number of ‘times’ of performance."&gt;&lt;/a&gt;&lt;/p&gt;
Number of ‘times’ of performance.



&lt;p&gt;We can see that in the case of the Unity it is significantly better, 2.5x in fact, to use multiplication over using a square root. The other languages however are all modestly different, if we use either approach for a reasonable amount of calculations we are unlikely to see a serious bottleneck in performance.&lt;/p&gt;




&lt;p&gt;In the best case scenario, at 2.5x better performance for multiplication, what sorts of gains could we expect to see? Per operation, that is for a single square root, we could save a whopping 0.033173 &lt;strong&gt;microseconds&lt;/strong&gt;. If we instead tried to be smart and raise our target value to the power of two we would make things considerably worse, however we would still only be adding 0.157795 &lt;strong&gt;microseconds&lt;/strong&gt;. There is no doubt that performing Vector math will have overhead because of the two dimensions but performing a check on square magnitude instead of magnitude only nets a performance increase of 0.051819 &lt;strong&gt;microseconds&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;The above is a classic case of micro-optimization. On paper it seems amazing to write code that is 2.5x faster. But it does come at the cost of some readability, and debug-ability, for fairly minimal performance gain. Technically square root is slower than multiplying our target value by itself, but practically I am not so sure, not for typical use cases anyway. If you are new to programming it is fine to learn these pieces of information and keep them tucked away. With that said you do not need to rush out use them when you could simplify your math. Checking against something such as magnitude will be easier for you, or your coworkers, to debug later.&lt;/p&gt;

&lt;p&gt;If you are in the position where you need to calculate 1,000,000 square roots in one frame of a game loop then I’d argue you have a design problem. Look at alternative solutions such as separate threads or an async pattern instead of looking to try to optimize your square root function. I would also like to hope that by the time you reach a problem like this you are already well on your way to understanding the pitfalls of micro optimization.&lt;/p&gt;

&lt;p&gt;As a final note I found the speeds coming out of Unity as a whole really interesting. Of all the languages I expected the Unity square root approach to be one of the fastest across the board. Given the language is designed for game development I expected a slightly less accurate float with the benefit of speed. That just didn’t seem to be the case here. My advice, get the feature in and optimize it once you know it is a problem.&lt;/p&gt;

</description>
      <category>unity3d</category>
      <category>node</category>
      <category>python</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Gittin' efficient with Git Push</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Thu, 19 Nov 2020 05:47:16 +0000</pubDate>
      <link>https://dev.to/iamscottcab/gittin-efficient-with-git-push-10bc</link>
      <guid>https://dev.to/iamscottcab/gittin-efficient-with-git-push-10bc</guid>
      <description>&lt;p&gt;At work we undertake two university placement rounds each year. It's always fun to get to teach people things you know and get exciting new ideas and energy into the team from fresh faces.&lt;/p&gt;

&lt;p&gt;One of the other benefits of hosting juniors is that they often ask questions you've never thought about or just taken the answer at face value. One such question during onboard related to the semantics about git push. So let's take a look at the current behaviour, and then how we might change it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Let's say our student is being on-boarded to an existing project and they are being asked to work on an existing branch upstream. That's pretty easy, we get them to do a git pull on the relevant branch.&lt;/p&gt;

&lt;p&gt;Now assuming that the developer does not have a local copy of this branch git goes ahead and sets all that up for us making an association between the upstream branch and the local copy it is currently creating.&lt;/p&gt;

&lt;p&gt;What happens however if the student being on-boarded is asked to work on a new feature or bugfix branch and nothing exists in the upstream yet?&lt;/p&gt;

&lt;p&gt;They create the new branch, perhaps with &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;git flow&lt;/a&gt;, and start working. After their first commit they decide to push their changes upstream. But unlike when we pull a branch git doesn't automatically create an upstream version of our branch in the same way that it does with a local one if pulling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iOYPa3fN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u0yacqd0oisxnodygl52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iOYPa3fN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/u0yacqd0oisxnodygl52.png" alt="No upstream set" width="591" height="495"&gt;&lt;/a&gt;&lt;/p&gt;
No upstream set



&lt;p&gt;When asked about this behaviour my response was the following:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Just copy that last command in the terminal with the set-upstream bit and it will do it for you.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While that is true and it does work it doesn't really answer the question and that bothered me, so why does that happen?&lt;/p&gt;




&lt;h2&gt;
  
  
  The Git Push Spec
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;push.default: Defines the action git push should take if no refspec is explicitly given. Different values are well-suited for specific workflows; for instance, in a purely central workflow (i.e. the fetch source is equal to the push destination), upstream is probably what you want. Possible values are:&lt;br&gt;
&lt;strong&gt;nothing&lt;/strong&gt; - do not push anything (error out) unless a refspec is explicitly given. This is primarily meant for people who want to avoid mistakes by always being explicit.&lt;br&gt;
&lt;strong&gt;current&lt;/strong&gt; - push the current branch to update a branch with the same name on the receiving end. Works in both central and non-central workflows.&lt;br&gt;
&lt;strong&gt;upstream&lt;/strong&gt; - push the current branch back to the branch whose changes are usually integrated into the current branch (which is called @{upstream}). This mode only makes sense if you are pushing to the same repository you would normally pull from (i.e. central workflow).&lt;br&gt;
&lt;strong&gt;simple&lt;/strong&gt; - in centralized workflow, work like upstream with an added safety to refuse to push if the upstream branch's name is different from the local one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As this branch is new and no refspec has been given the default git implementation (which is simple) says that for added safety we refuse to push up the branch without an upstream. It allows beginners to make sure they truly understand what they are doing before they make their change. That's nice and all but after a long time with git it feels inefficient so how can we change this to be useful and what are the caveats?&lt;/p&gt;




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

&lt;p&gt;As usual the actual solution here depends very much on your work flow and how you like to use git. I propose a few of the following after testing how they work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Change push.default
&lt;/h3&gt;

&lt;p&gt;The simplest method here is to change the &lt;strong&gt;push.default&lt;/strong&gt; config parameter to something other than simple. Both &lt;strong&gt;current&lt;/strong&gt; and &lt;strong&gt;upstream&lt;/strong&gt; work but there are a few gotchas to each.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git config push.default current&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When using the above command git will happily create / update a branch upstream for us that matches the name of our current local branch. In cases where you do trunk based development, or your developers largely work on their own branches (like we do with git flow) then this is almost universally going to be a great choice.&lt;/p&gt;

&lt;p&gt;What happens if we routinely rename our branches though? I work with Jakob, and while Jakob is a good guy (for the sake of this post) he creates terrible branch names. For example imagine the branch name below:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;feature/scott-is-the-worst&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As this branch is is an outright lie, when I work on this locally I want it to read something else. So on checking it out I set up tracking and change it's name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout -t -b feature/scott-is-the-best origin/feature/scott-is-the-worst&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now my branch is appropriately named I can work on it and finish whatever needs to be done. With my &lt;strong&gt;push.default&lt;/strong&gt; set to &lt;strong&gt;current&lt;/strong&gt; what happens when I push now? Git creates a new upstream branch notifying everyone that I am awesome, but leaves poor Jakob's branch telling everyone I am the worst to be stale. In this case I think he has every right to call me the worst, messing up our nice branching strategy.&lt;/p&gt;

&lt;p&gt;Perhaps I could fix this with &lt;strong&gt;push.default&lt;/strong&gt; set to &lt;strong&gt;upstream&lt;/strong&gt; instead?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git config push.default upstream&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If we replay the same steps above (for brevity I won't repeat them, expect for the Jakob being mean bit) then we expect I have a renamed branch on my local machine with changes ready to push upstream. What happens now? As the name might suggest we update Jakob's poorly named branch with my changes despite the naming being different. This happens because when we checked out the branch locally and changed it's name git set up tracking of the upstream so it knows which branch it needs to update. Nice!&lt;/p&gt;

&lt;p&gt;Now I am done fixing Jakob's branch I need to do some new work. I go and create a new branch of my own to work on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git flow feature start jakob-is-mostly-alright&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I commit all my changes and want to push this upstream. So I do a push only to find that git doesn't know what to do. Like with &lt;strong&gt;push.default&lt;/strong&gt; set to &lt;strong&gt;simple&lt;/strong&gt;, upstream has no tracking set up between this local branch and our origin so it doesn't push up the code and asks me what I want to do.&lt;/p&gt;

&lt;h3&gt;
  
  
  Git Aliases
&lt;/h3&gt;

&lt;p&gt;Depending on how you want to work you might find that keeping &lt;strong&gt;push.default&lt;/strong&gt; set to simple or upstream provides the safest method for making sure the correct branch always receives the correct updates.&lt;/p&gt;

&lt;p&gt;That's totally reasonable but it still doesn't help us with the initial push. Thankfully we can create git aliases which provides short hand on the command line to run multiple or verbose git commands. I tend to use a version floating around the internet called &lt;strong&gt;pushup&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git config alias.pushup \!"git push --set-upstream origin 'git symbolic-ref --short HEAD'"&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What Should I Do?
&lt;/h3&gt;

&lt;p&gt;My current work flow is to use &lt;strong&gt;push.default current&lt;/strong&gt; because it suits my use case. If you're nervous about changing the defaults you could try &lt;strong&gt;push.default upstream&lt;/strong&gt; with the alias set up for some quality of life on the command line. What's great about the latter is you'll always know whether your branch is upstream or not because it will cause an error the first time. If you're nervous about sending your code upstream until it's not embarrassing this might be a good method to double check that.&lt;/p&gt;




&lt;h2&gt;
  
  
  A Word on Git Aliases
&lt;/h2&gt;

&lt;p&gt;In almost every online tutorial for git the writer will append the &lt;code&gt;--global&lt;/code&gt; flag to their git config commands. As this might indicate the &lt;code&gt;--global&lt;/code&gt; flag changes your configuration for &lt;strong&gt;all&lt;/strong&gt; the git repositories on your machine. While that's great shorthand I like to configure each repository manually each time. It means I don't accidentally inherit a setting (like &lt;strong&gt;push.default current&lt;/strong&gt;) which might cause issues on a new project I am part of.&lt;/p&gt;

&lt;p&gt;The default git settings are extremely conservative so always be aware of overriding them at the global level. With that being said some things (like aliases) can be super handy in your global config.&lt;/p&gt;




&lt;p&gt;Enjoy the power of typing less with aliases or a push configuration that better matches your workflow!&lt;/p&gt;

</description>
      <category>git</category>
      <category>devops</category>
    </item>
    <item>
      <title>Serving a SPA with Express Server Router</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Mon, 16 Nov 2020 05:42:36 +0000</pubDate>
      <link>https://dev.to/iamscottcab/serving-a-spa-with-express-server-router-552n</link>
      <guid>https://dev.to/iamscottcab/serving-a-spa-with-express-server-router-552n</guid>
      <description>&lt;p&gt;For the longest time, largely because of the size and tech stacks of projects that I have worked on, I've treated the client and server of an application as strictly disparate entities. The client is it's own self contained application that often lives on a different host with it's own configuration, code repository and CI/CD pipelines. In a PaaS environment (like Azure) I think this pattern makes sense because spinning up and down new instances is easy and doesn't come with the same maintenance as perhaps IaaS where your containers and operating systems need to be maintained, patched and updated yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the side project
&lt;/h2&gt;

&lt;p&gt;I recently started working on a personal link service, like bit.ly or similar that allows me to better manage my links on social media. Mostly to allow me to retro-actively fix stale links or provide a more consistent link experience. I know there are plenty of open source variants that do this but I wanted to use the opportunity to roll my own. Mostly for fun, partly to learn.&lt;/p&gt;

&lt;p&gt;As with all side projects I want this to be cheap when I deploy it, vanity domains and hosting add up really quickly when you don't monetize any of your work. It got me thinking. I already host my blog, I'm about to run another node server and it also needs some sort of admin panel so that I can enter and edit links. Perhaps I can consolidate all of these onto the one server, save costs and learn a little bit about hosting files in node.&lt;/p&gt;

&lt;p&gt;You might have other motivations for serving a Single Page Application (SPA) from your Express Server though.&lt;/p&gt;

&lt;p&gt;You might need to deploy to a more traditional server that requires patching and maintenance and you really want to minimize the amount of infrastructure that requires that level of up-keep. &lt;em&gt;(I'm not going to lie, this is another motivation for me).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Alternatively you might want your spa to live at &lt;code&gt;your-domain.tld/app&lt;/code&gt; rather than &lt;code&gt;app.your-domain.tld&lt;/code&gt;. The former is trivial to do if it's being served by your API which we will step through now.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Anatomy of a Basic Express Application
&lt;/h2&gt;

&lt;p&gt;One of the reasons that I chose node (and Express) to run my API was how simple it is to get a web server up and running. &lt;em&gt;(I also think I really like JavaScript now, but don't go telling my colleagues that, I have a reputation to uphold&lt;/em&gt; 🤐 &lt;em&gt;)&lt;/em&gt;&lt;/p&gt;

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



&lt;p&gt;Here is a really simple Express Server, you can send a get request to the &lt;code&gt;/ping&lt;/code&gt; endpoint and be returned the &lt;code&gt;pong&lt;/code&gt; message to know the server is alive.&lt;/p&gt;

&lt;p&gt;I even have an extremely flat folder structure for this demo as you can see below.&lt;/p&gt;

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

&lt;p&gt;I'm going to assume some prior knowledge for node and Express here to keep this post short. In general though Express applications are built by a series of middlewares which execute against your request &lt;strong&gt;in order&lt;/strong&gt; &lt;em&gt;(and that order matters)&lt;/em&gt;. The same is true for evaluating which endpoint actually receives the request, it matches the first route that satisfies the request even if a more specific one is defined later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Middlewares
&lt;/h2&gt;

&lt;p&gt;The natural consequence of maintaining middleware order could be to continue to add all your routes to your main Express Server file (normally &lt;code&gt;index.js&lt;/code&gt;) to try and preserve the order you want them evaluated in. That gets messy though so where possible you want to compose your major routes with the Express router. For example let's say that we want to add some "admin" routes for my new admin portal. I could do the following and tell my app to use a different file to manage any routes that start with &lt;code&gt;/admin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2fq62f24m367hup3fi5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2fq62f24m367hup3fi5l.png" alt="Telling Express to use another file to manage admin requests"&gt;&lt;/a&gt;&lt;/p&gt;
Telling Express to use another file to manage admin requests



&lt;p&gt;Now I can separate my code out into logical units with more ease and also add and remove arbitrary admin routes without constantly having to go and refactor my main file that is largely just configuring the application. But how might we define a router in a new file and specify some routes?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjyj8wl64mssibt3vzgqi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fjyj8wl64mssibt3vzgqi.png" alt="A router definition for an Express application."&gt;&lt;/a&gt;&lt;/p&gt;
A router definition for an Express application.



&lt;p&gt;Hopefully the code here is fairly self documenting. We create a new Express Router. We create a new route definition and then handle the request like we were in our &lt;code&gt;index.js&lt;/code&gt; file, except instead of appending the &lt;code&gt;get&lt;/code&gt; operation on the app itself we append it to the router. Because we want to serve a SPA, and one of the defining features of a SPA is that it handles it's own routing, we want to create a rule that matches any sub-route of &lt;code&gt;/admin&lt;/code&gt; and just return the index page of the SPA itself. In scenarios where the SPA is hosted by itself this would happen in your reverse proxy or your web server configuration, but now we can easily do it in from within Express itself. You notice that I am serving an &lt;code&gt;index.html&lt;/code&gt; file from a folder called &lt;code&gt;admin-client&lt;/code&gt; that should be in the current working directory of the application (typically the project root).&lt;/p&gt;

&lt;p&gt;You will note that I don't have to prepend my routes with &lt;code&gt;/admin&lt;/code&gt; in the controller because we specified where to attach the router in our &lt;code&gt;index.js&lt;/code&gt; file. If we decide in a week that we prefer for the SPA to live at &lt;code&gt;/app&lt;/code&gt; instead of &lt;code&gt;/admin&lt;/code&gt; we can simply change the one line in our &lt;code&gt;index.js&lt;/code&gt; file and the routes all work again, yet another reason to pick up the Express Router in your projects.&lt;/p&gt;

&lt;p&gt;Assuming you have built your SPA and dropped it into the &lt;code&gt;admin-client&lt;/code&gt; folder you should notice that running your application and hitting &lt;code&gt;http://localhost:3000/admin&lt;/code&gt; in your browser nothing renders and you get lots of errors in the browser console. We're still missing one step, now any time we try to request any file at all (remember the &lt;code&gt;*&lt;/code&gt;) we are returning our &lt;code&gt;index.html&lt;/code&gt; page. Want your css stylesheet? Have our &lt;code&gt;index.html&lt;/code&gt;! What about a favicon? You guessed it more &lt;code&gt;index.html&lt;/code&gt;. While we have set up routing to deal with serving our pages we haven't added anything to serve our static content and Express provides that functionality out of the box as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpl9msopzbmcgf8pe3o2y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpl9msopzbmcgf8pe3o2y.png" alt="Adding static file serving to an Express route."&gt;&lt;/a&gt;&lt;/p&gt;
Adding static file serving to an Express route.



&lt;p&gt;Above our router definition we add another middleware definition, on the same route but instead using the &lt;code&gt;express.static&lt;/code&gt; middleware. You might be able to guess what this is doing. When a request for a resource to &lt;code&gt;/admin&lt;/code&gt; is made it first runs through the &lt;code&gt;express.static&lt;/code&gt; middleware and attempts to find a file in the &lt;code&gt;admin-client&lt;/code&gt; folder that matches the request file. If one is found it returns it, if one is not is falls through to our admin controller. Restarting your Express Server and refreshing your browser you should now see your SPA being rendered correctly.&lt;/p&gt;

&lt;p&gt;To illustrate exactly how middleware operates if you were to swap the &lt;code&gt;express.static&lt;/code&gt; and router implementations around you would end up with the same issue as when we hadn't specified the &lt;code&gt;express.static&lt;/code&gt; middleware at all. All requests to &lt;code&gt;/admin/*&lt;/code&gt; would get caught up by our router middleware and always returns &lt;code&gt;index.html&lt;/code&gt; which is why we declared it the way we did above.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Thoughts
&lt;/h2&gt;

&lt;p&gt;For an API first solution, or one where you want to save on costs this could be a really great solution. You would have to worry about issues of scalability long term (as opposed to say serving your content via a CDN), and the Express documentation says that production workloads should live behind a reverse proxy. Mostly so that the proxy can do things like handle caching of the &lt;code&gt;index.html&lt;/code&gt; file and generally do what reverse proxies are good at doing (and Express is not).&lt;/p&gt;

&lt;p&gt;One thing I have not done yet (as the project isn't quite as polished as I would like) is determine the best way to actually build and deploy this solution. When I started my repositories were separate, because I was treating the client and server separately. In reality because I need to build my SPA, drop it into my Express Server and then publish that perhaps I should be looking at a Monorepo set up or some other way to streamline the process.&lt;/p&gt;

&lt;p&gt;I also think given I need to consolidate my blog into this server as well that there may be some containerization coming my way. Stay tuned as the service rolls out and I can offer more learnings from this experience.&lt;/p&gt;

</description>
      <category>node</category>
      <category>angular</category>
      <category>react</category>
    </item>
    <item>
      <title>Using Hot Module Replacement in Angular 11</title>
      <dc:creator>Scott</dc:creator>
      <pubDate>Fri, 13 Nov 2020 06:21:50 +0000</pubDate>
      <link>https://dev.to/iamscottcab/using-hot-module-replacement-in-angular-11-mji</link>
      <guid>https://dev.to/iamscottcab/using-hot-module-replacement-in-angular-11-mji</guid>
      <description>&lt;p&gt;Angular 11 was released today and with it comes a large number of performance upgrades, bugfixes (including the third most popular issue) and improved logging.&lt;/p&gt;

&lt;p&gt;Not only was the upgrade from Angular V10 to V11 painless but I wanted to share the new Hot Module Replacement feature. This has been exposed on the CLI if you hadn't tried it in previous versions, so now is a great time to dive in and give it a go.&lt;/p&gt;

&lt;p&gt;For those unaware this feature is not native to Angular, rather webpack. If you'd like to read more about it you can find their documentation &lt;a href="https://webpack.js.org/concepts/hot-module-replacement/"&gt;here&lt;/a&gt;. In short you can think of Hot Module Replacement as a more advanced version of a file watcher, only replacing the modules that need replacement and (where possible) preserving state. So what does this look like in action? See the videos below (which are best viewed full screen).&lt;/p&gt;

&lt;h1&gt;
  
  
  Classic Angular Reloading
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2o4ADC26j0Y"&gt;
&lt;/iframe&gt;
&lt;br&gt;
The above should look very common for front end developers. We are testing out our model binding in our form. We decide that it's working well but we want to change the label on our input. Doing so forces a refresh of the page and we lose our state.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hot Module Replacement in Angular
&lt;/h1&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CMdNSYlEpZ0"&gt;
&lt;/iframe&gt;
&lt;br&gt;
With the Hot Module replacement flag used we see a slightly different story. The initial flow is the same. We test our model binding and again want to change the label on the input. This time the Hot Module Replacement preserves our state and our input still has our user generated value. Nice!&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding Hot Module Replacement &amp;amp; Use Cases
&lt;/h1&gt;

&lt;p&gt;In my current project I've nominated that we additively pick up this new feature. For most uses cases the standard watcher works just fine so retooling for a slightly better development experience for some might hurt others in the team. I propose you add a new script to your &lt;code&gt;package.json&lt;/code&gt; while you're adopting this to see if it suits your needs. Perhaps something like &lt;code&gt;"serve:hmr": "ng serve --hmr"&lt;/code&gt;. Then your team can either run &lt;code&gt;npm start&lt;/code&gt; for their normal experience or &lt;code&gt;npm run serve:hmr&lt;/code&gt;. This gives you the best of both options and allows you to pick and choose which reload strategy based on the functionality you are building out.&lt;/p&gt;

&lt;p&gt;Consider using Hot Module Replacement when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a complex flow that you do not want to restart.&lt;/li&gt;
&lt;li&gt;You are making cosmetic changes and want to test on non-standard input (such as long strings).&lt;/li&gt;
&lt;li&gt;You are fixing / tweaking API calls and want to reuse the same form values.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What else do you like about the Angular 11 update? Let me know on Twitter or check out my content on my site.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>webpack</category>
    </item>
  </channel>
</rss>
