<?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: Mischa Spiegelmock</title>
    <description>The latest articles on DEV Community by Mischa Spiegelmock (@cybermischa).</description>
    <link>https://dev.to/cybermischa</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%2F183608%2F8542e4ed-8b44-4430-9905-492e520826e7.jpeg</url>
      <title>DEV Community: Mischa Spiegelmock</title>
      <link>https://dev.to/cybermischa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cybermischa"/>
    <language>en</language>
    <item>
      <title>AWS CDK Video - Next-Gen IaC</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Mon, 05 Apr 2021 17:24:24 +0000</pubDate>
      <link>https://dev.to/cybermischa/aws-cdk-video-next-gen-iac-1ggo</link>
      <guid>https://dev.to/cybermischa/aws-cdk-video-next-gen-iac-1ggo</guid>
      <description>&lt;p&gt;New talk of mine about AWS Cloud Development Kit - a new more convenient way to write infrastructure as code.&lt;br&gt;
If you're using AWS, throw your Terraform or CloudFormation templates in the trash and use CDK instead.&lt;/p&gt;

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

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>devops</category>
      <category>unemployeddevops</category>
    </item>
    <item>
      <title>Typesafe Infra And Web Services With AWS CDK</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Tue, 26 Jan 2021 14:16:02 +0000</pubDate>
      <link>https://dev.to/cybermischa/typesafe-infra-and-web-services-with-aws-cdk-3kbi</link>
      <guid>https://dev.to/cybermischa/typesafe-infra-and-web-services-with-aws-cdk-3kbi</guid>
      <description>&lt;p&gt;If you want to build a cloud-native web service, consider reaching for the AWS &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/home.html"&gt;Cloud Development Kit&lt;/a&gt;. CDK is a new generation of infrastructure-as-code (IaC) tools designed to make packaging your code and infrastructure together as seamless and powerful as possible. It’s great for any application running on AWS, and it’s especially well-suited to serverless applications.&lt;/p&gt;

&lt;p&gt;The CDK consists of a set of libraries containing resource definitions and higher-level constructs, and a command line interface (CLI) that synthesizes CloudFormation from your resource definitions and manages deployments. You can imperatively define your cloud resources like &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html"&gt;Lambda functions&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html"&gt;S3 buckets&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigatewayv2-readme.html"&gt;APIs&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/aws-route53-readme.html"&gt;DNS records&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-synthetics.Canary.html"&gt;alerts&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-dynamodb.Table.html"&gt;DynamoDB tables&lt;/a&gt;, and everything else in AWS using TypeScript, Python, .NET, or Java. You can then connect these resources together and into more abstract groupings of resources and finally into stacks. Typically one entire service would be one stack.&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="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;HelloCdkStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;MyFirstBucket&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="na"&gt;versioned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;CDK doesn’t exactly replace CloudFormation because it generates CloudFormation markup from your resource and stack definitions. But it does mean that if you use CDK you don’t really ever have to manually write CloudFormation ever again. CloudFormation is a declarative language, which makes it challenging and cumbersome to do simple things like conditionals, for example changing a parameter value or not including a resource when your app is being deployed to production. When using a typed language you get the benefit of writing IaC with type checking and code completion, and the ability to connect resources together with a very natural syntax. One of the real time-saving benefits of CDK is that you can group logical collections of resources into reusable classes, defining higher level constructs like &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-synthetics.Canary.html"&gt;CloudWatch canary scripts&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda-nodejs.NodejsFunction.html"&gt;NodeJS functions&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudfront.CloudFrontWebDistribution.html"&gt;S3-based websites with CloudFront&lt;/a&gt;, and your own custom constructs of whatever you find yourself using repeatedly.&lt;/p&gt;

&lt;p&gt;The CLI for CDK gives you a set of tools mostly useful for deploying your application. A simple &lt;code&gt;cdk deploy&lt;/code&gt; parses your stacks and resources, synthesizes CloudFormation, and deploys it to AWS. The CLI is basic and relatively new, so don’t expect a ton of mature features just yet. I am still using the Serverless framework for serious applications because it has a wealth of built-in functionality and useful plugins for things like testing applications locally and tailing CloudWatch logs. AWS’s &lt;a href="https://aws.amazon.com/serverless/sam/#:~:text=The%20AWS%20Serverless%20Application%20Model,and%20model%20it%20using%20YAML."&gt;Serverless Application Model&lt;/a&gt; (SAM) is sort of equivalent to Serverless, but feels very Amazon-y and more like a proof-of-concept than a tool with any user empathy. The names of all of these tools are somewhat uninspired and can understandably cause confusion, so don’t feel bad if you feel a little lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample CDK Application
&lt;/h2&gt;

&lt;p&gt;I built a small web service to put the CDK through its paces. My &lt;a href="https://github.com/revmischa/cursed-webring"&gt;application&lt;/a&gt; has a React frontend that fetches a list of really shitty websites from a Lambda function and saves them in the browser’s &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API"&gt;IndexedDB&lt;/a&gt;, a sort of browser SQL database. The user can view the different shitty websites with previous and next buttons and submit a suggestion of a terrible site to add to the webring. You can view the entire source &lt;a href="https://github.com/revmischa/cursed-webring"&gt;here&lt;/a&gt; and the finished product at &lt;a href="https://cursed.lol"&gt;cursed.lol&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cursed.lol"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZXiX6S3H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/spiegelmock.com/wp-content/uploads/2021/01/Screen-Shot-2021-01-24-at-11.31.50-AM.png%3Fresize%3D700%252C404%26ssl%3D1" alt=""&gt;&lt;/a&gt;The Cursed Webring&lt;/p&gt;

&lt;p&gt;To kick off a CDK project, run the &lt;code&gt;init&lt;/code&gt; command: &lt;code&gt;cdk init app --language typescript&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This generates an application scaffold we can fill in, beginning with the &lt;code&gt;bin/cdk.ts&lt;/code&gt; script if using TypeScript. Here you can optionally &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/environments.html"&gt;configure environments&lt;/a&gt; and import your stacks.&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="cp"&gt;#!/usr/bin/env node
&lt;/span&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/core&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CursedStack&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="s2"&gt;../lib/stack&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;envProd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1234567890&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eu-west-1&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CursedStack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CursedStack&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="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;envProd&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The environment config isn’t required; by default your application can be deployed into any region and AWS account, making it easy to share and create development environments. However if you want to pre-define some environments for dev/staging/prod you can do that explicitly here. The &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/environments.html"&gt;documentation&lt;/a&gt; suggests using environment variables to select the desired AWS account and region at deploy-time and then writing a small shell script to set those variables when deploying. This is a very flexible and customizable way to manage your deployments, but it lacks the simplicity of Serverless which has a &lt;a href="https://www.serverless.com/blog/stages-and-environments"&gt;simple command-line option&lt;/a&gt; to select which stage you want. CDK is great for customizing to your specific needs, but doesn’t quite have that out-of-the-box user friendliness.&lt;/p&gt;

&lt;h2&gt;
  
  
  DynamoDB
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at a construct that defines a DynamoDB table for storing user submissions:&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/core&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/aws-dynamodb&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;class&lt;/span&gt; &lt;span class="nx"&gt;CursedDB&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submissionsTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SubmissionsTable&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="na"&gt;partitionKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AttributeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;billingMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;dynamodb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BillingMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PAY_PER_REQUEST&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;Here we create a table that has a string &lt;code&gt;id&lt;/code&gt; primary key. In this example we save the table as a public property (&lt;code&gt;this.submissionsTable&lt;/code&gt;) on the instance of our &lt;code&gt;Construct&lt;/code&gt; because we will want to reference the table in our Lambda function in order to grant write access and provide the name of the table to the function so that it can write to the table. This concept of using a class property to keep track of resources you want to pass to other constructs isn’t anything particular to CDK – it’s just something I decided to do on my own to make it easy to connect different pieces of my service together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lambda Functions
&lt;/h2&gt;

&lt;p&gt;Here I declare a construct which defines two Lambda functions. One function fetches a list of websites for the user to browse, and the other handles posting submissions which saved into our DynamoDB &lt;code&gt;submissionsTable&lt;/code&gt; as well as Slacked to me. I am extremely lazy and manage most of my applications this way. We use the convenient &lt;code&gt;NodejsFunction&lt;/code&gt; high-level construct to make our lives easier. This is the most complex construct of our stack. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads a secret containing our Slack webhook URL&lt;/li&gt;
&lt;li&gt;Defines a custom property &lt;code&gt;submissionsTable&lt;/code&gt; that it expects to receive&lt;/li&gt;
&lt;li&gt;Defines an API Gateway with CORS enabled&lt;/li&gt;
&lt;li&gt;Creates an API resource (&lt;code&gt;/sites/&lt;/code&gt;) to hold our function endpoints&lt;/li&gt;
&lt;li&gt;Defines two Lambda NodeJS functions (note that our source files are TypeScript – &lt;a href="https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda-nodejs.BundlingOptions.html"&gt;compilation&lt;/a&gt; happens automatically)&lt;/li&gt;
&lt;li&gt;Connects the Lambda functions to the API resource as &lt;code&gt;GET&lt;/code&gt; and &lt;code&gt;POST&lt;/code&gt; endpoints&lt;/li&gt;
&lt;li&gt;Grants write access to the &lt;code&gt;submissionsTable&lt;/code&gt; to the &lt;code&gt;submitSiteHandler&lt;/code&gt; function
&lt;/li&gt;
&lt;/ul&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/core&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;apigateway&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/aws-apigateway&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;sm&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/aws-secretsmanager&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NodejsFunction&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="s2"&gt;@aws-cdk/aws-lambda-nodejs&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;RestApi&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="s2"&gt;@aws-cdk/aws-apigateway&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Table&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="s2"&gt;@aws-cdk/aws-dynamodb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ARN of a secret containing the slack webhook URL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;slackWebhookSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arn:aws:secretsmanager:eu-west-1:178183757879:secret:cursed/slack_webhook_url-MwQ0dY&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// required properties to instantiate our construct&lt;/span&gt;
&lt;span class="c1"&gt;// here we pass in a reference to our DynamoDB table&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;CursedSitesServiceProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Table&lt;/span&gt;&lt;span class="p"&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;class&lt;/span&gt; &lt;span class="nx"&gt;CursedSitesService&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;id&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="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CursedSitesServiceProps&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// load our webhook secret at deploy-time&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromSecretCompleteArn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SlackWebhookSecret&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;slackWebhookSecret&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// our API Gateway with CORS enabled&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;RestApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cursed-api&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="na"&gt;restApiName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cursed Service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;defaultCorsPreflightOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;allowOrigins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;apigateway&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Cors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ALL_ORIGINS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// defines the /sites/ resource in our API&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sitesResource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// get all sites handler, GET /sites/&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getAllSitesHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;NodejsFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GetCursedSitesHandler&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="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resources/cursedSites.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;getAllHandler&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="nx"&gt;sitesResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;getAllSitesHandler&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// submit, POST /sites/&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;submitSiteHandler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;NodejsFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SubmitCursedSiteHandler&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="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resources/cursedSites.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submitHandler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// let our function access the webhook and dynamoDB table&lt;/span&gt;
          &lt;span class="na"&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secretValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
          &lt;span class="na"&gt;CURSED_SITE_SUBMISSIONS_TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// allow submit function to write to our dynamoDB table&lt;/span&gt;
    &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;grantWriteData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitSiteHandler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;sitesResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;submitSiteHandler&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;While there’s a lot going on here it is very readable if taken line-by-line. I think this showcases some of the real expressibility of CDK. That &lt;code&gt;props.submissionsTable.grantWriteData(submitSiteHandler)&lt;/code&gt; stanza is really &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZMFuojAC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/13.0.1/72x72/1f468-1f3fb-200d-1f373.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZMFuojAC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/13.0.1/72x72/1f468-1f3fb-200d-1f373.png" alt="👨🏻‍🍳"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s1QIv4HP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/13.0.1/72x72/1f44c-1f3fb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s1QIv4HP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s.w.org/images/core/emoji/13.0.1/72x72/1f44c-1f3fb.png" alt="👌🏻"&gt;&lt;/a&gt;. It grants that one function permission to write to the DynamoDB table that we defined in our first construct. We didn’t have to write any IAM policy statements, reference CloudFormation resources, or even &lt;a href="https://aws.amazon.com/blogs/security/how-to-create-an-aws-iam-policy-to-grant-aws-lambda-access-to-an-amazon-dynamodb-table/"&gt;look up exactly&lt;/a&gt; which actions this statement needs to consists of. This gives you a bit of the flavor of CDK’s simplicity compared to writing CloudFormation by hand.&lt;/p&gt;

