<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Michael Timbs</title>
    <description>The latest articles on Forem by Michael Timbs (@michael_timbs).</description>
    <link>https://forem.com/michael_timbs</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%2F347683%2Fdee6614e-8886-4676-a0ff-d0b6f34bf6e5.JPG</url>
      <title>Forem: Michael Timbs</title>
      <link>https://forem.com/michael_timbs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/michael_timbs"/>
    <language>en</language>
    <item>
      <title>Creating a serverless-deploy user with AWS IAM</title>
      <dc:creator>Michael Timbs</dc:creator>
      <pubDate>Sun, 08 Mar 2020 14:38:19 +0000</pubDate>
      <link>https://forem.com/michael_timbs/creating-a-serverless-deploy-user-with-aws-iam-43d8</link>
      <guid>https://forem.com/michael_timbs/creating-a-serverless-deploy-user-with-aws-iam-43d8</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4H8dTnhQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2400/1%2AvFDlvvnRY0TW3Cc3CpHzSw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4H8dTnhQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2400/1%2AvFDlvvnRY0TW3Cc3CpHzSw.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are building a project with AWS serverless using SAM or &lt;a href="https://serverless.com/"&gt;serverless framework &lt;/a&gt;, you’ll need to be regularly deploying your code from your local machine and CI/CD pipelines. Both of these frameworks use AWS &lt;a href="https://aws.amazon.com/cloudformation/"&gt;CloudFormation&lt;/a&gt; under the hood to provision and deploy resource stacks. In order for these frameworks to provision your infrastructure for you, you will need to give them permission to do so.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This article assumes you already have the AWS CLI installed and configured. You will need to set that up first. Instructions can be found &lt;a href="https://aws.amazon.com/cli/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Firstly log into your AWS console and navigate to Identity and Access Management (IAM). Go to &lt;em&gt;Users *and the create new user. Name it something that is easy to identify like *serverless-deploy&lt;/em&gt;. Ensure &lt;em&gt;programmatic access&lt;/em&gt; is enabled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--14KDsqms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5788/1%2A0FqnbH2RHjEQtAswEvInmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--14KDsqms--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5788/1%2A0FqnbH2RHjEQtAswEvInmw.png" alt="AWS Console — Create User"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Create User&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click through next, &lt;strong&gt;giving it no permissions&lt;/strong&gt;, if required add some tags, otherwise click next. Download the user credentials (don’t lose these, you can’t recover them again) and then let’s add them to our local CLI.&lt;/p&gt;

&lt;p&gt;AWS credentials are typically stored in ~/.aws on your local machine if you have configured the AWS CLI.&lt;/p&gt;

&lt;p&gt;We’re going to add the following snippets to the config and credentials files in the .aws directory. See below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;~/.aws/config
&lt;span class="o"&gt;[&lt;/span&gt;profile serverless-deploy]
&lt;span class="nv"&gt;region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-region&amp;gt;
&lt;span class="nv"&gt;output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json

~/.aws/credentials

&lt;span class="o"&gt;[&lt;/span&gt;serverless-deploy]
aws_access_key_id &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;access-key-here&amp;gt;
aws_secret_access_key &lt;span class="o"&gt;=&lt;/span&gt; &amp;lt;secret-key-here&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;*&lt;em&gt;Note: *&lt;/em&gt;&lt;em&gt;You can name your profile whatever you want and substitute “serverless-deploy” with whatever you want to call it.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We should now be able to deploy a serverless project locally from our machine. Below is an example of what you would do if you were using serverless framework.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sls deploy --stage dev --aws-profile serverless-deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At this point you should get an error. Most likely&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- not authorized to perform: cloudformation:DescribeStacks
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now need to go and give this IAM user permission to create resources for us and spin up infrastructure based on our CloudFormation templates. Back in our AWS console we will need to create an IAM group *serverless-deploy *(or whatever you want to call it). We won’t any policies to it here but will create those separately.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sW9OWMJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6104/1%2Aur7JM0pO2bcwyNVftXfIqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sW9OWMJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6104/1%2Aur7JM0pO2bcwyNVftXfIqw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will now create a new IAM policy to attach to this group.&lt;/p&gt;

&lt;p&gt;In this policy we will add a policy for the &lt;em&gt;CloudFormation *service and then allow the Actions *List:DescribeStacks. *Indicate that this permission applies to all resources and then click *Review Policy.&lt;/em&gt; You’ll be prompted to give this policy a name, again something like &lt;em&gt;serverless-deploy&lt;/em&gt; is fine. Give it a description if you like and then click Create Policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5XY1HJ6c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5280/1%2AWgW8wNgW7Yzg1BTgVTHoKg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5XY1HJ6c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5280/1%2AWgW8wNgW7Yzg1BTgVTHoKg.png" alt="AWS IAM Console adding CloudFormation:DescribeStack permission to our user"&gt;&lt;/a&gt;&lt;em&gt;AWS IAM Console adding CloudFormation:DescribeStack permission to our user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note: **You can either create a universal *serverless-deploy&lt;/em&gt; user for all services/projects, or create a specific one for each project. If you want to create a specific one for each project you can limit the resources you give this user permission to.&lt;/p&gt;

&lt;p&gt;Now that we have created the policy, we need to attach it to the group we created before. Go back to groups, find the group we created before and click on Attach Policy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A_ZRWPUI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6244/1%2AXekYC2kyEZLn72JMNM3TGA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A_ZRWPUI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6244/1%2AXekYC2kyEZLn72JMNM3TGA.png" alt="AWS Console — Attach Policy"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Attach Policy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Search for the newly created policy and attach it to the group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6copj2lD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6120/1%2Aq7r-PAyVfRk3ujVwblvVAQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6copj2lD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6120/1%2Aq7r-PAyVfRk3ujVwblvVAQ.png" alt="AWS Console — Attach Policy"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Attach Policy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Our serverless-deploy group now has a policy attached. We should now put our IAM user into this group so that it inherits it’s policies. We need to go back to our Users tab and then click on our user. Navigate to the &lt;em&gt;Groups&lt;/em&gt; tab on the user info screen and attach a group.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UYWAn4Kg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6092/1%2AabrBc24WfYXmz8ONfpncCQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UYWAn4Kg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6092/1%2AabrBc24WfYXmz8ONfpncCQ.png" alt="AWS Console — IAM Users"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — IAM Users&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now we can add the serverless-deploy group to the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJGvEsdp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6060/1%2A7QsdgPl_pP3OGw7jYPDHOA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZJGvEsdp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6060/1%2A7QsdgPl_pP3OGw7jYPDHOA.png" alt="AWS Console — IAM User Add user to groups"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — IAM User Add user to groups&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;With these changes we can try deploying our app again and see what happens.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sls deploy --stage dev --aws-profile serverless-deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We should get another error, although this time the error will be different.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;user/serverless-deploy is not authorized to perform: 