&lt;p&gt;If you’d like to look at the source code of these Lambdas you can find it &lt;a href="https://github.com/revmischa/cursed-webring/blob/master/cdk/resources/cursedSites.ts"&gt;here&lt;/a&gt;. Fetching the list of sites is accomplished by loading a Google Sheet as a CSV (did I mention I’m really lazy?) and the submission handler does a simple DynamoDB &lt;code&gt;Put&lt;/code&gt; &lt;a href="https://github.com/revmischa/cursed-webring/blob/master/cdk/resources/db.ts"&gt;call&lt;/a&gt; and hits the Slack webhook with the submission. I love this kind of web service setup because once it’s deployed it runs forever and I never have to worry about managing it again, and it costs roughly $0 per month. If a website is submitted I can evaluate it and decide if it’s shitty enough to be included, and if so I can just add it to the Google Sheet. And I have a record of all submissions in case I forget or one gets lost in Slack or something.&lt;/p&gt;

&lt;h2&gt;
  
  
  CloudFront CDN
&lt;/h2&gt;

&lt;p&gt;Let’s take a look at one last construct I put together for this application, a CloudFront CDN distribution in front of a S3 static website bucket. I realized the need to mirror many of these lame websites because due to their inherent crappiness they were slow, didn’t support HTTPS (needed when iFraming), and might not stay up forever. A little &lt;code&gt;curl --mirror&lt;/code&gt; magic fixed that right up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i1.wp.com/spiegelmock.com/wp-content/uploads/2021/01/Screen-Shot-2021-01-24-at-11.33.42-AM.png?ssl=1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1awAG6DY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/spiegelmock.com/wp-content/uploads/2021/01/Screen-Shot-2021-01-24-at-11.33.42-AM.png%3Fresize%3D700%252C403%26ssl%3D1" alt=""&gt;&lt;/a&gt;It’s important to preserve these treasures&lt;/p&gt;

&lt;p&gt;Typically defining a CloudFront distribution with HTTPS support is a bit of a headache. Again the high-level constructs you get included with CDK really shine here and I made use of the &lt;code&gt;CloudFrontWebDistribution&lt;/code&gt; construct to define just what I needed:&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;CloudFrontWebDistribution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;OriginProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;,&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="s2"&gt;@aws-cdk/aws-cloudfront&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// cursed.llolo.lol ACM cert&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;certificateArn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;arn:aws:acm:us-east-1:1234567890:certificate/79e60ba9-5517-4ce3-8ced-2d9d1ddb1d5c&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;class&lt;/span&gt; &lt;span class="nx"&gt;CursedMirror&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CloudFrontWebDistribution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cursed-mirrors&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="na"&gt;originConfigs&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="na"&gt;customOriginSource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;domainName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cursed.llolo.lol.s3-website-eu-west-1.amazonaws.com&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;httpPort&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;originProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;OriginProtocolPolicy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HTTP_ONLY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;behaviors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;isDefaultBehavior&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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="na"&gt;aliasConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;acmCertRef&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;certificateArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;names&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;cursed.llolo.lol&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a HTTPS-enabled CDN in front of my existing S3 bucket with static website hosting. I could have created the bucket with CDK as well but, since there can only be one bucket with this particular domain that seemed a bit overkill. If I wanted to make this more reusable these values could be stack &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/parameters.html"&gt;parameters&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;Finally the top-level &lt;code&gt;Stack&lt;/code&gt; contains all of our constructs. Here you can see how we pass the DynamoDB table provided by the &lt;code&gt;CursedDB&lt;/code&gt; construct to the &lt;code&gt;CursedSitesService&lt;/code&gt; containing our Lambdas.&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="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@aws-cdk/core&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CursedMirror&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="s2"&gt;./cursedMirror&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CursedSitesService&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="s2"&gt;./cursedSitesService&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CursedDB&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="s2"&gt;./db&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;class&lt;/span&gt; &lt;span class="nx"&gt;CursedStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Stack&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Construct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;cdk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StackProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CursedDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CursedDB&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CursedSitesService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CursedSiteServices&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="na"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;submissionsTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CursedMirror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CursedSiteMirrorCDN&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;Putting it all together, all that’s left to do is run &lt;code&gt;cdk deploy&lt;/code&gt; to summon our cloud resources into existence and write our &lt;a href="https://github.com/revmischa/cursed-webring/tree/master/src"&gt;frontend&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is This Better?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/spiegelmock.com/wp-content/uploads/2021/01/AppStacks.png?ssl=1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lr023EA8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/spiegelmock.com/wp-content/uploads/2021/01/AppStacks.png%3Fresize%3D700%252C391%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Going through this exercize of creating a real service using nothing but CDK was a great way for me to get more comfortable with the tools and concepts behind it. Once I wrapped my head around the way the constructs fit together and started discovering all of the high-level constructs already provided by the libraries I really started to dig it. Need to load some secrets? Need to define Lambda functions integrated to API Gateway? Need a CloudFront S3 bucket website distribution? Need CloudWatch canaries? It’s already there and ready to go along with strict compile-time checking of your syntax and properties. I pretty much never encountered a situation where my code compiled but the deployment was invalid, a vastly improved state of affairs from trying to write CloudFormation manually.&lt;/p&gt;

&lt;p&gt;And what about Terraform? In my humble opinion if you’re going to build cloud-native software it’s a waste of effort to abstract out your cloud provider and their resources. Better to embrace the tooling and particulars of one provider and specialize instead of pursuing some idealistic cloud-agnostic setup at a great price of efficiency. &lt;a href="https://www.lastweekinaws.com/blog/multi-cloud-is-the-worst-practice/"&gt;Multi-cloud is the worst practice&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The one thing that I missed most from the Serverless framework was tailing my CloudWatch logs. When I had issues in my Lambda logic (not something the CDK can fix for you) I had to go into the CloudWatch console to look at the logs instead of simply being able to tail them from the command line. The upshot though is that CDK is simply code, and writing your own tooling around it using the AWS API should be straightforward enough. I expect SAM and the CDK CLI to only get more mature and user-friendly over time, so I imagine I’ll be building projects of increasing seriousness with them as time progresses.&lt;/p&gt;

&lt;p&gt;If you want to learn more, start with the &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/home.html"&gt;CDK docs&lt;/a&gt;. And if you know of any cursed websites please feel free to &lt;a href="http://cursed.lol/"&gt;mash that submit button&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://spiegelmock.com/2021/01/25/web-services-with-aws-cdk/"&gt;Web Services with AWS CDK&lt;/a&gt; appeared first on &lt;a href="https://spiegelmock.com"&gt;spiegelmock.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>uncategorized</category>
    </item>
    <item>
      <title>Is Software Contracting For You?</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Tue, 20 Oct 2020 19:11:25 +0000</pubDate>
      <link>https://dev.to/cybermischa/is-software-contracting-for-you-592i</link>
      <guid>https://dev.to/cybermischa/is-software-contracting-for-you-592i</guid>
      <description>&lt;p&gt;It was in the last great recession that I started doing contract software development, about 2008-2010. The bubble didn’t burst with as much force and shrapnel as in 2000, but it had a distinct dampening of the animal spirits of SOMA, San Francisco where all the startups lived.&lt;/p&gt;

&lt;p&gt;It was somewhat by design. The previous job I had, writing Java and ActionScript for a marketing research company was chill enough but felt aimless. I had so little motivation I ended up coasting for a few months and playing a lot of pingpong. I wanted some new challenges, so decided to go freelance.&lt;/p&gt;

&lt;p&gt;The first gig I got was off of Craigslist, although I imagine these days Upwork would be a better place to look for work. The project was very limited in scope; mostly adding a Google Maps visualization on top of some grant data for a nonprofit. It was a couple weeks of work, a couple grand, and time to move on.&lt;/p&gt;

&lt;p&gt;Some time later a former colleague of mine hired me for some development work at a SF startup doing IP telephony combined with podcasting. This was 2009 so nobody had ever heard of podcasts and smartphones were still a fresh new technology people weren’t entirely sure what to do with. The gig was a fun challenge – enabling people to listen to and produce podcasts using only a telephone, no apps involved. I ended up developing some pretty innovative software that resembled a web framework but for touch tone and interactive voice response (IVR) phone applications. We successfully moved the application from an expensive managed solution to our own in-house platform that I designed, significantly cutting down operating costs.&lt;/p&gt;

&lt;p&gt;After some time working on that project, I met a couple of guys who wanted to build a SEO-optimized directory of medical professionals, starting with Spanish-speaking plastic surgeons. I said I could cobble together a search engine in my spare time and was engaged. Some days I would walk the two blocks over from the small telephony company office to the small office housing the nascent doctor directory business and show my progress.&lt;/p&gt;

&lt;p&gt;It seemed clear at the time that the podcasting telephony company while highly experimental, was professionally run. It had not one but two Stanford business school co-CEOs running it, with what amounted to a successful track record in the form of an early dot-com electronic greeting card company. Remember those? Weird shit. There were respectable investors, a small team of smart and highly competent professionals, and a beautiful office on Howard St. I recall situated on the floor below our office sat a little room consisting of no furniture save a well-stocked bar with never any people in sight, and a sign on the door reading “GitHub.” I felt like great things could happen.&lt;/p&gt;

&lt;p&gt;In contrast, my side gig seemed like some small-time SEO hustling along with a smaller team and paycheck and no Stanford business vibes or major VC funding. I didn’t see anything wrong with that, and still tried to do a professional job, but it seemed like more of a dead end compared to the “real” engineering I was doing, fighting battles with touchy open-source PBX software and voice recognition grammars.&lt;/p&gt;

&lt;p&gt;Then things turned out completely differently from what I expected. The doctor directory project kept growing, expanding, and taking on a life of its own. We got a proper office at 1st and Mission, hired an engineer, a designer, a salesperson. Plastic surgeons were mostly ditched, and now we were primarily helping American dentists establish a presence on this new “world wide web” technology they couldn’t quite wrap their heads around. This contacting gig that I imagined would consist of a couple months of basic work kept growing and there was always more work to do. Without any planning or expectations it turned into a real company, with eventually a staff of 25 talented and terrific people and an extremely respectable office in the Financial District. We built software to help all kinds of small medical practices in the US manage their patient communication, from appointment reminders to e-visits to actually useful online medical Q&amp;amp;A. Six years later we sold the company to a large practice management software firm in Irvine, CA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i1.wp.com/spiegelmock.com/wp-content/uploads/2020/10/20140912_164524.jpeg?ssl=1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R1kXg9Fc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/spiegelmock.com/wp-content/uploads/2020/10/20140912_164524.jpeg%3Fresize%3D700%252C525%26ssl%3D1" alt=""&gt;&lt;/a&gt;And practiced our swordsmanship.&lt;/p&gt;

&lt;p&gt;Following that experience my business partner John and I started a new company together again, this time on purpose. We started hiring and training some of the best young engineers, taking on projects and filling outstaffing needs for our clients, staffing a couple offices in Eastern Europe until covid forced us to go purely remote. This has in effect scaled up from my original single-person consulting operation into a powerhouse team of crack young engineers ready to take on complex software projects.&lt;/p&gt;