cloudformation:CreateStack on resource
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is progress, which indicates that the work we just did at least changed something and appears to have worked. In the AWS console, go back to *Policies *and search for the serverless-deploy policy we created earlier.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8vhot2bG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5144/1%2AOZHNLQRcRKtNcBlRho_skw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8vhot2bG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/5144/1%2AOZHNLQRcRKtNcBlRho_skw.png" alt="AWS Console - Policy Summary"&gt;&lt;/a&gt;&lt;em&gt;AWS Console - Policy Summary&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Click edit policy and add the &lt;em&gt;CreateStack&lt;/em&gt; permission in the CloudFormation service. Review and save.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6L-aETIu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4936/1%2AwdWFVHr1rXHx1LfHqzEzPQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6L-aETIu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4936/1%2AwdWFVHr1rXHx1LfHqzEzPQ.png" alt="AWS Console — IAM policies"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — IAM policies&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Rinse and repeat this process of deploying and then adding each policy incrementally.&lt;/em&gt;&lt;/strong&gt; This is the best way to ensure you have the minimum possible permissions and avoid security risks of giving your IAM users too much access.&lt;/p&gt;

&lt;p&gt;**Hint: **Sometimes the console output isn’t great so you can look at the CloudFront events log in the AWS console to get the errors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XEMi78-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6088/1%2AtoB5lIhAnspxPOkZnYapoQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XEMi78-y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/6088/1%2AtoB5lIhAnspxPOkZnYapoQ.png" alt="AWS Console — CloudFormation events"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — CloudFormation events&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;*&lt;em&gt;Note: *&lt;/em&gt;&lt;em&gt;If you keep going with this process you may have to manually delete some resources and the CloudFormation stack as you’ll hit an error, the stack will try to rollback but then not have permission to roll back.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once you successfully get a deploy working I recommend creating an IAM.json in your project and copying across the final policy to your project and committing it to the repo. This will enable you to quickly duplicate this stack between staging/production accounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HINT:&lt;/strong&gt; It is often best to go through this iterative process in a development account. Then once you have the final permissions, copy them across into your production account so that your deploys don’t fail and have unintended consequences. You can read about multiple accounts &lt;a href="https://medium.com/@Michael_Timbs/switching-between-multiple-aws-accounts-4d048fd076cb"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the base template of a new serverless project (like the one &lt;a href="https://medium.com/@Michael_Timbs/getting-started-with-aws-serverless-typescript-8c172ccfec41"&gt;here&lt;/a&gt;) the basic permissions should be as follows. Feel free to verify these permissions and copy them straight into your IAM policy if you are happy with them.&lt;/p&gt;


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



</description>
      <category>serverless</category>
      <category>aws</category>
      <category>iam</category>
    </item>
    <item>
      <title>Get Started With AWS, Serverless, and TypeScript</title>
      <dc:creator>Michael Timbs</dc:creator>
      <pubDate>Sun, 08 Mar 2020 14:07:03 +0000</pubDate>
      <link>https://forem.com/michael_timbs/get-started-with-aws-serverless-and-typescript-5hgf</link>
      <guid>https://forem.com/michael_timbs/get-started-with-aws-serverless-and-typescript-5hgf</guid>
      <description>&lt;p&gt;About five months ago, I got thrown head first into the world of serverless when I joined the team at &lt;a href="http://fleet.space"&gt;fleet.space&lt;/a&gt; to build cloud infrastructure to support their nano-satellite constellation and industrial IoT network.&lt;/p&gt;

&lt;p&gt;I really struggled to find a comprehensive guide on how to build new services with TypeScript, so here I am writing the one I wish I had. We won’t go through any example code — we’ll just focus on building up a robust base template you can reuse for all your services.&lt;/p&gt;

&lt;p&gt;The first thing we’re going to do is install the &lt;a href="https://serverless.com/framework/docs/"&gt;Serverless Framework&lt;/a&gt;. I find it has better support than the official AWS SAM templates.&lt;/p&gt;

&lt;p&gt;First, lets install Serverless as a global dependency on our system via npm i -g serverless. Next, we’ll create a project, mkdir typescript-serverless. Inside that directory, let’s scaffold out a new Serverless template with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sls create &lt;span class="nt"&gt;--template&lt;/span&gt; aws-nodejs-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This will generate a bare-bones template with TypeScript, but it’s missing a lot of powerful configuration I use over and over again. So let’s set some of these things up. If you don’t use VS Code, go ahead and delete the pesky VS Code directory this template initialises, and then run npm i to install the base dependencies of the Serverless Framework.&lt;/p&gt;
&lt;h2&gt;
  
  
  Serverless Plugins
&lt;/h2&gt;