&lt;p&gt;The classic Silicon Valley VC-backed, Stanford-connected, hip startup went nowhere, and closed its doors. I got permission to &lt;a href="https://github.com/revmischa/asteryst"&gt;open-source&lt;/a&gt; the IVR framework we built but little else came of it. As it happened, consulting across different clients helped me to gain a broader picture of what was actually possible and break my preconceived notions founded on image instead of substance. I accidentally ended up starting a company which went on to help make American health care just a little tiny bit less terrible, created a couple dozen jobs, and had the profound and unique experience of building up the software for a company starting completely from nothing up through due diligence and acquisition. Along the way I learned some lessons about software contracting I want to share with others who may be considering going &lt;em&gt;rōnin&lt;/em&gt; and setting out on their own as freelancers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tradeoffs and Considerations
&lt;/h2&gt;

&lt;p&gt;It’s my nature to think of everything in terms of trade-offs. Maybe because I have engineer-brain, or because I’m a libra, who knows. There are real benefits to consulting as opposed to being a full-time employee, but also some downsides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Legal Concerns
&lt;/h3&gt;

&lt;p&gt;In America at least, contracting means forming your own business, doing 1099 tax forms and racking up deductions, and drafting and reviewing contracts. It’s more effort and responsibility than being a full-time employee somewhere, as you’re now responsible for taxes and legal matters. Even if you’re not in America, being able to work across borders means creating a legal business entity.&lt;/p&gt;

&lt;p&gt;I started by initially getting a DBA, or “Doing Business As” name, under which I could legally create contracts and other paperwork using an official-looking business name. Later on I “upgraded” to a California S-Corporation, which gives favorable tax treatment once your income reaches a certain threshold along with some legal liability protection. If your corporation is sued, all that can be collected usually is what the corporation has, shielding you personally to some degree. A Cali S-Corp will run you $800 a year not counting the time spent on paperwork and taxes you or your accountant/tax attorney will be doing.&lt;/p&gt;

&lt;p&gt;Even getting a DBA or Fictitious Business Name is far from simple. In Contra Costa County for example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Within 30 days after a fictitious business name statement has been filed, the registrant shall cause it to be published in a newspaper of general circulation in the county where the fictitious business name statement was filed or, if there is no such newspaper in that county, in a newspaper of general circulation in an adjoining county. If the registrant does not have a place of business in this state, the notice shall be published in a newspaper of general circulation in Sacramento County. The publication must be once a week for four successive weeks and an affidavit of publication must be filed with the county clerk where the fictitious business name statement was filed within 30 days after the completion of the publication.&lt;/p&gt;

&lt;p&gt;&lt;cite&gt;&lt;a href="https://www.ccclerkrec.us/clerk/clerk/fictitious-business-name/"&gt;&lt;/a&gt;&lt;a href="https://www.ccclerkrec.us/clerk/clerk/fictitious-business-name/"&gt;https://www.ccclerkrec.us/clerk/clerk/fictitious-business-name/&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_p0j5YJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/spiegelmock.com/wp-content/uploads/2020/09/image.png%3Fresize%3D700%252C306%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_p0j5YJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/spiegelmock.com/wp-content/uploads/2020/09/image.png%3Fresize%3D700%252C306%26ssl%3D1" alt=""&gt;&lt;/a&gt;You also need to take out an ad in a local paper announcing the new business and inform your county.&lt;/p&gt;

&lt;p&gt;You don’t need to do this yourself necessarily, services like &lt;a href="https://www.businessrocket.net/"&gt;BusinessRocket&lt;/a&gt; can take care of business formation and taxes for a small fee.&lt;/p&gt;

&lt;p&gt;One of the first things you’ll need to do is ask your friends for legal services recommendations. If you know anyone who is a contractor or a small business owner they probably have lawyers they work with and can recommend. Or you can hit me up. I enlisted the services of a business attorney to help me draft and review contracts, and a &lt;a href="https://taxninja.com/"&gt;tax attorney&lt;/a&gt; to take care of the corporation taxes and paperwork. Obviously lawyers are not cheap and in theory you can do all of this yourself, but they can also save you a great time of time and money as well by warning you about common pitfalls and fuckups, and suggest ways to better protect yourself or take advantage of favorable tax laws.&lt;/p&gt;

&lt;p&gt;When you are going to agree to do work for a client they will want to know your hourly or project rate and a contract to sign. Understand that around a third to a half of your hourly rate is going to go to taxes, so adjust accordingly. A contract will need to have some important pieces of information. I highly suggest not listening to me and listening to an Actual Lawyer in your country or state about drafting a contract, but as far as software development you will typically need to include a “schedule of work.” This is the scope of what you will be expected to deliver in order to get paid.&lt;/p&gt;

&lt;p&gt;Come at the schedule of work with a PM mindset – you have to figure out what the client actually wants and what actually needs to get built. If you end up needing to do more work outside of this scope then it can be a headache, and having a contract which spells out what you’ve been asked to do can make an effective backstop against scope creep. As a related matter, I highly suggest doing per-hour billing rather than doing projects for a fixed price whenever possible, because as we all know the best laid o’ work statement often go awry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YQ0K4XOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/spiegelmock.com/wp-content/uploads/2020/09/image-1.png%3Fresize%3D700%252C720%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YQ0K4XOd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i1.wp.com/spiegelmock.com/wp-content/uploads/2020/09/image-1.png%3Fresize%3D700%252C720%26ssl%3D1" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Technology
&lt;/h3&gt;

&lt;p&gt;Sometimes you have a particular skill or framework or vertical or other some such specialization, and you can look for relevant gigs. When I started out it mine was actually Perl, and I didn’t have a hard time at all finding work. The first nonprofit project I worked on was already using my favorite Perl web framework. Some jobs will leave it entirely up to you to create something from nothing, and you can have your choice of technology for solving the problem. Sometimes you will go work for a company with their own existing codebase that wants to expand it, fix existing problems, or throw it away and rewrite from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eWp4wS6p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/imgs.xkcd.com/comics/regular_expressions.png%3Fw%3D700%26ssl%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eWp4wS6p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i2.wp.com/imgs.xkcd.com/comics/regular_expressions.png%3Fw%3D700%26ssl%3D1" alt="Regular Expressions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For me this is one of the most thrilling parts of contracting; getting to see how different companies operate. I’ve gotten an opportunity to look at a good amount of different codebases and operational setups. It gives you a broader view of the landscape, allowing you to borrow best practices others have landed on, and learn from the mistakes of others. I’ve gotten to encounter a lot of technologies I would not have otherwise run into, like seeing different implementations of microservices, getting really familiar with SNMP, and deconstructing a J2EE application. When you work for one company or for yourself for a long time, it can be hard to stay current or get experience with other technologies. When working with different companies, you can rapidly take in and observe various stacks that organizations have coalesced around, usually ending up with good practices. There’s an infinite combination of frameworks, languages, architectures, libraries, development environments, and security practices and the state of the art is always in flux. Having exposure to new assemblies of technology keeps you curious and informed and better able to make decisions for your clients and projects.&lt;/p&gt;

&lt;p&gt;Most of our business consists of either building new projects for people, taking over existing projects, or joining existing teams. We get to experience not just code of course, but see how different organizations are run, different business models, all kinds of personalities and team dynamics. It can potentially open you up to a richer tapestry of experiences and cultures than working on the same product and team for years and years will.&lt;/p&gt;

&lt;p&gt;The technology you encounter will vary wildly, from hipster web microframeworks to ancient enterprise Java. Being flexible and able to rapidly adapt and figure out the basics of a lot of different technologies is a very valuable skill, as is learning how to start up every kind of bespoke development environment out there. I sort of have a weird perverted dream of going around rewriting ancient COBOL applications for desperate businesses to run on modern serverless cloud-first architecture.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/spiegelmock.com/wp-content/uploads/2020/10/2013-06-12-22.32.19.jpeg?ssl=1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zLJ2bjW3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/spiegelmock.com/wp-content/uploads/2020/10/2013-06-12-22.32.19.jpeg%3Fresize%3D700%252C525%26ssl%3D1" alt=""&gt;&lt;/a&gt;You never know where freelancing will take you.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clients
&lt;/h3&gt;

&lt;p&gt;The coolest thing about being a contractor is that you can be your own boss. You set your own schedule, work from where you want, and don’t technically have to wear pants a lot of the time. Maybe this is less of a big deal than it used to be thanks to the ‘rona but it is definitely something I value a lot.&lt;/p&gt;

&lt;p&gt;Of course in the end, everyone has a boss, you can’t escape from it. The CEO has to answer to the board and investors, the investors have to answer to their partners, the partners have to answer to funds, and so on. Your boss is now the client, since they’re the one cutting your checks now.&lt;/p&gt;

&lt;p&gt;In my experience this has been a good thing. I can report honestly that I’ve enjoyed working with 100% of my past and present clients and things have on the whole gone very smoothly. Much of it comes down to choosing your clients. You will turn some people down because they are looking for someone with different skills, don’t pay enough, have a Million Dollar App Idea I Just Need Someone To Build It, are unprofessional, or just not cut out for the whole business thing. Just don’t work for these people. It’s okay to turn down work and it’s okay to fire your client as long as you’re not breaking contract obligations. Always act professionally though, no matter what situation you find yourself in. Your reputation absolutely follows you around, and taking pride in your work and professionalism is a requirement for being a freelancer.&lt;/p&gt;

&lt;p&gt;Another skill that you must be consciously aware of and always seeking to improve is communication. Being direct, open, and transparent with your clients can often mean the difference between a successful project and one that ends up in a mess of assumptions and bad feelings. Underpromise and overdeliver is the mantra. Over-communicate, bring any concerns about the project to the fore, have regularly scheduled progress meetings when applicable, and do demos for your client. Focus on delivering something visible, something the client can look at and play with, so you can get feedback early. There will almost always be some gray area between what your client has in their mind and what you envision in your own, not just in designs but in all the details in the details.&lt;/p&gt;

&lt;p&gt;Sometimes a client may come to you with detailed designs and specifications, but I’ve never been in a situation where all the information needed to deliver a project was hashed out up front. Most of the time very little of it is. You need to establish a good two-way street of communication and always be asking for feedback and clarification of ambiguities. Get a MVP in their hands as early as possible and iterate on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Skills
&lt;/h3&gt;

&lt;p&gt;Consider also what skills you can bring besides just writing code. Familiarity and expertise in UX and design is very valuable and basically a requirement for most software jobs these days. We’ve had clients come to us to help them perform due diligence on codebases of companies that they are considering acquiring. We’ve performed security audits on codebases, sometimes unbidden. And thanks to our extensive commercial experience building successful companies we also can provide valuable consulting services on marketing, sales and raising capital.&lt;/p&gt;

&lt;p&gt;Whatever extra you can bring to the table for your clients be sure to market it and build up your experience and knowledge in that area. It can make the difference between being just another coder and a valuable partner to your client.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i0.wp.com/spiegelmock.com/wp-content/uploads/2020/10/2013-02-15-14.01.31.jpeg?ssl=1"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LzNv8MrV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i0.wp.com/spiegelmock.com/wp-content/uploads/2020/10/2013-02-15-14.01.31.jpeg%3Fresize%3D640%252C480%26ssl%3D1" alt=""&gt;&lt;/a&gt;Working on three laptops at once can be a valuable skill.&lt;/p&gt;

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

&lt;p&gt;For many contractor-curious folks getting started may be scary or daunting.&lt;/p&gt;

&lt;p&gt;If you’re a full-time employee, becoming a contractor means giving up some job security. You may not have a guaranteed paycheck for a while, if ever. Being a contractor, especially if you’re starting out and doing it alone, brings many uncertainties. However working as a full-time employee carries its own sort of risks. Job security isn’t what it used to be, spending time on bureaucracy and pleasing your superiors may not make you fulfilled, and there’s a real limit to how much you can accomplish for yourself as part of a larger organization.&lt;/p&gt;

&lt;p&gt;There is comfort in working at a company; all you have to do is show up and be told what to do, you don’t have to think much about taxes or contracts, someone else can make a lot of the decisions about how to run the company. But if you want to take on more responsibility, have the opportunity to grow and learn to run your own business, and do things your way then consider becoming a contractor. Almost everyone I know who works for a company of any size will be happy to tell you all about the mistakes and boneheaded ideas of their superiors. Everyone has ideas of how the company they work for could be run better. I say if you really believe this then work for yourself.&lt;/p&gt;

&lt;p&gt;So how to begin? You have two options: line up to your first gig, or join a company doing freelance work. You can put the word out to your network that you are available for work, or you can go look for jobs posted on sites like Upwork. There are also companies that specialize in doing contract work and are often looking for contractors to augment their pool of developers. If you go this route know that such companies may not always have work immediately lined up for you, but they may be happy to interview you and keep you on file in case some work comes up that matches your qualifications.&lt;/p&gt;

&lt;p&gt;My suggestion is to do both; look at what’s out there, get a feel for what people are looking for and how much they’re offering and also check out companies that are doing the kind of contracting work you’re interested in and offer your services to them. There certainly is no shortage of work and job opportunities out there for contractors, it’s more a matter of finding a good fit for you that will be engaging work and well-compensated. Even if you start with some small simple jobs, they can definitely lead to greater opportunities as you gain more confidence, experience, references, and a better understanding of the market.&lt;/p&gt;

&lt;p&gt;I would of course be remiss as a small business owner if I did not mention that our consulting company &lt;a href="https://jetbridge.com/"&gt;JetBridge&lt;/a&gt; is always looking for smart and talented engineers. If you’re thinking of becoming a contractor, feel free to &lt;a href="//mailto:mischa@jetbridge.com"&gt;drop me a line&lt;/a&gt;, and I might be able to help you get started or refer you to other work out there. I know it can be an intimidating career jump, but it can be extremely rewarding and full of new opportunities as well. And if the current tech bubble happens to pop again someday, it just might be a great time to try something new.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://spiegelmock.com/2020/10/20/is-software-contracting-for-you/"&gt;Is Software Contracting For You?&lt;/a&gt; appeared first on &lt;a href="https://spiegelmock.com"&gt;Mischa Spiegelmock&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>software</category>
    </item>
    <item>
      <title>AWS Lambda Deep Dive</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Fri, 28 Aug 2020 13:28:38 +0000</pubDate>
      <link>https://dev.to/cybermischa/aws-lambda-deep-dive-5cp9</link>
      <guid>https://dev.to/cybermischa/aws-lambda-deep-dive-5cp9</guid>
      <description>&lt;p&gt;A brief history lesson about serving web applications, followed by an in-depth look at Functions as a Service on AWS using Lambda.&lt;br&gt;
• Lambda REST API&lt;br&gt;
• How functions are created and invoked&lt;br&gt;
• Connecting to HTTP events with API Gateway&lt;br&gt;
• Limitations&lt;br&gt;
• Custom runtimes&lt;br&gt;
• How layers work&lt;/p&gt;

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

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>serverless</category>
      <category>faas</category>
    </item>
    <item>
      <title>Basics of Sockets</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Fri, 28 Aug 2020 13:26:44 +0000</pubDate>
      <link>https://dev.to/cybermischa/basics-of-sockets-5fhc</link>
      <guid>https://dev.to/cybermischa/basics-of-sockets-5fhc</guid>
      <description>&lt;p&gt;A deep dive into files and sockets, TCP and UDP, on UNIX.&lt;/p&gt;

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

</description>
      <category>sockets</category>
      <category>unix</category>
      <category>tcp</category>
      <category>udp</category>
    </item>
    <item>
      <title>Communication Tips for Engineers</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Tue, 04 Aug 2020 09:55:00 +0000</pubDate>
      <link>https://dev.to/cybermischa/communication-tips-for-engineers-2e38</link>
      <guid>https://dev.to/cybermischa/communication-tips-for-engineers-2e38</guid>
      <description>&lt;p&gt;Communication is a fundamental skill for engineers. No one builds anything on their own. Whether participating in an open-source project or being employed to crank out code, you need to work with others. The value of effective communication skills cannot be overstated.&lt;/p&gt;

&lt;p&gt;Even Linus Torvalds, a curmudgeon who will never lack work and whose word is law in the Linux community, has &lt;a href="https://www.bbc.com/news/technology-45664640"&gt;acknowledged&lt;/a&gt; the need to be more measured in his criticisms and more generous with empathy.&lt;/p&gt;

&lt;p&gt;Soft skills, in the parlance of our times, are in vogue. Employers and potential collaborators will judge you based on your ability to lucidly communicate your thoughts in an agreeable and succinct fashion.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qvem4puP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y8f793q45y1t4rz4si5u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qvem4puP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/y8f793q45y1t4rz4si5u.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CareerBuilder also found in this survey that eighty percent of hirers said that soft skills would be equally or more important than hard skills.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are many great guides and books written about how to communicate effectively with other human beings. A lot centers around having empathy. Having an understanding of where someone is coming from, considering the information that they have that you don't or vice-versa, and being respectful are basic tenets. I offer a few suggestions here:&lt;/p&gt;

&lt;h2&gt;
  
  
  Use interrogatives instead of declarations
&lt;/h2&gt;

&lt;p&gt;Even when you are pretty sure of a fact you want to communicate to someone else, it is often better phrased as a question rather than a statement of fact.&lt;/p&gt;

&lt;p&gt;"Why did you write it this way?" is infinitely preferable to "this code is wrong."&lt;/p&gt;

&lt;p&gt;If discussing a solution or implementation with someone, ask them what they think first, regardless if you already have a plan in your head. They may suggest what you are already thinking, may have thought about things you haven't, and may bring up other good ideas. Especially for junior people; it helps them engage their critical thinking skills instead of learning to rely on you to provide the answer. It gives people more ownership and desire to defend their idea because it's theirs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't argue forever over things
&lt;/h2&gt;

&lt;p&gt;This is one I am especially guilty of, and it has to do with knowing when to concede a technical argument. Very often there are no clear right answers for how to proceed with a feature or fix, and a healthy discussion of the tradeoffs can be illuminating and help arrive at a reasonable solution.&lt;/p&gt;

&lt;p&gt;However since many tradeoff estimations involve a lot of guesswork and feelings and intuition, the "best" answer may never be agreed on. At some point you have to agree and move forward, and different people may have ideas of when that time has passed. I know I've driven at least one person crazy by continuing past the point they considered to be entering the domain of diminishing returns.&lt;/p&gt;

&lt;p&gt;Often the proper solution isn't clear. Agreeing on a proposal, prototyping, and gathering more data is more fruitful than making people exasperated or arguing for hours. Once you sit down to actually try it, it may quickly resolve the debate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try to not talk too much shit on other people's code
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Oho!" said the pot to the kettle; "You are dirty and ugly and black! Sure no one would think you were metal, Except when you're given a crack."&lt;/p&gt;

&lt;p&gt;"Not so! not so!" kettle said to the pot; "'Tis your own dirty image you see; For I am so clean – without blemish or blot – That your blackness is mirrored in me."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If there's one thing engineers love to do it's complain about languages, libraries, tools, operating systems, service providers, interfaces, APIs, containerization systems, people on mailing lists, etc… When your tools don't work right it can cause you hours of frustration and confusion, which nobody enjoys.&lt;/p&gt;

&lt;p&gt;A moment's contemplation will recollect the vast amount of sub-standard, buggy, hacked together balls of mud that the experienced engineer has thrown together in the past. If you write perfect defect-free code then you should continue with your expressions of distaste for the inferior engineers out there making fools of themselves. If on the other hand, you realize you have made plenty of blunders of your own, consider going easy on the target of your ire.&lt;/p&gt;

&lt;p&gt;I've seen many online communities devolve into an ever-smaller group of grumpy guys, mostly chatting about how much everyone else is stupid and sucks. These communities sap your soul. Inject some positivity into your world when you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communicate proactively
&lt;/h2&gt;

&lt;p&gt;People aren't mind readers and they generally are focused on their own work and problems. If you have information that may be useful to others, don't wait for them to come to you and ask for it. If someone hasn't asked you for an update or provided you with what you need, reach out rather than suffering in silence.&lt;/p&gt;

&lt;p&gt;Over-communicating in a team is almost always better than under-communicating. By letting people know what you're doing you can help others prioritize, not duplicate work, know whom to ask questions, inform you if they're making changes that could affect your work, and reduce the need for people to make assumptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't assume
&lt;/h2&gt;

&lt;p&gt;Assumptions are frequently foolish and rarely right. Often a brief message can save you time, making sure you don't start off down a fruitless path. And by asking, you are communicating information about what you are working on and the fact that the knowledge you seek is not as widely shared or accessible as the owner of it may assume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment and document what you're doing and why
&lt;/h2&gt;

&lt;p&gt;Nothing makes working with code others have written go smoothly like having comments liberally sprinkled throughout the source code. Whether it's a new hire or yourself in two years when you've forgotten why you need to check that condition in that insane query, a brief summary of your logic and thinking at the time can help impart understanding and reduce the need for assumptions.&lt;/p&gt;




&lt;p&gt;The goal is clarity and unambiguous communication of ideas. People aren't mind readers and need a lot of information, some of which only you possess. &lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>communication</category>
    </item>
    <item>
      <title>Decentralizing Social Media</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Thu, 28 May 2020 09:49:41 +0000</pubDate>
      <link>https://dev.to/cybermischa/decentralizing-social-media-31e3</link>
      <guid>https://dev.to/cybermischa/decentralizing-social-media-31e3</guid>
      <description>&lt;h4&gt;
  
  
  No, it has nothing to do with blockchain.
&lt;/h4&gt;

&lt;p&gt;What kind of language should Facebook forbid? What kind of regulations should the U.S. government promogulate regarding whom Twitter can ban?&lt;/p&gt;

&lt;p&gt;☞ &lt;strong&gt;Who cares?? ☜&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Not me.&lt;/p&gt;

&lt;p&gt;A depressing amount of energy and ink is wasted on these questions which shouldn’t even be issues in the first place. We don’t have to base our public discourse on platforms that corporations or even governments control.&lt;/p&gt;

&lt;p&gt;The great news is that there does exist an alternative to the model of having all social media content go through a couple of companies. There is certainly no technical reason it should work that way, and there is a solution to the problem that has a foundation in technology, though there is naturally a social component as well.&lt;/p&gt;

&lt;p&gt;What is this problem that needs a solution? I think it’s fantastically illustrated by all of these articles and experts and laws being passed to try to nudge Facebook, Youtube, Twitter to control what people are allowed to say and post. Busybodies, Concerned Citizens, corrupt politicians, think tanks, your parents, all want to petition these platforms to decide what you should be able to read or write. I view this as a problem, because I don’t think anyone should decide for me what information I should be able to share or consume. Not Mark Zuckerberg, not Donald Trump, not Jack Dorsey, not my congressional representatives, not the People’s Republic of China.&lt;/p&gt;

&lt;p&gt;Government and private corporations in control of censorship are not the only problem here. As everyone knows these services are free, and as everyone also knows if the product is free then &lt;strong&gt;you&lt;/strong&gt; are the product. Facebook and Google make almost all of their money from extracting and mining as much personal data about you as possible to sell to advertisers, PR agencies, and politicians. There is a better way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Federated Social Media
&lt;/h2&gt;

&lt;p&gt;The answer is &lt;strong&gt;federation&lt;/strong&gt;. Decentralization. Distributed systems. You’re already familiar with the concept, just think of email. You don’t have an email username, you have an &lt;em&gt;address&lt;/em&gt;. Your email address is a username on a host – &lt;code&gt;mspiegelmock@gmail&lt;/code&gt;.&lt;code&gt;com&lt;/code&gt; specifies the user &lt;code&gt;mspiegelmock&lt;/code&gt; on the system &lt;code&gt;gmail.com&lt;/code&gt;. I can write an email to someone else like &lt;code&gt;rms@gnu.org&lt;/code&gt;, even if they don’t use gmail. I ask my provider &lt;code&gt;gmail.com&lt;/code&gt; to send a message to the &lt;code&gt;gnu.org&lt;/code&gt; host which is responsible for delivering it to the user &lt;code&gt;rms&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;No company “runs” email, yet all email servers know how to pass messages to each other. There is a vast array of different email hosts, providers, server applications and client apps. You can choose to sign up with a free provider like Google or Microsoft, your employer may provide you an account, or you can run your own server. You can use any sort of app you like with email, such as gmail.com, Apple Mail, Superhuman, Outlook, mutt, or emacs. In the earlier days of web-based mail there were a few options to choose from, like Yahoo and Hotmail, and eventually the company which provided the best user experience ended up grabbing a significant slice of email users, thanks to the wonders of competition. There were and are some issues with spam and malicious content to be sure, though a great amount of progress has been made on systems to combat it (spam and virus filters, real-time blacklists, DKIM/SPF). This is what federation looks like.&lt;/p&gt;