&lt;p&gt;The Serverless Framework has one advantage over SAM in that there are many community plugins built around it to help you do things (and you can build your own, if needed). It’s very extensible. Plugins I use in almost every service are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/functionalone/serverless-iam-roles-per-function#readme"&gt;serverless-iam-roles-per-function&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This plugin allows you to define IAM permissions at a function level instead of the default project level. If only one function needs to touch DynamoDB then we don't need to give them all access.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/rrahul963/serverless-create-global-dynamodb-table"&gt;serverless-create-global-dynamodb-table&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multi-region deploys are essentially free in the serverless world (compared to containers/ec2 anyway). The only complexity is keeping DynamoDB in sync. This can be done with a global table.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/dherault/serverless-offline"&gt;serverless-offline&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This one I don't always use these days but it's only a dev dependency and handy to have. It will let you invoke your lambda API locally.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/claygregory/serverless-prune-plugin"&gt;serverless-prune-plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a sneaky risk with serverless, especially if you deploy frequently. Lambda will version each function you deploy and there is a hard storage limit to how many you can store. This plugin will prune old versions that aren't needed and prevent that subtle error hitting your production environment.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; serverless-iam-roles-per-function serverless-create-global-dynamodb-table serverless-offline serverless-prune-plugin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We’ll also add &lt;a href="https://github.com/aws/aws-sdk-js"&gt;aws-sdk&lt;/a&gt; and &lt;a href="https://github.com/awspilot/cli-lambda-deploy"&gt;aws-lambda&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i aws-sdk aws-lambda.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Lambda Powertools
&lt;/h3&gt;

&lt;p&gt;One thing I really struggled with when I stepped into the world of serverless was observability and traceability. Debugging across service boundaries and even infrastructure within boundaries (Lambda &amp;gt; SQS &amp;gt; Lambda &amp;gt; Kinesis &amp;gt; Lambda &amp;gt; DynamoDB, etc.) was a pain. Thankfully I came across a great set of &lt;a href="https://github.com/getndazn/dazn-lambda-powertools"&gt;powertools&lt;/a&gt; for Lambda that are a must-have in any service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-cloudwatchevents-client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-correlation-ids&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-logger&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-pattern-basic&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-lambda-client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-sns-client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-sqs-client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-dynamodb-client&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@dazn/lambda-powertools-kinesis-client&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I just import all of these and let webpack tree shaking worry about getting rid of what I’m not using.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i @dazn/lambda-powertools-cloudwatchevents-client @dazn/lambda-powertools-correlation-ids @dazn/lambda-powertools-logger @dazn/lambda-powertools-pattern-basic @dazn/lambda-powertools-lambda-client @dazn/lambda-powertools-sns-client @dazn/lambda-powertools-sqs-client @dazn/lambda-powertools-dynamodb-client @dazn/lambda-powertools-kinesis-client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Linting
&lt;/h2&gt;

&lt;p&gt;The next important thing I can’t live without in a codebase is linting. ESLint is one of the biggest crutches I use everyday. Let’s configure it to work with TypeScript and the Serverless Framework. We’ll need the following dev dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/eslint/eslint"&gt;eslint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/airbnb/javascript"&gt;eslint-config-airbnb-base&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/typescript-eslint/typescript-eslint"&gt;typescript-eslint&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/benmosher/eslint-plugin-import"&gt;eslint-plugin-import&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/typescript-eslint/typescript-eslint"&gt;@typescript-eslint/eslint-plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/typescript-eslint/typescript-eslint"&gt;@typescript/eslint-parser&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/johvin/eslint-import-resolver-alias"&gt;eslint-import-resolver-alias&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/HeroProtagonist/eslint-plugin-module-resolver"&gt;eslint-plugin-module-resolver&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; eslint eslint-config-airbnb-base typescript-eslint eslint-plugin-import eslint-import-resolver-alias eslint-plugin-module-resolver @typescript-eslint/eslint-plugin @typescript-eslint/parser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now, we need to create an .eslintrc.json config file to define our rules. I like the following rules. This gist also includes some alias mapping for some module aliases we’ll set up at the end and some Jest config we’ll set up in a second.&lt;/p&gt;


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



&lt;p&gt;I’ll also tweak my tsconfig file to add inlineSource, esModuleInterop, sourceRoot, and baseUrl. The following gist also pre-populates some module aliasing information we’ll set up later. You can comment out anything in paths for now, if you want.&lt;/p&gt;


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


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

&lt;p&gt;I’ll write tests for every service so it makes sense to configure a test runner in our base template. I personally like &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt;, so we’ll set that up.&lt;/p&gt;

&lt;p&gt;Once again, we’ll need to fill the the black hole of our node_modules with some npm dev dependencies.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;jest&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;babel-jest&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/core&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/preset-env&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/babel"&gt;@babel&lt;/a&gt;
/preset-typescript&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; jest babel-jest @babel/core @babel/preset-env @babel/preset-typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Make sure that Jest is configured as a plugin in your .eslintrc.json and that you set jest/globals under env (if you copied the gist above, you’ll have this in there already).&lt;/p&gt;

&lt;p&gt;We need to create a Babel .config for Jest to work.&lt;/p&gt;


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



&lt;p&gt;At this point, we should check to see if Jest is working and if it’s configured correctly. Lets create a tests directory and add an example test. Create a test file, and let’s add a dummy test, tests/example.test.ts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;who tests the tests?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;can run a test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasAssertions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re using WebStorm, you can hit Ctrl+Shift+R to run this test straight from your IDE. Otherwise, let’s go update our package.json to add a test script (and a lint and TS compile check while we’re there).&lt;/p&gt;

&lt;p&gt;In your package.json file, update the scripts section to include the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NODE_ENV=test ./node_modules/.bin/jest --ci --verbose"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eslint . --ext .js,.jsx,.ts,.tsx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"buildtest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc --noEmit"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I generally run all of these in CI/CD pipelines to prevent bad code from hitting production. Now, you can run npm run test from your console to run the test suite. Hopefully, your test suite runs and passes. Ideally, your IDE won’t be throwing linting errors at you in your example.test.ts file either.&lt;/p&gt;

&lt;p&gt;While we’re here, run npm run lint, and let’s see if there are any linting errors with the default template. You’ll likely get some errors with webpack.config and the handler.ts file that was autoscaffolded. Let’s clear these up.&lt;/p&gt;

&lt;p&gt;At the top of your webpack.config file, add &lt;code&gt;*/* eslint-disable @typescript-eslint/no-var-requires */*&lt;/code&gt; and uncomment out the Fork TS Checker Webpack Plugin defaults that came with the template. That should solve that file.&lt;/p&gt;