&lt;p&gt;To grasp the concept behind federated social media, think of email. You sign up for an account with an instance (“host”) that you feel comfortable with, or run your own if you’re so inclined.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GVr_dqep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-6.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GVr_dqep--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-6.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To follow someone you need their address, like &lt;a href="https://social.coop/@wooster"&gt;&lt;strong&gt;@wooster@social.coop&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Think Twitter, but as an email address. The address denotes the username (&lt;code&gt;@wooster&lt;/code&gt;) and the host the user is registered on (&lt;code&gt;social.coop&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;You have two timelines, in addition the people you follow. One timeline is the “local” timeline, which is everyone else on your instance. If you join an instance of people that share a particular hobby, language, interest, region or philosophy you get to start out with a feed that may have posts that may be relevant for you. Your instance can link, or “federate”, with other similar instances, connecting users on your instance with users on the other instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yILm_bGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yILm_bGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jTAlALcM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jTAlALcM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Moderation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UVfFqdJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-4.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UVfFqdJC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-4.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;Why not run a whitehouse.gov instance instead?&lt;/p&gt;

&lt;p&gt;Just because there is no central authority for content moderation doesn’t mean that the system is full of abuse and Those Sorts Of People you would like to avoid. These things exist to be sure, as they do on any platform, but they are confined to their own instances. Moderation does exist, but unlike Facebook or Twitter you can choose your moderators. Most instances have &lt;a href="https://blog.joinmastodon.org/2019/07/statement-on-gabs-fork-of-mastodon/"&gt;policies&lt;/a&gt; about what external content they block, what types of instances they want to federate with, and what kinds of content they permit. If you disagree with their policies, you are free to join an instance that fits with your preferences, or start your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LVgbh1Zb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-5.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LVgbh1Zb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-5.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;a href="https://joinmastodon.org/"&gt;&lt;/a&gt;&lt;a href="https://joinmastodon.org"&gt;https://joinmastodon.org&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are plenty of people I &lt;strong&gt;don’t&lt;/strong&gt; want to hear from, there are plenty of posts our there that would decrease my quality of life, and I’m fine with outsourcing some moderation. I just don’t want this guy to be the final arbiter of all information.&lt;/p&gt;



&lt;p&gt;Propaganda, trolls, abuse, and misinformation exist on every platform. You can find it on YouTube, LiveJournal, TikTok, Twitter, and no doubt on federated social media. Media literacy is an important skill that should be taught to help media consumers understand biases and distortions inherent in all media. A platform that helpfully provides fact-checking would be desirable to many users. But the fact remains that &lt;em&gt;you cannot outsource critical thinking&lt;/em&gt;. There’s no getting around this.&lt;/p&gt;

&lt;p&gt;The problem with top-down centralized structures that take it upon themselves to decide what information can or can not be spread should be plain. Corporations and politicians have bad incentives and the temptation to misuse such power to cover up misdeeds is too powerful for most to resist. We all know now what happened with Chernobyl and the misery caused by the suppression of information. Maybe if we had some supremely enlightened and benevolent information despot it would be okay to put them in charge, but I can’t really think of anyone I want to grant that authority over me.&lt;/p&gt;

&lt;p&gt;The instance I belong to is &lt;a href="https://social.coop/"&gt;social.coop&lt;/a&gt;, a social media cooperative. It’s a group of people who donate a small amount of money to pay for a server to host a Mastodon instance and volunteers who help maintain and administer it. There is an online forum for discussions and consensus-based decision-making, and a lot of smart people on it. This is just one example of the kind of self-organization that is possible in the fediverse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mastodon
&lt;/h2&gt;

&lt;p&gt;Today the most popular software for plugging into the federated social media network is Mastodon. It’s free (AGPL) and &lt;a href="https://github.com/tootsuite/mastodon"&gt;open source&lt;/a&gt; naturally, and there are a number of &lt;a href="https://joinmastodon.org/apps"&gt;apps&lt;/a&gt; you can use with it, including some slick paid apps. The Mastodon web interface looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X2uZoqBm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-9.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X2uZoqBm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-9.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the “Toot” app looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Msp4fR1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-10.png%3Fw%3D598" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Msp4fR1y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-10.png%3Fw%3D598" alt=""&gt;&lt;/a&gt;Toot for iOS&lt;/p&gt;

&lt;p&gt;Many communities run Mastodon instances, some are public, some are cooperatives, some are private. You don’t have to use Mastodon to talk to people using Mastodon, if you use software that speaks ActivityPub then you can follow, share, post, like, comment, and communicate with anyone else in the fediverse. Just like if you use any email software, you can email anyone else using email software, which I think is pretty neat.&lt;/p&gt;

&lt;p&gt;Mastodon is federated social media, federated social media is not Mastodon.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Details (ActivityPub)
&lt;/h2&gt;

&lt;p&gt;In the early days there were a &lt;a href="https://lwn.net/Articles/741218/"&gt;number of attempts&lt;/a&gt; at creating social networking protocols with really obnoxious names like “pubsubhubbub.” After a bit of experimentation an official standard was published by the World Wide Web Consortium (W3C) in 2018, going by the name &lt;a href="https://en.wikipedia.org/wiki/ActivityPub"&gt;ActivityPub&lt;/a&gt;. You may know the W3C from their earlier hits like HTML, CSS, XML, and SVG.&lt;/p&gt;

&lt;p&gt;As it’s an extremely recent standard, we’re still in the very early days of implementations. I expect there will be a number of libraries and clients popping up, along with not just standalone servers but server capabilities integrated into existing platforms and sites. Any site that lets you log in and post content could be modified to plug into the fediverse by implementing the relatively simple, JSON-based protocol. Your existing accounts could turn into ActivityPub &lt;a href="https://www.w3.org/TR/activitystreams-vocabulary/#actor-types"&gt;Actor objects&lt;/a&gt;. New social networks can in effect bootstrap themselves by leveraging existing users, software, and federation networks, and we’ll see companies and open source projects compete to offer the best user experience.&lt;/p&gt;

&lt;p&gt;Honestly the best way to learn about ActivityPub is to &lt;a href="https://www.w3.org/TR/activitypub/#Overview"&gt;go read the standard doc&lt;/a&gt;. It’s in plain English with friendly cartoons and very straightforward.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJO4_By7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.w3.org/TR/activitypub/illustration/tutorial-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJO4_By7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.w3.org/TR/activitypub/illustration/tutorial-2.png" alt="Actor with messages flowing from rest of world to inbox and from outbox to rest of world"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The very brief gist of it is that there is a client &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9kDwzwFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2194.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9kDwzwFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2194.png" alt="↔"&gt;&lt;/a&gt;︎ server protocol and a server &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9kDwzwFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2194.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9kDwzwFN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2194.png" alt="↔"&gt;&lt;/a&gt;︎ sever protocol, much like IRC. You can read notifications that arrive in your inbox and you can publish messages to the world via an outbox. All content and &lt;a href="https://www.w3.org/TR/activitystreams-vocabulary/#object-types"&gt;objects&lt;/a&gt; on the platform are simple JSON documents that live at a URL (an IRI to be precise). Technically you could make a compliant ActivityPub server with a static webserver (I think? Tell me if I’m wrong).&lt;/p&gt;

&lt;p&gt;Social media isn’t just text and image posts. The site &lt;a href="https://joinpeertube.org/"&gt;PeerTube&lt;/a&gt; is a decentralized version of YouTube:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NjGPANEH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-14.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NjGPANEH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-14.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;PeerTube is a free and open-source, decentralized, federated video platform powered by ActivityPub and WebTorrent, that uses peer-to-peer technology to reduce load on individual servers when viewing videos.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  User Base
&lt;/h2&gt;

&lt;p&gt;The network effect is what makes a social network attractive. The more people on it, the more useful it is. Having celebrities is a big draw for many people. It’s the biggest challenge that any challenger to the status quo faces.&lt;/p&gt;

&lt;p&gt;I believe there is nothing permanent about Facebook or Twitter. I remember when it was hard to imagine anything replacing MySpace, or when everyone on the Russian-speaking internet had a LiveJournal. Fads change and great masses of people move smoothly to new platforms with ever increasing rapidity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ssApj66y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-12.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ssApj66y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-12.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;a href="https://the-federation.info/"&gt;&lt;/a&gt;&lt;a href="https://the-federation.info/"&gt;https://the-federation.info/&lt;/a&gt; – Federation Stats&lt;/p&gt;

&lt;p&gt;The thing that is so powerful about a social media protocol is that it seems, at least to me, like the logical conclusion of social media. Once a growing critical mass of people move to it, either because they are sick of Facebook’s shit or some cool new company’s platform happens to be powered by ActivityPub, most of the innovation around communities, software, moderation, new forms of media, organization and technology can happen within the fediverse. Because of the open and extensible nature of the underlying foundation anyone can plug in a conformant piece of software and shape their piece of it how they want while still interoperating with the wider world. It’s a perfect vehicle in which one can imagine fictional visions of the future internet taking shape, like the Metaverse from Snowcrash or the VR Net from Otherland.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r-r4crxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-11.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r-r4crxr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-11.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;a href="https://pawoo.net/about"&gt;&lt;/a&gt;&lt;a href="https://pawoo.net"&gt;https://pawoo.net&lt;/a&gt; – Japanese Mastodon with 625,000 users and 45 million posts&lt;/p&gt;

&lt;p&gt;The internet is a decentralized collection of autonomous systems held together by communities defining standards and protocols. Distributed social media maps very nicely onto the architecture of the internet and promotes freedom of expression and experimentation with new forms of media, social organization, and technology. Doubtlessly it will create new problems as well, like intensifying the &lt;a href="https://spiegelmock.com/2018/07/10/the-internet-hypernormalization-effect/"&gt;internet hypernormalization effect&lt;/a&gt;. It will likely be some time before norms and robust community structures are figured out at scale. The ability for anyone to participate in the wider social community within bounds and parameters they set for themselves will be messier but ultimately more powerful and driven by more positive incentives than the current social media monopolists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;p&gt;If you want to give Mastodon a spin you can check out &lt;a href="https://joinmastodon.org/"&gt;joinmastodon.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To learn more about ActivityPub read the &lt;a href="https://www.w3.org/TR/activitypub/#Overview"&gt;spec&lt;/a&gt; (really, it’s not dry). More info about the types of Actors, Activities and Objects on ActivityPub can be found &lt;a href="https://www.w3.org/TR/activitystreams-vocabulary/#types"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://joinpeertube.org/"&gt;PeerTube homepage&lt;/a&gt; explaining federation of video content.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.joinmastodon.org/2018/12/why-does-decentralization-matter/"&gt;Why does decentralization matter&lt;/a&gt;? Mastodon op-ed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://the-federation.info/"&gt;The-federation.info&lt;/a&gt; – statistics and open source fediverse projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G2IN5JiG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-13.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G2IN5JiG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/05/image-13.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>activitypub</category>
      <category>mastodon</category>
      <category>fediverse</category>
    </item>
    <item>
      <title>WebAssembly, not only for browsers</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Thu, 21 May 2020 10:03:59 +0000</pubDate>
      <link>https://dev.to/cybermischa/webassembly-not-only-for-browsers-kii</link>
      <guid>https://dev.to/cybermischa/webassembly-not-only-for-browsers-kii</guid>
      <description>&lt;p&gt;Two great talks about WebAssembly, Rust, and WASI. Really recommend checking out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=fh9WXPu0hw8"&gt;Bringing WebAssembly outside the web with WASI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=CMB6AlE1QuI"&gt;Rust, WebAssembly, and the future of Serverless &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WASI (WebAssembly System Interface) provides a standard for interacting with OS-type facilities via system calls and the like. It is essentially about being able to run WASM anywhere, including on a desktop or server, not just the browser. Sooort of like node.js is for JavaScript but it works with any language that compiles to WASM. That is pretty much every language you might use except Haskell.&lt;/p&gt;

&lt;p&gt;I think WASM and WASI are the future and can and should replace node.js entirely. You can write code in (almost) any language and run it in the browser or on desktop/server/backend. Just like node, only not limited to JS. The isolation capabilities of WASI make it suitable for some applications where one might otherwise use docker.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>rust</category>
      <category>wasi</category>
    </item>
    <item>
      <title>Python 2020: Modern Best Practices</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Mon, 06 Jan 2020 17:55:14 +0000</pubDate>
      <link>https://dev.to/cybermischa/python-2020-modern-best-practices-187k</link>
      <guid>https://dev.to/cybermischa/python-2020-modern-best-practices-187k</guid>
      <description>&lt;p&gt;Python and related tooling continues to progress and evolve. I’d like to share some of the tools and practices we’re using at JetBridge to develop python web applications.&lt;/p&gt;

&lt;p&gt;This is by no means an exhaustive account or a definite list of all best practices, and I hope readers will share what’s working well for them so I can learn and incorporate that knowledge. I don’t know about everything out there but I can at least present a survey of what we’ve been using on multiple projects with success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python
&lt;/h2&gt;

&lt;p&gt;Let’s start with… python. As of January 1st, 2020 python 2 support was &lt;a href="https://www.python.org/doc/sunset-python-2/"&gt;officially discontinued&lt;/a&gt;. If you are still maintaining any python 2 code you are using the language equivalent of Windows XP. Not only is python 2 no longer receiving security updates but now all python module authors will feel comfortable dropping any support for python 2 in any future versions of their modules, which means your dependencies are unlikely to receive security updates as well. Using python 2 is now a legitimate security risk.&lt;/p&gt;

&lt;h4&gt;
  
  
  Python 3.8 is out. What’s new in it?
&lt;/h4&gt;

&lt;p&gt;The “walrus operator” &lt;code&gt;:=&lt;/code&gt; allows you &lt;a href="https://www.python.org/dev/peps/pep-0572/#syntax-and-semantics"&gt;to initialize a variable as part of any expression&lt;/a&gt; and save a line or two of code. The battle in PEP 572 over getting this operator included in the language was so unpleasant that it caused Guido van Rossum to &lt;a href="https://www.mail-archive.com/python-committers@python.org/msg05628.html"&gt;ragequit&lt;/a&gt; his Benevolent Dictator For Life of Python role.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;__pycache__&lt;/code&gt; directories are now managed out-of-tree so they stop polluting your deployments and source control.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.python.org/3/whatsnew/3.8.html#typing"&gt;New additions to python’s type system&lt;/a&gt; – &lt;code&gt;TypedDict&lt;/code&gt; lets you define the shape of a dictionary type, &lt;code&gt;Literal&lt;/code&gt; lets you easily construct literal value constraints such as for enumerated value options, and at long last we have built-in support for structural subtyping, also known as &lt;a href="https://www.python.org/dev/peps/pep-0544/"&gt;&lt;code&gt;Protocol&lt;/code&gt;s&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;F-string debug syntax – now instead of writing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print(f"blorp={blorp}")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;print(f"{blorp=}")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Which is terrific news for those of us who will continue using print statements to debug until the day we die.&lt;/p&gt;

&lt;p&gt;Python 3.9 is &lt;a href="https://www.python.org/dev/peps/pep-0596/"&gt;expected out in October 2020&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Linting and Formatting
&lt;/h2&gt;

&lt;p&gt;Keeping your code neat and formatted can really help with readability and enforcing a consistent style. The tooling can also help catch potential bugs or mistakes. Here’s what we’re using:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Flake8&lt;/strong&gt; – Classic Linting Tool
&lt;/h4&gt;

&lt;p&gt;Run as a pre-commit hook or in your CI flow. We suggest installing and enabling the plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pypi.org/project/flake8-docstrings/"&gt;flake8-docstrings&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/pep8-naming/"&gt;pep8-naming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/flake8-debugger/"&gt;flake8-debugger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;tox.ini&lt;/code&gt; configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[flake8]
ignore = E305,E402,E501,I101,I100,I201
max-line-length = 160
exclude = .git, __pycache__ ,build,dist,.serverless,node_modules,migrations,.venv,.bento
enable-extensions = pep8-naming,flake8-debugger,flake8-docstrings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Mypy – Type Checking
&lt;/h4&gt;

&lt;p&gt;Mypy performs the useful function of type-checking, to the extent one can in python. It does on some occasions catch useful errors for you and is improving as time goes on. Still, the usefulness of python’s bolted-on type system afterthought is limited compared to say, any other typed language.&lt;/p&gt;

&lt;p&gt;If you are adding it to an existing project with many dependencies you may need to add &lt;code&gt;ignore_missing_imports = True&lt;/code&gt; to your &lt;code&gt;mypy.ini&lt;/code&gt; configuration file until you can resolve all of the warnings you’re going to get.&lt;/p&gt;

&lt;h4&gt;
  
  
  Bento – Static Analysis
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://pypi.org/project/bento-cli/"&gt;Bento&lt;/a&gt; is a very new tool that attempts to be sort of a meta-linter, combining a number of different checker tools into one, most notably &lt;a href="https://pypi.org/project/bandit/"&gt;Bandit&lt;/a&gt;, a “Security oriented static analyser for python code.” It’s designed to integrate into git hooks and CI workflows relatively easily. It’s still quite new and not super mature yet but this is definitely a tool to keep your eye on. The analysis engines are open source and provided for free, though the company behind it is working to offer paid features for larger teams.&lt;/p&gt;

&lt;h4&gt;
  
  
  Black – Formatting
&lt;/h4&gt;

&lt;p&gt;Black is a brutal and fantastic code formatter, much like &lt;code&gt;prettier&lt;/code&gt; for python. It can be run as a pre-commit hook to make sure your code is formatted correctly, or you can have your editor run it automatically on save (my preference). It is technically possible to modify the formatting rules but there is no reason you should ever do that. Just enable it, always run it on every changed file, and never worry about 97% of code formatting issues ever again.&lt;/p&gt;

&lt;h4&gt;
  
  
  Workflow Integration
&lt;/h4&gt;

&lt;p&gt;People are of differing opinions on whether you should add these tools into your editor, git hooks, or CI pipeline. Personally I have all of these tools hooked into my editor (mostly spacemacs but giving PyCharm a try) and love having my code formatted upon saving and seeing type errors inline in my code. This is definitely the best way to develop but it doesn’t enforce any standards in your team. Maybe you can always expect the people working on your project to have their editors configured correctly but this is mostly unrealistic for most teams.&lt;/p&gt;

&lt;p&gt;You can add it as a pre-commit (or pre-push) git hook, which ensures everything is run before it goes to CI. The downside is this can add extra setup steps for the project or greatly increased execution time for common git commands.&lt;/p&gt;

&lt;p&gt;Another option is to run all of your checks in CI and let developers be responsible for committing code that is correct or suffer failed tests. I have CircleCI &lt;a href="https://github.com/jetbridge/jetkit-flask/blob/e3fc3448933ffbfb573cc1dfc873364cd17d4aca/.circleci/config.yml"&gt;configured&lt;/a&gt; to install dependencies and then run the checks as separate jobs in parallel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q1RP4SiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/01/screen-shot-2020-01-03-at-9.10.26-pm.png%3Fw%3D1024" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q1RP4SiO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://spiegelmock.files.wordpress.com/2020/01/screen-shot-2020-01-03-at-9.10.26-pm.png%3Fw%3D1024" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And these options are not mutually exclusive. You can totally do all three together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Switching away from &lt;code&gt;unittest.TestCase&lt;/code&gt; and lots of custom helper functions to create objects in favor of pytest &lt;a href="https://docs.pytest.org/en/latest/fixture.html"&gt;fixtures&lt;/a&gt; and &lt;a href="https://factoryboy.readthedocs.io/en/latest/"&gt;factoryboy&lt;/a&gt; made testing vastly more pleasant, especially when writing tests that talk to the database.&lt;/p&gt;

&lt;p&gt;Our setup for writing tests that interact with Flask and SQLAlchemy is to set up fixtures with &lt;a href="https://factoryboy.readthedocs.io/"&gt;factoryboy&lt;/a&gt; which helps you declaratively write fixture factories for all your database models and &lt;a href="https://github.com/pytest-dev/pytest-factoryboy"&gt;pytest-factoryboy&lt;/a&gt; which lets you register your factories as pytest fixtures. The plugin &lt;a href="https://pypi.org/project/pytest-postgresql/"&gt;pytest-postgresql&lt;/a&gt; allows easy creation of a PostgreSQL database for running tests and &lt;a href="https://pypi.org/project/pytest-flask-sqlalchemy/"&gt;pytest-flask-sqlalchemy&lt;/a&gt; patches in a mocked database session (or sessionmaker or engine if you need them) during tests that ensures each test runs in a subtransaction. Subtransactions (aka &lt;code&gt;SAVEPOINT&lt;/code&gt;) allow you to run each test isolated in its own transaction and all changes are rolled back at the end of the test. This allows each test to be invisible to any other test or transaction and also to have all database changes cleaned up automatically. This is the most efficient way to run database tests with a high degree of reproducibility to how your application will be running for real.&lt;/p&gt;

&lt;p&gt;There are a lot of pieces here but they fit together beautifully in the end. Your test setup may look something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;myapp/db/fixture.py&lt;/code&gt; – where we like to define database factories. These can be used for populating development environments and tests with sample DB rows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;faker&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Factory&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;FakerFactory&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;factory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;jetkit.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;  &lt;span class="c1"&gt;# see https://github.com/jetbridge/jetkit-flask/blob/e3fc3448933ffbfb573cc1dfc873364cd17d4aca/jetkit/db/__init__.py#L10
&lt;/span&gt;
&lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FakerFactory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FakerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SQLAFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alchemy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SQLAlchemyModelFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Use a scoped session when creating factory models."""&lt;/span&gt;

    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="c1"&gt;# by providing access to our current sqlalchemy session the factory can automatically 
&lt;/span&gt;        &lt;span class="c1"&gt;# add newly-created objects to the session (i.e. insert into the DB)
&lt;/span&gt;        &lt;span class="n"&gt;sqlalchemy_session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserFactoryFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SQLAFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Base class for user factories with common fields."""&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;abstract&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;dob&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LazyAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;simple_profile&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s"&gt;"birthdate"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LazyAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'my-default-pw!'&lt;/span&gt;
    &lt;span class="n"&gt;avatar_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LazyAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;f"https://placem.at/people?w=200&amp;amp;txt=0&amp;amp;random=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;randint&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="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NormalUserFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserFactoryFactory&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Create a user with type=Normal."""&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NormalUser&lt;/span&gt;

    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;f"normaluser.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;@example.com"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This sets us up with a factory that can produce &lt;code&gt;NormalUser&lt;/code&gt; objects. In our setup we use &lt;a href="https://docs.sqlalchemy.org/en/13/orm/inheritance.html"&gt;SQLAlchemy polymorphism&lt;/a&gt; to distinguish between different user types with different model classes and the &lt;code&gt;UserFactoryFactory&lt;/code&gt; (how very enterprise) gives us a base class to quickly define factories for each type of user model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;myapp/test/conftest.py&lt;/code&gt; – place to add fixtures made available to your tests. Documentation on these fixtures is provided &lt;a href="https://pypi.org/project/pytest-flask-sqlalchemy/#configuration"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp.db.fixtures&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;NormalUserFactory&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pytest_factoryboy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;register&lt;/span&gt;

&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NormalUserFactory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;register&lt;/code&gt; helper function takes our factory and creates two pytest fixtures out of it. One fixture will be called &lt;code&gt;normal_user&lt;/code&gt; which will always return a user object in our DB session, created on demand once per test. The other fixture will be &lt;code&gt;normal_user_factory&lt;/code&gt; which will accept arguments to override the factory defaults.&lt;/p&gt;

&lt;p&gt;Next we set up fixtures for &lt;code&gt;database&lt;/code&gt;, &lt;code&gt;app&lt;/code&gt;, and our DB session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"session"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Create a Postgres database for the tests, and drop it when the tests are done."""&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;DatabaseJanitor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DB_USER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DB_HOST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DB_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DB_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DB_VERSION&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This provides a new database for the entire test session – it’s only created once and dropped when everything is finished.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"session"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;database&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Create a Flask app context for tests."""&lt;/span&gt;
    &lt;span class="c1"&gt;# here we pass in config overrides to our create_app
&lt;/span&gt;    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SQLALCHEMY_DATABASE_URI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DB_CONN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TESTING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_context&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above code provides us with a Flask app and context for the duration of the entire test session. You can push a new context for each test if you like (remove the &lt;code&gt;scope&lt;/code&gt; fixture argument) but I’ve never needed to do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"session"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Provide the transactional fixtures with access to the database via a Flask-SQLAlchemy database connection."""&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is the magic hook to provide our database session to &lt;code&gt;pytest-flask-sqlalchemy&lt;/code&gt;. We need to provide the package of our SQLAlchemy instance to our pytest configuration in &lt;code&gt;tox.ini&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[pytest]
# mock sqlalchemy database session during testing
mocked-sessions = myapp.db.db.session
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can define a fixture for a HTTP client to talk to our app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal_user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# get flask test client
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;normal_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# set environ http header to authenticate user
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ_base&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"HTTP_AUTHORIZATION"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;f"Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This fixture has a dependency on two other fixtures; &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;normal_user&lt;/code&gt;. We defined the &lt;code&gt;app&lt;/code&gt; fixture just above, and the &lt;code&gt;normal_user&lt;/code&gt; fixture is automatically added for us by the &lt;code&gt;pytest_factoryboy&lt;/code&gt; &lt;code&gt;register&lt;/code&gt; helper.&lt;/p&gt;

&lt;p&gt;So now that we have a &lt;code&gt;client&lt;/code&gt; fixture and a &lt;code&gt;normal_user&lt;/code&gt; fixture, we can write very straightforward tests for API calls. Suppose we want to test a user API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal_user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# get flask test client
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;test_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;identity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;normal_user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# set environ http header to authenticate user
&lt;/span&gt;    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ_base&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"HTTP_AUTHORIZATION"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;f"Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The simplicity and compactness of this test is striking. We don’t have any test cases, we define our dependencies in the function arguments, we use straightforward &lt;code&gt;assert&lt;/code&gt; statements to check our responses. The test runs in an isolated subtransaction, dependency injection is performed to load the complete dependencies for this particular test, and it couldn’t possibly be any cleaner.&lt;/p&gt;

&lt;p&gt;If you’re curious why we’re doing a simple &lt;code&gt;assert&lt;/code&gt; here and not something like &lt;code&gt;self.assertEqual()&lt;/code&gt; the answer is that pytest overrides the built in &lt;code&gt;assert&lt;/code&gt; function with a more test-friendly and powerful version. You will still receive output exactly as you would expect from any test framework if the assertion fails. See the &lt;a href="https://docs.pytest.org/en/latest/assert.html#assert"&gt;pytest documentation&lt;/a&gt; for more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Virtual Environments ﹠ Dependencies
&lt;/h2&gt;

&lt;p&gt;The most modern tool for managing dependencies and virtual environments is &lt;a href="https://github.com/pypa/pipenv"&gt;Pipenv&lt;/a&gt;. It’s a bit more &lt;code&gt;npm&lt;/code&gt;-style than &lt;code&gt;venv&lt;/code&gt; or &lt;code&gt;virtualenvwrapper&lt;/code&gt;, with a lockfile, split dev dependencies, and environment management via command line instead of sourcing anything in your shell. It saves the virtual environment files away out of tree.&lt;/p&gt;

&lt;p&gt;The downsides for Pipenv are that it is frankly super slow and there hasn’t been an official release in over a year despite very active development. I hope that a faster new release will come out sometime soon.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/pypa/pipfile"&gt;Pipfiles are the future&lt;/a&gt;, no reason to be using requirements.txt anymore.&lt;/p&gt;

&lt;p&gt;One more feature that may be of interest to some is the ability to define multiple sources in a Pipfile. If you have certain dependencies that need to be pulled from an internal package index server for example, you can &lt;a href="https://pipenv.kennethreitz.org/en/latest/advanced/#specifying-package-indexes"&gt;define that source for only those dependencies&lt;/a&gt; instead of having to globally change your &lt;code&gt;pypi&lt;/code&gt; mirror.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web Framework
&lt;/h2&gt;

&lt;p&gt;Some of the popular modern web frameworks are &lt;a href="https://www.djangoproject.com/"&gt;Django&lt;/a&gt;, &lt;a href="https://www.palletsprojects.com/p/flask/"&gt;Flask&lt;/a&gt;, and &lt;a href="https://falcon.readthedocs.io/en/stable/"&gt;Falcon&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Django
&lt;/h4&gt;

&lt;p&gt;Django is a pretty heavy solution but has the benefit of everything being set up for you. It’s not a tool I reach for because I normally only try to create lightweight API servers, with little to no server-side rendering of HTML, and I don’t find Django as suited to a serverless architecture as something more lightweight.&lt;/p&gt;

&lt;h4&gt;
  
  
  Flask
&lt;/h4&gt;

&lt;p&gt;Flask has been our go-to tool for years. It gives you a basic core into which you can plug in components and features as needed. The setup involved in creating the perfect enterprise-ready Flask app from scratch is considerable and takes some experience to get right on your own. The flexibility and ability to craft an application perfectly suited to your needs is invaluable for serious projects, and the simplicity and whipupitude makes it perfect for dead-simple services too.&lt;/p&gt;

&lt;p&gt;I’ve written at length about writing serverless web applications with Flask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/cybermischa/serverless-python-api-development-2jol-temp-slug-7099056"&gt;https://spiegelmock.com/2018/11/21/rapid-api-serverless-development/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cybermischa/serverless-python-web-applications-with-aws-lambda-and-flask-1jpf-temp-slug-2158608"&gt;https://spiegelmock.com/2018/09/06/serverless-python-web-applications-with-aws-lambda-and-flask/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Falcon
&lt;/h4&gt;

&lt;p&gt;If Flask is too heavy for you, there’s the Falcon microframework. If you’re writing a web service for a system with 64k of RAM and it’s not talking to any database or external services and the CPU overhead of handling HTTP requests and responses is the main bottleneck, Falcon may be a good choice. Their documentation really emphasizes how &lt;strong&gt;fast&lt;/strong&gt; it is. I don’t think your web framework is usually the primary concern when it comes to speed but doubtless there are situations where this is needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Digression: Request Globals
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;Digression&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There is one funky aspect of how Flask provides access to the current “app” context and the current request context that bothers or confuses some people. There exists an instance of your web application that contains configuration, routes, error handlers, and extensions that comprise your app. When your app is started up a new “&lt;a href="https://flask.palletsprojects.com/en/1.1.x/appcontext/"&gt;app context&lt;/a&gt;” is pushed onto the app context stack to keep track of what app is currently active:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;myapp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app_context&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;do_stuff_with_my_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In any code running inside of this context, you can access the current application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;current_app&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_stuff_with_my_app&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'SOME_KEY'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;What’s important here is that &lt;code&gt;current_app&lt;/code&gt; is a context variable proxy, which you can treat like a global variable but actually belongs to a context stack and is thread safe. Typically you only need to deal directly with pushing an app context if you’re writing scripts or wrappers that utilize your Flask app instance.&lt;/p&gt;

&lt;p&gt;A similar approach is used for the current &lt;a href="https://flask.palletsprojects.com/en/1.1.x/reqcontext/"&gt;request context&lt;/a&gt;. When your Flask app is running (inside an app context) and a new request comes in, a new request context is pushed onto the request context stack to keep track of the request and request-local variables.&lt;/p&gt;

&lt;p&gt;So whereas in many web frameworks like node’s Express you get passed in &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; objects as part of your handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&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;Or in python’s Falcon:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;falcon&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;on_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;falcon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In Flask one might write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;
&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;app_index&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again, &lt;code&gt;request&lt;/code&gt; looks somewhat like a global variable but in reality it is a &lt;a href="https://werkzeug.palletsprojects.com/en/0.16.x/local/#werkzeug.local.LocalProxy"&gt;proxy object&lt;/a&gt; to a thread-local object on a context stack. The request is pushed automatically for you by Flask when the request comes in, so you mostly don’t have to know or care about manipulating this stack, unless you are writing some of the more exotic kinds of test cases.&lt;/p&gt;

&lt;p&gt;This global-seeming access to context may feel dirty to some, likely conditioned by a healthy aversion to global variables or “&lt;a href="https://en.wikipedia.org/wiki/God_object"&gt;god-objects&lt;/a&gt;” because of thread safety issues, poor code organization, and the inability to grapple with multiple instances of such objects simultaneously in the same program. These are valid concerns that the &lt;a href="https://werkzeug.palletsprojects.com/en/0.16.x/local/#werkzeug.local.LocalProxy"&gt;LocalProxy&lt;/a&gt; objects and context stacks effectively mitigate, while still providing a simple and convenient method to access the instances as needed from anywhere in your codebase, with the only caveat that you are responsible for pushing an app context if you are doing something outside the normal request flow.&lt;/p&gt;

&lt;p&gt;I confess that the appeal of this approach was not obvious to me until I tried building a Flask app that talked to a database without using the &lt;a href="https://flask-sqlalchemy.palletsprojects.com/"&gt;Flask-SQLAlchemy&lt;/a&gt; extension. This extension integrates &lt;a href="https://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; (an ORM) sessions with the Flask contexts so you can always easily access a database session that is local to the current request and transaction, or linked to your app context if not inside a request.&lt;/p&gt;

&lt;p&gt;The real value of these context variables comes when you try to modularize your code and database routines. One problem that this solves is when you have a database transaction started inside a request, and then you call into some other code which may call other code which performs queries that should be inside the same transaction, as in a typical atomic operation that a RESTful endpoint might do. Somewhere you must retain a database handle to this operation, and expecting it to be passed through every function that might conceivably call another function that might perform a query is not feasible or clean. Being able to simply import a database session object that is automatically scoped to the finest level of application work you are performing (i.e. to the current request, or not) and assume it belongs to the current database transaction is a truly simple and elegant solution.&lt;/p&gt;

&lt;p&gt;This approach has been recognized as a useful tool and in fact in python 3.7 gained first-class support in the form of &lt;a href="https://docs.python.org/3/library/contextvars.html"&gt;contextvars&lt;/a&gt; from &lt;a href="https://www.python.org/dev/peps/pep-0567/"&gt;PEP 567&lt;/a&gt;. Opinions certainly may differ on the purity and magical-ness of this mechanism but I consider the simplicity and accessibility it affords to be the stronger argument. And given that it is now enshrined in python core means it is unlikely to go away anytime soon.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;/Digression&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Putting Into Practice
&lt;/h2&gt;

&lt;p&gt;If some of these ideas sound just splendid to you and you want to try them out, by all means give them a spin. If you’re looking to incrementally adopt new tools and features to your codebase implementing each of these suggestions independently should be manageable. However if you’re starting a new project or want to maximally embrace JetBridge style, it’s a daunting task to configure and wire up all of these practices into a well-organized and clean template. Honestly, setting up the database tests and Flask extensions is tedious. I’m lazy and don’t feel like doing it for new projects. That’s why we’ve created an open-source app starter kit and utility library for rapidly building modern, enterprise-ready python web applications with all of these practices and many more baked in and ready to go. Sort of a Create-React-App (&lt;a href="https://github.com/jetbridge/create-react-app"&gt;we have one of those too&lt;/a&gt;) for our very opinionated python web service setup where we can put these recommendations into practice and save ourselves time setting up each new service.&lt;/p&gt;

&lt;h4&gt;
  
  
  sls-flask
&lt;/h4&gt;

&lt;p&gt;Our starter kit is called &lt;code&gt;sls-flask&lt;/code&gt;. It generates a Flask app skeleton with pytest fixtures, RESTful APIs and serialization, database factories, linting, authentication and more in a serverless-first package. It utilizes our handy &lt;code&gt;JetKit-Flask&lt;/code&gt; python library that provides common database utilities (soft delete, upsert, UUIDs), S3 asset support, starting points for authentication and user access and other bits of functionality we’ve found useful in many projects.&lt;/p&gt;

</description>
      <category>software</category>
    </item>
    <item>
      <title>Serverless WebSockets</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Mon, 05 Aug 2019 21:51:40 +0000</pubDate>
      <link>https://dev.to/cybermischa/serverless-websockets-5acd</link>
      <guid>https://dev.to/cybermischa/serverless-websockets-5acd</guid>
      <description>&lt;p&gt;I wrote about how to set up fully serverless WebSockets&lt;br&gt;
&lt;a href="https://spiegelmock.com/2019/08/02/serverless-websockets/"&gt;https://spiegelmock.com/2019/08/02/serverless-websockets/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>websockets</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Web Application Boring Stack</title>
      <dc:creator>Mischa Spiegelmock</dc:creator>
      <pubDate>Thu, 18 Jul 2019 08:54:59 +0000</pubDate>
      <link>https://dev.to/cybermischa/web-application-software-stack-2019-edition-3c30</link>
      <guid>https://dev.to/cybermischa/web-application-software-stack-2019-edition-3c30</guid>
      <description>&lt;p&gt;At &lt;a href="https://jetbridge.com"&gt;JetBridge&lt;/a&gt; we enjoy developing software applications with our clients that we can take pride in while expanding our areas of knowledge and expertise at the same time. Because we are frequently starting on new projects we have standardized on a harmonious and expressive set of tools and libraries and frameworks to help us rapidly lift off new applications and deliver as much value as we can with minimal repetition.&lt;/p&gt;

&lt;p&gt;Our setup isn't perfect or the end-all stack for every project, but it's something we've evolved over years and it works quite well for us. We continue to learn about new tools and techniques and evolve our workflow so consider this more of a snapshot in time. If you aren't reading this in July of 2019 then we have probably modified at least some parts of the stack.&lt;/p&gt;

&lt;h3&gt;Methodology&lt;/h3&gt;

&lt;p&gt;Our theory of software development is: don't overcomplicate things.&lt;/p&gt;

&lt;p&gt;Pragmatism and business value are the overriding concerns, not the latest and coolest and hippest frameworks or tech. We love playing with new cool stuff as much as any geek but we don't believe in using something new just for the sake of being new or feeling unhip. Maturity and support should factor into deciding on a library or framework to base your application on, as should maintainability, community, available documentation and support, and of course what actual value it brings for us and our clients.&lt;/p&gt;

&lt;p&gt;There is a tendency a lot of engineers have to make software more complex than it needs to be. To use non-standard tools when widely available and known tools exist that might already do the job. To try to shoehorn some neat piece of tech someone read about on Hacker News into something it isn't really suited for. To depend on extra external services when there are already existing services that can be extended to perform the desired task. Using something too low-level when more abstraction would really simplify things, or using something too fancy and complicated when a simple system-level tool or language would accomplish things more expediently. &lt;/p&gt;

&lt;p&gt;Simplicity is a strategy that when used wisely can greatly increase your code readability and maintainability, as well as result in easy to manage operational environments.&lt;/p&gt;

&lt;h3&gt;Frontend&lt;/h3&gt;

&lt;p&gt;By the time I am writing this all frameworks and libraries we use have likely been superseded by cool new hip JS jams and you will sneer at our unfashionable choices. Nevertheless, this is what is working well for us today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React:&lt;/strong&gt; Vue may have more stars on GitHub but React is still the industry standard and is used and supported actively by Facebook among others. Writing apps with React hooks really feels like we are getting closer and closer to functional programming, adding a new level of composibility and code reuse that was clumsily achieved with HOCs before.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://material-ui.com"&gt;Material-UI&lt;/a&gt; for React is a toolkit that has almost every sort of widget and utility you might need, powerful theming and styling options, integrates CSS-in-JS very smoothly and looks solid out of the box. It is essentially an implementation of the UI paradigms promulgated by Google so working within its constraints and visual language gives you a good foundation. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create-React-App/react-scripts:&lt;/strong&gt; This really does everything you need and configures your new React app with sane defaults. You never need to monkey around with Webpack or HMR again. We have &lt;a href="https://github.com/jetbridge/create-react-app"&gt;extended&lt;/a&gt; CRA/r-s to spit out new frontend projects with extra ESlint and prettier options and Storybook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://storybook.js.org/"&gt;Storybook&lt;/a&gt;:&lt;/strong&gt; We prefer to build a component library of small and larger components implemented in isolation using mock data, rather than always coding and testing the layout and design inside the complete app. This allows UI devs to work without being blocked on completion of backend endpoints, helps to enforce the concept of reusable and self-contained components, and lets us preview the various interface states easily.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript:&lt;/strong&gt; Everyone uses TypeScript now because it's good and you should too. It does take some getting used to and learning how to use it properly with React and Redux requires some small amount of learning, but it's entirely worth it. Remember: you should never need to use &lt;code&gt;any&lt;/code&gt;. And when you think you need to use &lt;code&gt;any&lt;/code&gt; - you probably just need to add a type argument (generic).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESLint:&lt;/strong&gt; ESlint works great with TypeScript now! Don't forget to set &lt;code&gt; extends: ['plugin:@typescript-eslint/recommended', 'plugin:react/recommended', 'react-app']&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prettier:&lt;/strong&gt; Set up your editor to run Prettier on your code when you hit save. Not only does it enforce a consistent style, but it also means you can be way way lazier about formatting your code. Less typing but better formatting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redux: &lt;/strong&gt;Redux is nice... I guess. You do need some central place to store your user authentication info and stuff like that, and &lt;a href="https://github.com/rt2zz/redux-persist"&gt;redux-persist&lt;/a&gt; is super handy. In the spirit of keeping things simple though, really ask yourself if you need redux for what you're doing. Maybe you do, or maybe you can just use a hook or state instead. Sure maybe you think at first that you want to cache some API response in redux, but if you start adding server-side filtering or search or sorting, then it really is better off just as a simple API request inside your component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Async/await:&lt;/strong&gt; Stop using the Promise API! Catch exceptions in your UI components where you can actually present an error to the user rather than in your API layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Axios&lt;/strong&gt;: The HTTP client of choice. We use JWT for authentication and recommend our &lt;a href="https://www.npmjs.com/package/axios-jwt"&gt;axios-jwt interceptor module&lt;/a&gt; for taking care of token storage, authorization headers, and refresh.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't believe there's anything crazy or unusual here and that's sort of the point. Stick with what's standard unless you have a good reason not to.&lt;/p&gt;

&lt;h3&gt;Backend&lt;/h3&gt;

&lt;p&gt;Our backend services are always designed around the &lt;a href="https://12factor.net"&gt;12-factor app principles&lt;/a&gt; and always built to be cloud-native and when appropriate, &lt;a href="https://read.acloud.guru/serverless-is-a-state-of-mind-717ef2088b42"&gt;serverless&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Most projects involve setting up your typical REST API, talking to other services, and performing CRUD on a PostgreSQL DB. Our go-to stack is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.7. Python is clean, readable, has an impressively massive repository of community modules on PyPI, active core development, and a pretty good balance of high-level dynamic features without getting too obtuse or distracting. &lt;/li&gt;
&lt;li&gt;Type annotations and type linting with &lt;code&gt;&lt;a href="http://mypy.readthedocs.io/http://mypy-lang.org/"&gt;mypy&lt;/a&gt;&lt;/code&gt;. Python does have type annotations, but they are very limited, not well integrated, and not usually very useful for catching mistakes. I hope the situation improves because many errors have to be discovered at runtime in Python when compared with languages like TypeScript or Go. This is the biggest drawback to Python in my opinion, but we do our best with &lt;code&gt;mypy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://palletsprojects.com/p/flask/"&gt;Flask&lt;/a&gt;, a lightweight web application framework. Flask is very nicely suited to building REST APIs, providing just enough structure to your application for handling WSGI, configuration, database connections, reusable API handlers, tracing/debugging (with &lt;a href="https://aws.amazon.com/xray/"&gt;AWS X-Ray&lt;/a&gt;), logging, exception handling, authentication, and flexible URL routing. We don't lean on Flask for much besides providing the glue to hold everything together in a coherent application without imposing too much overhead or boilerplate.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.sqlalchemy.org"&gt;SQLAlchemy&lt;/a&gt; for declarative ORM. Has nice features for handling Postgres dialect features such as &lt;code&gt;UPSERT&lt;/code&gt; and &lt;code&gt;JSONB&lt;/code&gt;. Ability to compose mixins for model and query classes is very powerful and something we are using more and more for features like soft deletion. &lt;a href="https://docs.sqlalchemy.org/en/13/orm/inheritance.html#single-table-inheritance"&gt;Polymorphic subtypes&lt;/a&gt; are one of the most interesting SQLAlchemy features, allowing you to define a type discriminator column and instantiate appropriate model subclasses based on its value.&lt;/li&gt;
&lt;li&gt;Testing: &lt;a href="https://pypi.org/project/pytest-flask-sqlalchemy/"&gt;subtransactions wrapping each test&lt;/a&gt;, &lt;a href="https://pytest-factoryboy.readthedocs.io/en/latest/#model-fixture"&gt;pytest-factoryboy&lt;/a&gt; for generating fixtures from our model classes for pytest and for generating mock data for development environments. CircleCI. &lt;a href="https://docs.pytest.org/en/latest/fixture.html"&gt;Pytest fixtures&lt;/a&gt;. &lt;a href="https://flask.palletsprojects.com/en/1.1.x/testing/"&gt;Flask test client&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://flask-rest-api.readthedocs.io/en/stable/"&gt;Flask-REST-API&lt;/a&gt; with &lt;a href="https://marshmallow.readthedocs.io/en/3.0/"&gt;Marshmallow&lt;/a&gt; helps succinctly define REST endpoints and serialization and validation with a minimum of boilerplate, making heavy use of decorators for a declarative feel when appropriate. As a bonus it also generates OpenAPI spec documents and comes with Swagger-UI to automatically provide documentation of every API endpoint and its arguments and response shapes without any extra effort required.&lt;/li&gt;
&lt;li&gt;We are currently developing &lt;a href="https://github.com/jetbridge/flask-crud"&gt;Flask-CRUD&lt;/a&gt; to further reduce boilerplate in the common cases for CRUD APIs and mandating strict data model access control checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In projects that require it we can use Heroku or just EC2 for hosting but all of our recent projects have been straightforward enough to build as serverless applications. You can read about our setup and the benefits this brings us in more detail &lt;a href="https://spiegelmock.com/2018/11/21/rapid-api-serverless-development/"&gt;in this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have built a starter kit that ties together all of our backend pieces together in a powerful template to bootstrap new serverless Flask projects called &lt;a href="https://github.com/jetbridge/sls-flask/"&gt;sls-flask&lt;/a&gt;. If you're thinking of building a database-backed REST API in Python, give it a try! You get a lot of power and flexibility in a small bundle. There isn't anything particularly special or exotic included in it, but we believe the foundation it provides adds up to an extremely streamlined and modern development toolkit.&lt;/p&gt;

&lt;p&gt;All of our tooling and templates are open source, and we often contribute bug reports and fixes upstream to modules that we make use of. We encourage you to try out our stack or let us know what you're using if you're happy with what you're doing. &lt;a href="https://www.urbandictionary.com/define.php?term=share%20and%20enjoy"&gt;Share and enjoy&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>python</category>
      <category>react</category>
    </item>
  </channel>
</rss>