&lt;p&gt;For the handler.ts file, just go remove the unused context-function signature from the hello function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code goes in /src
&lt;/h2&gt;

&lt;p&gt;One convention I like is putting all our domain logic inside a /src directory and leaving the root for the config (and /tests). Create a /src directory, and move the handler.ts file inside of the /src directory.&lt;/p&gt;

&lt;p&gt;If you decide to adopt this convention, you’ll need to go to serverless.yml and update the path for the handler to src/handler.hello.&lt;/p&gt;

&lt;p&gt;Let’s configure our Serverless plugin while we’re in the serverless.yml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;    service:
      name: typescript-serverless&lt;span class="sb"&gt;

    ...

    plugins:
      - serverless-offline
      - serverless-webpack
      - serverless-iam-roles-per-function
      - serverless-create-global-dynamodb-table
      - serverless-prune-plugin

    ...

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

&lt;/div&gt;



&lt;p&gt;At this point, you should be able to run sls offline in your terminal and have a clean compile and build launching a Serverless offline endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;    ➜  typescript-serverless git:&lt;span class="o"&gt;(&lt;/span&gt;master&lt;span class="o"&gt;)&lt;/span&gt; ✗ sls offline
    Serverless: Bundling with Webpack...
    Time: 398ms
    Built at: 27/02/2020 11:24:42 pm
      Asset      Size       Chunks             Chunk Names
      src/handler.js  6.33 KiB  src/handler  &lt;span class="o"&gt;[&lt;/span&gt;emitted]  src/handler
      Entrypoint src/handler &lt;span class="o"&gt;=&lt;/span&gt; src/handler.js
      &lt;span class="o"&gt;[&lt;/span&gt;./src/handler.ts] 316 bytes &lt;span class="o"&gt;{&lt;/span&gt;src/handler&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;built]
      &lt;span class="o"&gt;[&lt;/span&gt;source-map-support/register] external &lt;span class="s2"&gt;"source-map-support/register"&lt;/span&gt; 42 bytes &lt;span class="o"&gt;{&lt;/span&gt;src/handler&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;built]
    Serverless: Watching &lt;span class="k"&gt;for &lt;/span&gt;changes...
    Serverless: Starting Offline: dev/us-east-1.

    Serverless: Routes &lt;span class="k"&gt;for &lt;/span&gt;hello:
    Serverless: GET /hello
    Serverless: POST /&lt;span class="o"&gt;{&lt;/span&gt;apiVersion&lt;span class="o"&gt;}&lt;/span&gt;/functions/typescript-serverless-dev-hello/invocations

    Serverless: Offline &lt;span class="o"&gt;[&lt;/span&gt;HTTP] listening on http://localhost:3000
    Serverless: Enter &lt;span class="s2"&gt;"rp"&lt;/span&gt; to replay the last request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, you see this. You should be able to visit localhost:3000 and see a list of available API endpoints. If you go to /hello, things should see a dump of the APIGatewayProxyEvent we return in src/handler.ts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;APIGatewayProxyHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aws-lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APIGatewayProxyHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Go Serverless Webpack (Typescript) v1.0! Your function executed successfully!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Serverless Config
&lt;/h2&gt;

&lt;p&gt;Now that we have a working API Gateway endpoint, let’s configure a few more options in the Serverless Framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Set up X-Ray tracing for functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set some default .env variables&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lock the version of Serverless&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set stage and region configs with defaults&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up global DynamoDB plugin&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set up automatic pruning for lambda versions (we'll retain the last 3 versions only)&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;
    service:
      name: typescript-serverless&lt;span class="sb"&gt;

    custom:
      webpack:
        webpackConfig: ./webpack.config.js
        includeModules: true
      serverless-iam-roles-per-function:
        defaultInherit: true *# Each function will inherit the service level roles too.
      globalTables:
        regions: # list of regions in which you want to set up global tables
          - us-east-2 # Ohio (default region to date for stack)
          - ap-southeast-2 # Sydney (lower latency for Australia)
        createStack: false
      prune: # automatically prune old lambda versions
        automatic: true
        number: 3

    plugins:
      - serverless-offline
      - serverless-webpack
      - serverless-iam-roles-per-function
      - serverless-create-global-dynamodb-table
      - serverless-prune-plugin

    provider:
      name: aws
      runtime: nodejs12.x
      frameworkVersion: ‘1.64.1’
      stage: ${opt:stage, 'local'}
      region: ${opt:region, 'us-east-2'}
      apiGateway:
        minimumCompressionSize: 1024 *# Enable gzip compression for responses &amp;gt; 1 KB
      environment:
        DEBUG: '*'
        NODE_ENV: ${self:provider.stage}
        AWS_NODEJS_CONNECTION_REUSE_ENABLED: 1
      tracing:
        lambda: true
      iamRoleStatements:
        - Effect: Allow
          Action:
            - xray:PutTraceSegments
            - xray:PutTelemetryRecords
          Resource: "*"

    functions:
      hello:
        handler: src/handler.hello
        events:
          - http:
              method: get
              path: hello

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

&lt;/div&gt;



&lt;p&gt;Under provider, we set a default stage and region and some global .env variables for the service. We also set up X-Ray tracing so we can easily debug our service once it’s deployed.&lt;/p&gt;

&lt;p&gt;We also locked our version of the Serverless Framework. I’ve not done this before and had deploy pipelines break when Serverless bumps up a version and breaks one of our plugins. At the time of writing, this the version is 1.64.1.&lt;/p&gt;

&lt;p&gt;Finally, we set the stage and region configs with some defaults of local and us-east-2. These are set as CLI arguments (optional) during deploy.&lt;/p&gt;

&lt;p&gt;Lastly, we configured some global IAM role statements for the service. (These are the only global roles we’ll set. Everything else we’ll set at a per-function level).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: You’ll want to comment out the global tables for your initial multi-region deploy. This plugin may not work as you expect. The reason this may fail a deploy is outlined &lt;a href="https://github.com/rrahul963/serverless-create-global-dynamodb-table/issues/17"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module Aliasing
&lt;/h2&gt;

&lt;p&gt;The last thing to configure is module aliasing. It really blows my mind people are building Node apps in 2020 without using module aliasing. Relative import paths are too fragile for me, so let’s set up some aliases.&lt;/p&gt;

&lt;p&gt;We are going to set three defaults (src, test, and queries) just so someone can come in and know how to set them up in the future. We’ll also use an import from queries in our example handler to make sure TypeScript compiles and resolves correctly.&lt;/p&gt;

&lt;p&gt;Now this is a bit messy, but let’s go set this up. It’s worth the effort.&lt;/p&gt;

&lt;p&gt;First, let webpack know about module aliases and updating the resolve object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.mjs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="nx"&gt;symlinks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;cacheWithContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@queries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./queries&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./tests&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we’ll let our .tsconfig know about the module aliasing by updating the compilerOptions path (we can also refer to the tsconfig gist earlier).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;paths&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@src/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;src/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@queries/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;queries/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tests/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tests/*&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we’ll let ESLint know about it so we don’t get pesky linting errors when we alias. (Again, this was done in the earlier gist if you just copied that.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;import/resolver&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alias&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./src&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@queries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./queries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;extensions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, time to make sure this is configured correctly.&lt;/p&gt;

&lt;p&gt;Lets go create a /queries directory and add queries/exampleQuery.ts to validate our aliasing. We’ll make this module as simple as can be to test the compilation still works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;echo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We’ll just take a parameter and return it straight back. We’ll get a compile time error if this doesn’t work.&lt;/p&gt;

&lt;p&gt;Now in src/handler.ts, lets import this module with the alias we set up and try to use this in our response. Let’s update the message in our response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;APIGatewayProxyHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;aws&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;lambda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;
import { echo } from ‘@queries/exampleQuery&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;source-map-support/register’;

export const hello: APIGatewayProxyHandler = async (event) =&amp;gt; ({
  statusCode: 200,
  body: JSON.stringify({
    message: echo(‘Module aliasing is really the best’),
    input: event,
  }, null, 2),
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the aliasing makes refactoring so much simpler. Your IDE should also be smart enough to autoimport with aliases (WebStorm is anyway).&lt;/p&gt;

&lt;p&gt;And that’s about all there is to it. You should be good to start writing code and build out your services with all the goodness of TypeScript, ESLint, and Jest. I’ll cover how to use some of the powertools and how to set up SQS, SNS, Kinesis, and DynamoDB in a future post.&lt;/p&gt;

&lt;p&gt;You can find this entire starter template on &lt;a href="https://github.com/mtimbs/typescript-serverless"&gt;my GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For information on how to deploy this project to your AWS account by configuring IAM roles, &lt;a href="https://medium.com/@Michael_Timbs/creating-a-serverless-deploy-user-with-aws-iam-b2053227534"&gt;read here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>typescript</category>
    </item>
    <item>
      <title>When to Use Vue Over React</title>
      <dc:creator>Michael Timbs</dc:creator>
      <pubDate>Sun, 08 Mar 2020 13:26:57 +0000</pubDate>
      <link>https://forem.com/michael_timbs/when-to-use-vue-over-react-44fn</link>
      <guid>https://forem.com/michael_timbs/when-to-use-vue-over-react-44fn</guid>
      <description>&lt;p&gt;A highly opinionated article based on my experience as a front-end web developer over the last four years.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; professionally at my current job, but I choose &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt; for all personal projects. It’s my preferred framework of choice. I’ve used Vue in previous (publicly traded) companies, and it scaled incredibly well.&lt;/p&gt;

&lt;p&gt;Any seasoned developer will tell you software is all about trade-offs and throwing around objective statements like “Framework x is better than Framework y” are generally meaningless. By what metrics? In whose opinion? For this reason, I’ll compare Vue and React across three main concerns that are often competing trade-offs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Performance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Job Market&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Performance is usually where people want to start when discussing frameworks or languages. Everyone who writes software is building the next FAANG company, and every nanosecond of performance must be extracted from our code.&lt;/p&gt;

&lt;p&gt;I’m going to compare both frameworks on two components of performance, namely silicon time and carbon time. &lt;em&gt;Silicon time&lt;/em&gt; refers to the raw execution performance — how fast it can run in the browser. &lt;em&gt;Carbon time&lt;/em&gt; refers to how fast developers can build products in the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Silicon-time comparison
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fl8Rhlmh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3476/1%2A7mJ82zEHJdQY_giUkG4QlA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fl8Rhlmh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3476/1%2A7mJ82zEHJdQY_giUkG4QlA.png" alt="JS framework trade-offs for performance"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;React leverages JSX, which gives developers a lot of power to build arbitrarily complex logic. We can harness the Turing-complete power of JavaScript and treat our view as data. Something like Svelte leverages templates for markup that provide a rigid structure to the view layer.&lt;/p&gt;

&lt;p&gt;React and Vue both use a &lt;a href="https://stackoverflow.com/questions/21965738/what-is-virtual-dom"&gt;virtual DOM&lt;/a&gt; (VDOM), which, while practically fast enough, is inherently expensive and &lt;a href="https://svelte.dev/blog/virtual-dom-is-pure-overhead"&gt;almost purely overhead&lt;/a&gt;. Svelte compiles template code to raw JS and manipulates the DOM directly, which means it doesn’t have the performance overheads of maintaining a VDOM.&lt;/p&gt;

&lt;p&gt;What I love about Vue is it hedges its bets a little bit. The most common way to use Vue is to use templates in &lt;a href="https://vuejs.org/v2/guide/single-file-components.html"&gt;single-file components&lt;/a&gt;. This has allowed the Vue team to do some very clever things in the upcoming Vue 3 release with ahead-of-time (AOT) optimisations.&lt;/p&gt;

&lt;p&gt;The structured nature of a templates means a compiler can know things about your code and perform optimisations. The main optimisation Vue introduces is dropping all static data from the VDOM diff. VDOM performance is directly affected by the number of nodes it has to track. By filtering out static data from this VDOM-diffing process, we can reduce the number of nodes being tracked. This makes the code run much faster as it doesn’t have to compare a recursive tree of arbitrary nodes at each render cycle.&lt;/p&gt;

&lt;p&gt;While Vue appears to use templates in most cases, the compiler actually turns these templates into &lt;a href="https://vuejs.org/v2/guide/render-function.html"&gt;render functions&lt;/a&gt; for you under the hood. This means any time the templating of Vue is getting in your way, you can directly drop down and write render functions exactly like you would in React. This means you get all the flexibility of render functions and JSX that you get in React with some of the performance benefits you get from a templated framework like Svelte. Obviously, if you write a Vue application with 100% render functions, you lose all of the template optimisations.&lt;/p&gt;

&lt;p&gt;Code benchmarks are a bit of a waste of time, in my opinion, but a few show Vue 2 around 2.5x faster than default React, and Vue 3 is benchmarking 3-5x faster than Vue 2. In practice, the JS framework you use is going to be such a small component of your application that these benchmarks are nearly meaningless. However, if you’re building templates that’ll leverage Vue 3’s AoT optimisations from templates, there’s just no way the same app will be faster written in React.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Vue&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Carbon-time performance
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mMBT7FPc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3852/1%2AHbtXKUXCUSlz5J5gqWdN5A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mMBT7FPc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3852/1%2AHbtXKUXCUSlz5J5gqWdN5A.png" alt="Carbon cost versus silicon cost for software development"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A senior developer will cost you around $150/hr depending on where you are in the world. Even junior to midlevel developers are earning a good enough salary that you want to be factoring in development time and costs into your technical stack. It’s the reason why languages such as PHP, Python, Node, Ruby, etc. are so popular and we don’t just write everything in C.&lt;/p&gt;

&lt;p&gt;For front-end applications, we’re constrained by the browser, device resources, and network latency, so silicon performance is still a contributing factor — but carbon performance should also be at the forefront of any CTO’s mind.&lt;/p&gt;

&lt;p&gt;In my opinion, the single greatest contributing factor in the success of Vue has been its approachable documentation, resources, and ease of learning. I learned React and Vue at the same time, and Vue was noticeably easier to get started with. If you know HTML, CSS, and the bare basics of JS, you can build an application with Vue. I’ve spent half a day with a design team and had them shipping changes to production front ends in Vue. This frees up a lot of time for the dev team and allows designers to implement A/B tests and design updates without getting blocked by the software backlog.&lt;/p&gt;

&lt;p&gt;One of the things I love about Vue is the layered design of its opt-in tooling. You can start by pulling in Vue via a CDN. That means you can play with it without needing to go through complex build steps (webpack/Babel config, npm, etc). You can then progress to the Vue CLI and build basic apps. If you then need a state management solution, there’s an officially supported and documented solution in Vuex. Similarly, Vue Router is an officially endorsed and supported router solution for Vue.&lt;/p&gt;

&lt;p&gt;On the other hand, React introduces the &lt;a href="https://en.wikipedia.org/wiki/The_Paradox_of_Choice"&gt;paradox of choice,&lt;/a&gt; which can make things hard for newcomers.&lt;/p&gt;

&lt;p&gt;React is a small-scope, single-purpose library that introduces a component model that receives props and returns a VDOM tree. This provides a lot of flexibility and the React community has built many complex systems on top of this simple library.&lt;/p&gt;

&lt;p&gt;There’s a large ecosystem with many, many options available to solve tasks. These are maintained independently by users. This model provides a lot of opportunities for people to build things on top of React and build popular libraries and tools.&lt;/p&gt;

&lt;p&gt;It also makes things very difficult to find and learn. You’re stuck choosing the best option for state management or routing or configuring a new application. In my experience, this also makes hiring React developers harder. When there’s multiple ways to do things, onboarding new members to a React project has more friction than onboarding to a Vue project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Vue&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Scalability
&lt;/h2&gt;

&lt;p&gt;Most of my thoughts on the scalability of these frameworks was touched on in the performance section. Scalability is often intrinsically linked with performance, so it’s not surprising.&lt;/p&gt;

&lt;p&gt;I generally think of scalability in terms of:&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling the number of views/components/workflows in an application
&lt;/h3&gt;

&lt;p&gt;In terms of scaling out the number of components, I’m a really big fan of the single-file component (SFC). The logical grouping of a component makes a lot of sense to me. Many people disagree with this, and it’s a matter of opinion rather than an objective statement.&lt;/p&gt;

&lt;p&gt;The reason I love SFCs is because they provides a great way to enforce the &lt;a href="https://blog.cleancoder.com/uncle-bob/2014/05/08/SingleReponsibilityPrinciple.html"&gt;separation of concerns&lt;/a&gt; (SoC).* *Some people argue that mixing HTML, CSS, and JavaScript is doing the opposite of separating concerns. I’ve changed the way I think about this principle on the front end, largely with my obsessive adoption of &lt;a href="https://tailwindcss.com/"&gt;Tailwind CSS&lt;/a&gt; for styling my components.&lt;/p&gt;

&lt;p&gt;Adam Wathan wrote a &lt;a href="https://adamwathan.me/css-utility-classes-and-separation-of-concerns/"&gt;great article&lt;/a&gt;on the notion of SoC and how it applies to HTML and CSS. I think about my front-end components in a similar way. In my mind, a component is how it looks (HTML/CSS) &lt;em&gt;and&lt;/em&gt; how it works. Separating the markup from the JS feels arbitrary to me. If you consider your views as data, then (to me) it makes sense to group them with your data.&lt;/p&gt;

&lt;p&gt;Don’t even get me started on JSX and CSS-in-JS. HTML and CSS are not dead. They’re incredibly powerful building blocks of the web. Use them!&lt;/p&gt;

&lt;p&gt;The benefits of officially supported solutions to common problems also comes in handy at scale. If you’re having trouble scaling a Vue application, then chances are any other Vue application at scale has used the same architecture, and you’ll be able to find advice and help. You don’t need to worry about people saying, “Just use hooks/&lt;a href="https://mobx.js.org/README.html"&gt;MobX&lt;/a&gt;/&lt;a href="https://medium.com/p/9a4e0f01e064/edit"&gt;Redux&lt;/a&gt;/&lt;a href="https://redux-saga.js.org/"&gt;Redux-Saga&lt;/a&gt;.”&lt;/p&gt;

&lt;h3&gt;
  
  
  Scaling the number of developers on a team
&lt;/h3&gt;

&lt;p&gt;I’ve already mentioned I’ve previously seen a design team empowered to push changes to production with a few hours of help. That’s an insane productivity boost to any consumer-facing application.&lt;/p&gt;

&lt;p&gt;The general consensus that Vue is easier to learn also means you can train junior developers to a point of net benefit to the team much much faster. You can also onboard a React developer (assuming they know HTML and CSS) with little effort.&lt;/p&gt;

&lt;p&gt;Again, having consistent solutions to common problems makes code review and reasoning about a large codebase that much easier for everyone on the team.&lt;/p&gt;

&lt;p&gt;The key thing with both of these is maintaining development velocity while keeping a performant application that meets the needs of your users. Vue strikes the perfect balance here as far as I’m concerned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Vue&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Job Market
&lt;/h2&gt;

&lt;p&gt;OK, so I’ve convinced you Vue is better than React in every conceivable way. But this is meaningless if you can’t get paid (or find devs to hire).&lt;/p&gt;

&lt;p&gt;React has a much higher share of the job market (at least in Australia and the United States). If you look on most job boards, the number of React jobs advertised relative to Vue is significant (nearly 8x as many React jobs at the time of writing this based on 10 seconds of job-board searches).&lt;/p&gt;

&lt;p&gt;While React appears to win on this metric, I refuse to let React get points on the board, so I’ll make the following (water-tight, unassailable) argument.&lt;/p&gt;

&lt;p&gt;There are opportunities for both React and Vue in the job market. Companies using Vue or React both find it difficult to hire, and, in my experience, there’s a skills shortage for both. As someone looking for work, you can achieve mastery (or perceived mastery) of Vue much faster than you can with React. This means you should get an accelerated path to higher salaries. You’ll also have less competition when interviewing as React is still the most popular choice for many developers who are currently victims of the &lt;a href="https://www.behavioraleconomics.com/resources/mini-encyclopedia-of-be/sunk-cost-fallacy/"&gt;sunk-cost fallacy&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a company or hiring manager worried about competing for talent in the current market, Vue offers an opportunity to build more product per resource (carbon time benefits of Vue) and to grow your own talent (faster learning curve). Choosing Vue for greenfield projects or a new startup could just be the best decision you ever made when it comes to hiring.&lt;/p&gt;

&lt;p&gt;As more companies realise the benefits of Vue, I believe it’ll continue to swallow market share — and may even overtake React as the framework of choice in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Winner: Tie&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion and Closing Remarks
&lt;/h2&gt;

&lt;p&gt;This was a semi-tongue-in-cheek article about Vue and why I think it’s superior to React. I think React is a perfectly reasonable tool for building front ends, and I’m not claiming it’s bad. I just believe Vue has achieved a better balance in framework design.&lt;/p&gt;

&lt;p&gt;I would choose React over Vue in the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You want to work somewhere that uses React — e.g., Facebook&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have a team of experienced React developers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It’s easier to hire for React in your area&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I honestly don’t think there’s a single technical reason I’d choose React over Vue for the kind of applications I build or work on. This doesn’t mean one doesn’t exist, but I’ve just not come across one yet.&lt;/p&gt;

&lt;p&gt;Svelte and Elm are both incredibly interesting options I’m following closely but am uncertain about their viability for large-scale enterprise applications at this point in time.&lt;/p&gt;

&lt;p&gt;If you want to learn Vue, I highly recommend &lt;a href="https://laracasts.com/series/learn-vue-2-step-by-step"&gt;this free course&lt;/a&gt; by the amazing Jeffrey Way.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>react</category>
    </item>
    <item>
      <title>Switching Between Multiple AWS Accounts</title>
      <dc:creator>Michael Timbs</dc:creator>
      <pubDate>Wed, 04 Mar 2020 22:12:03 +0000</pubDate>
      <link>https://forem.com/michael_timbs/switching-between-multiple-aws-accounts-2g1d</link>
      <guid>https://forem.com/michael_timbs/switching-between-multiple-aws-accounts-2g1d</guid>
      <description>&lt;p&gt;Whether you use AWS across your organisation or for personal projects, it is useful to set up multiple accounts on AWS to seperate your staging/test and production environments. It is especially useful if you are building serverless applications as many of the tools you will use (e.g. Lambda) have soft limits on concurrent usage at the account level.&lt;/p&gt;

&lt;p&gt;Apart from getting around usage limits, separating your development and production accounts allows you to experiment in a real cloud environment without negatively impacting your production environment.&lt;/p&gt;

&lt;p&gt;The naive way of doing this involves constantly logging out and back in each time you want to change accounts, or to set up multiple chrome profiles that save your credentials for each account. Instead you can leverage assumed roles via IAM permissions and Organisation Units.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Organisations
&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%2Fcdn-images-1.medium.com%2Fmax%2F5312%2F1%2AwotQ528ngauzVHzx9LVP8g.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%2Fcdn-images-1.medium.com%2Fmax%2F5312%2F1%2AwotQ528ngauzVHzx9LVP8g.png" alt="AWS console — Navigate to My Organisation"&gt;&lt;/a&gt;&lt;em&gt;AWS console — Navigate to My Organisation&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Under your root AWS account create an organisational unit. Below I’ve created Production, Staging and Playground organisation accounts. Production and Staging are generally fine for most companies. I use playground as a place to try new AWS products in an environment I know I can safely nuke anything at any time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; All the accounts we are about to create all get billed in your root account.&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%2Fcdn-images-1.medium.com%2Fmax%2F4084%2F1%2A5kjJHMDp6to2vbwduQOuFg.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%2Fcdn-images-1.medium.com%2Fmax%2F4084%2F1%2A5kjJHMDp6to2vbwduQOuFg.png" alt="AWS Console — Organisation Unit View"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Organisation Unit View&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Once we have created these organisational units, we are going to need to add user accounts to them. Under &lt;strong&gt;Accounts&lt;/strong&gt; we are going to create some new accounts&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%2Fcdn-images-1.medium.com%2Fmax%2F4148%2F1%2A-kgPDyVEvA7-hF-jN4kr0Q.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%2Fcdn-images-1.medium.com%2Fmax%2F4148%2F1%2A-kgPDyVEvA7-hF-jN4kr0Q.png" alt="AWS Console — Create Account View"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Create Account View&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AWS account name I generally name after the organisational unit to keep things clear. The email I will usually do something like &lt;em&gt;michael+@domain.com.&lt;/em&gt; Leave the IAM role name as the default *OrganizationAccountAccessRole *(this is important).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; AWS requires unique emails, so adding the “+pod” etc will satisfy that requirement while still delivering emails to your primary domain.&lt;/p&gt;

&lt;p&gt;Once you create these users, you’ll need to wait 1–5 minutes for an invitation email from AWS. You’ll then need to use the &lt;em&gt;forgot password&lt;/em&gt; functionality to set a password for these accounts. I suggest using a password manager and making these strong.&lt;/p&gt;

&lt;p&gt;Log in to each of these accounts and note down the Account Number of each one. You’ll need these in a later step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create an IAM User
&lt;/h3&gt;

&lt;p&gt;Once we have the root accounts for production and staging, we need to create a user that can easily hop between these accounts. Unfortunately (and for reasons that aren’t clear to me) root accounts can not hop between other root accounts. We’ll need to create a dedicated IAM user and then give them access to all the accounts we created (root, production, staging etc).&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%2Fcdn-images-1.medium.com%2Fmax%2F4196%2F1%2AH4xsRc4e1HMGp2BZ38Txzw.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%2Fcdn-images-1.medium.com%2Fmax%2F4196%2F1%2AH4xsRc4e1HMGp2BZ38Txzw.png" alt="AWS Console — Create IAM user"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Create IAM user&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We give this user a username and give them access to the AWS management console. It’s important that we don’t give programmatic access here — if we need programmatic access to these accounts (for deployments via CLI etc, we will use the root credentials or create new ones). This user is merely for hopping between the AWS console across your accounts.&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%2Fcdn-images-1.medium.com%2Fmax%2F4276%2F1%2AwJR-Qqz0VMXrmkZgdy6BqA.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%2Fcdn-images-1.medium.com%2Fmax%2F4276%2F1%2AwJR-Qqz0VMXrmkZgdy6BqA.png" alt="AWS Console — IAM user permissions"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — IAM user permissions&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I’ll give this user administration permissions as I am the admin and want to use this user across all my accounts. If you are creating a user for someone else in your organisation you may want to change the access policies as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switch Roles
&lt;/h3&gt;

&lt;p&gt;Once you create this user you will be given a special log in link. Click through to this link and then log in as this user. One you log in you should see that the main account menu gives you access to a new option called &lt;em&gt;Switch Role&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%2Fcdn-images-1.medium.com%2Fmax%2F5888%2F1%2AF-wTXK0vdWEAC1-Xl6A94A.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%2Fcdn-images-1.medium.com%2Fmax%2F5888%2F1%2AF-wTXK0vdWEAC1-Xl6A94A.png" alt="AWS Console — IAM user login with Switch Role"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — IAM user login with Switch Role&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%2Fcdn-images-1.medium.com%2Fmax%2F5448%2F1%2A2PguwsfVzk9tbpfQlnBuYw.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%2Fcdn-images-1.medium.com%2Fmax%2F5448%2F1%2A2PguwsfVzk9tbpfQlnBuYw.png" alt="AWS Console- Switch Role"&gt;&lt;/a&gt;&lt;em&gt;AWS Console- Switch Role&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Switch Role&lt;/em&gt; screen will prompt you to input the account number of the account you want to switch to. Add the account number of the Staging/Production account we created earlier.&lt;br&gt;
In the &lt;em&gt;Role*section we need to input the role name we created with those accounts *OrganizationAccountAccessRole.&lt;/em&gt; Then give the account display name and a colour and hit the Switch Role button.&lt;/p&gt;

&lt;p&gt;This will save this role on your account and redirect you to it. You can repeat this step with any other accounts you want to be able to hop between.&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%2Fcdn-images-1.medium.com%2Fmax%2F6096%2F1%2AoZWSJSLsNPz7f4NixoMywQ.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%2Fcdn-images-1.medium.com%2Fmax%2F6096%2F1%2AoZWSJSLsNPz7f4NixoMywQ.png" alt="AWS Console — Switch Roles"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Switch Roles&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You’ll now be able to switch between accounts at the click of a button. Once you switch to an account you’ll clearly be able to see which account you are in.&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%2Fcdn-images-1.medium.com%2Fmax%2F6136%2F1%2AEU2suiGDh9GABTqCEWH7yA.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%2Fcdn-images-1.medium.com%2Fmax%2F6136%2F1%2AEU2suiGDh9GABTqCEWH7yA.png" alt="AWS Console — Example Production Account"&gt;&lt;/a&gt;&lt;em&gt;AWS Console — Example Production Account&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now as a solo developer you’ll be able to sandbox your environments, have clean accounts to play with new technologies (like &lt;a href="https://medium.com/@Michael_Timbs/linear-regression-with-aws-sagemaker-15feefb19342" rel="noopener noreferrer"&gt;Sagemaker&lt;/a&gt;) and not have to worry about deleting resources or experimenting and breaking production code.&lt;/p&gt;

&lt;p&gt;At an organisation level you will be able to create seperate root accounts for various parts of your organisation, and give users access to only the environments they need.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>iam</category>
    </item>
  </channel>
</rss>
