<?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: Richard Keller</title>
    <description>The latest articles on DEV Community by Richard Keller (@_rich).</description>
    <link>https://dev.to/_rich</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%2F105961%2F54ca06d0-34f4-4493-9a9f-dac105cc7316.jpeg</url>
      <title>DEV Community: Richard Keller</title>
      <link>https://dev.to/_rich</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_rich"/>
    <language>en</language>
    <item>
      <title>Living Without Adobe Creative Suite as a Product Developer </title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Sat, 10 Aug 2019 14:32:49 +0000</pubDate>
      <link>https://dev.to/_rich/living-without-adobe-creative-suite-as-a-product-developer-2ep5</link>
      <guid>https://dev.to/_rich/living-without-adobe-creative-suite-as-a-product-developer-2ep5</guid>
      <description>&lt;p&gt;If you’re a digital product developer, you probably have Adobe software such as Photoshop and Illustrator. If you cannot live without Ubuntu as your OS, you probably don’t. Installing Adobe products on Ubuntu is a difficult process because Adobe doesn’t make Linux compatible software.&lt;/p&gt;

&lt;p&gt;Without the Adobe software suite, I have found other ways to create/modify graphics and wireframes using open source software, freemium software, and code.&lt;/p&gt;

&lt;p&gt;Here is a short collection of tools I have been using to replace the Adobe Suite. Some of these products are open source and some are paid subscriptions with free plans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whimsical.com
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Flow charts, mind maps, wireframes&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Whimsical is an amazing tool for creating wireframes, flow charts, and mind maps. Whimsical has enough wireframe features to build your design without being too complicated. The best part of this app is how intuitive it is to use. Coming from using Adobe products, Whimsical is intuitive enough to get started right away without needing any tutorials.&lt;/p&gt;

&lt;p&gt;In addition to wireframing, Whimsical allows you to create flow charts and mind maps with the same intuitive experience. This tool has been a great resource for me to design the initial prototypes of apps quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wireframes&lt;/li&gt;
&lt;li&gt;Flow charts&lt;/li&gt;
&lt;li&gt;Mind maps&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sketchpad.io
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Simple graphic design.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sketchpad.io is a decent web app for doing basic graphic design. Like Whimsical, it is very intuitive to use although there it can be buggy when using the zoom feature.&lt;/p&gt;

&lt;p&gt;Overall, it has enough features to design quick graphics. Notable featured include: Ease of use, amazing font selection, drop in images to artboards, and easy gradient overlaying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logo/graphic design&lt;/li&gt;
&lt;li&gt;Graphic experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gimp
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Advanced graphic design&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For the seriously advanced graphic design that rivals photoshop, Gimp is the goto software for Linux (or if you are on a tight budget). Gimp is open source software that can do pretty much every you would expect from professional graphic software. The catch with Gimp is that there is a learning curve. Gimp is available for all platforms: Linux, Windows, and OSX.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Advanced graphic design&lt;/li&gt;
&lt;li&gt;Logo design&lt;/li&gt;
&lt;li&gt;Photo editing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  PIL Python Image Library
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Image Editing with code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For simple image manipulation or image automation tasks, there is PIL (Python Image Library). PIL can be used to resize, filter, and crop images. Recently, I needed to make convert a white background into a transparent background. With PIL I did this with the following code:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Change a color to transparent&lt;/strong&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;PIL&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;color_to_transparent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'image.png'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'RGBA'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;datas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getdata&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;newData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;datas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;item&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="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;putdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NEW-image.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"PNG"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;img&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating multiple icon versions&lt;/li&gt;
&lt;li&gt;Color replacement&lt;/li&gt;
&lt;li&gt;Resizing + Cropping&lt;/li&gt;
&lt;li&gt;Automate image editing tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Inkscape
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Vector Graphics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Finally, there is Inkscape. Inkscape is open-source software that replaces Adobe Illustrator. The interface is not as polished as Adobe Illustrator, but after studying the interface for a bit of time, it becomes easy to use, especially if you are experienced with Illustrator already.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logo design&lt;/li&gt;
&lt;li&gt;Print design&lt;/li&gt;
&lt;li&gt;Illustrations&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;In this post, we quickly looked at some tools you can use instead of Adobe. Adobe has a great set of products, but they are not compatible with Linux. All hope is not lost though, there are many open source products that can help you accomplish your design goals.&lt;/p&gt;

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

</description>
      <category>design</category>
      <category>linux</category>
      <category>tools</category>
    </item>
    <item>
      <title>Anatomy of a Serverless YAML File </title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Sun, 04 Aug 2019 16:34:17 +0000</pubDate>
      <link>https://dev.to/_rich/anatomy-of-a-serverless-yaml-file-39ie</link>
      <guid>https://dev.to/_rich/anatomy-of-a-serverless-yaml-file-39ie</guid>
      <description>&lt;p&gt;Within the last few years, creating a serverless infrastructure has become more accessible than ever before. With AWS, Azure, and Google Cloud platforms, developers and engineers have almost limitless capabilities when deploying websites and applications. &lt;a href="https://serverless.com/"&gt;Serverless Framework&lt;/a&gt;, a popular framework for creating serverless architecture, has made it even easier to utilize the biggest cloud computing platforms available. They have done this by abstracting the cloud architecture configuration to a more straightforward form using &lt;a href="https://learn.getgrav.org/16/advanced/yaml"&gt;YAML&lt;/a&gt;. In this post, we’ll look at the &lt;strong&gt;serverless.yml&lt;/strong&gt; file in more detail to see how it is used to set up a serverless architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Serverless.yml 
&lt;/h2&gt;

&lt;p&gt;The serverless.yml is the heart of a serverless application. This file describes the entire application infrastructure, all the way from the programming language to resource access.&lt;/p&gt;

&lt;p&gt;The primary section of this YAML file is the provider. In serverless.yml configuration, you have the option to use AWS, Google Cloud, or Microsoft Azure as your serverless provider. You can also specify the programming language you want to use. In the example below, I specify that I am going to use AWS with Python 3.7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example serverless.yml:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-first-serverless-app&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The serverless.yml file above is the foundation of what could be unlimited computing power, hundreds of serverless functions, and a database infrastructure that powers your website or application. Let’s dive deeper into this configuration. I will be using AWS and python for my base example.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;p&gt;Setting up environment variables to use in your application is really easy with the serverless.yml file. Under the provider, you add an environment section and a list of key values. Taking our example from above a step further, let’s add an environment variable that specifies a table name for a user table.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;users_table&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now in any serverless function we use, the environment variables &lt;strong&gt;USER_TABLE&lt;/strong&gt; is available for us to use. We can also use this variable in other parts of our serverless.yml file to name resources or prefix HTTP paths.&lt;/p&gt;

&lt;p&gt;To use this environment variable in the serverless.yml later on, use the following syntax. Notice that it is similar to traversing an object in other programming languages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;${self:provider.environment.USER_TABLE}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Sourcing Other Files
&lt;/h2&gt;

&lt;p&gt;Often you need to separate configuration for your application into separate files. Serverless Framework has a really nice syntax for including variables from other files. Let’s say for example that you want the user’s table to be named &lt;strong&gt;dev_users_table&lt;/strong&gt; for a development branch. There are many ways to this, but to illustrate sourcing other files, I’ll show you one way.&lt;/p&gt;

&lt;p&gt;You could have multiple config files that are used for specific environments. Let’s say you have two YAML config files in your projects root folder:&lt;/p&gt;

&lt;p&gt;Example &lt;strong&gt;dev.config.yml:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;dev_users_table'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example &lt;strong&gt;prod.config.yml&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;table_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prod_users_table'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Your production application would use &lt;strong&gt;prod.config.yml.&lt;/strong&gt; To source this prod file, you could use the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./prod.config.yml):table_name}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But wait, how do you deploy this application on dev? You have to change the file to specify dev right? No, we can update this config to utilize the &lt;strong&gt;stage&lt;/strong&gt; variable. The stage variable is a special variable in the Serverless Framework that can be used to specify which environment you are using. By default, the stage variable is &lt;strong&gt;dev.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stage Variables
&lt;/h2&gt;

&lt;p&gt;Let’s fix our serverless.yml so that we can use the dev config without updating the file manually. To do this, we use &lt;strong&gt;${opt:stage, self:provider.stage}.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Example &lt;strong&gt;serverless.yml&lt;/strong&gt; with stage variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${opt:stage, self:provider.stage}_users_table&lt;/span&gt;

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



&lt;p&gt;Now that we are using the stage variable. We don’t need the prod.config.yml file now. We can easily prefix all our services with the stage variable so that when we deploy our application to test a new service or feature, we don’t affect the production services.&lt;/p&gt;

&lt;p&gt;If we did want to use separate config files we could use our stage variable to separate the configuration into separate files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./${opt:stage, self:provider.stage}.config.yml):table_name}&lt;/span&gt;

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



&lt;p&gt;Separating out your environment variables into files is a great way to organize bigger applications that use many resources such as S3 buckets, database tables, API version paths, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  IAM Role Statements
&lt;/h2&gt;

&lt;p&gt;If you have used AWS services, you have probably had to create an IAM user or a role before. With serverless, you can give your application permissions to utilize resources via the serverless.yml file. The permission configuration is basically AWS Cloudformation written in YAML. The permissions go under the &lt;strong&gt;iamRoleStatements&lt;/strong&gt; section under the provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example giving your application S3 Access:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have an S3 bucket named &lt;strong&gt;awesome-bucket-name.&lt;/strong&gt; The following example will give your application full access (Read, Write, List, etc) to the specified bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;users_table&lt;/span&gt; 
 &lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;  &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
       &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*"&lt;/span&gt;
       &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:s3:::awesome-bucket-name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example giving your application SES:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have an application that needs to send emails. You can give it access to Amazon SES like this: (Note: you need to setup SES with a verified domain separately.) The following example gives your application access to use all SES resources to send emails.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;USER_TABLE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;users_table&lt;/span&gt; 
 &lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
      &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ses:SendEmail"&lt;/span&gt;
      &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



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

&lt;p&gt;I’ve been writing about this mysterious “application”, but I haven’t explained what that is. In your serverless.yml file, you configure functions to be created on your serverless provider’s platform. For AWS, you can tell serverless to create Lambda functions that can be routed to HTTP endpoints. Let’s take a quick look at how to define an &lt;a href="https://en.wikipedia.org/wiki/Web_API"&gt;HTTP endpoint&lt;/a&gt; via the &lt;strong&gt;serverless.yml&lt;/strong&gt; file.&lt;/p&gt;

&lt;p&gt;Without functions, you do not actually have an application. Remember the programming language we specified in the provider? That tells our provider which programming language to create our functions with. (Note: Programming languages are determined by the provider. You cannot pick any language.)&lt;/p&gt;

&lt;p&gt;As an example, let’s create an HTTP endpoint that returns the &lt;a href="https://en.wikipedia.org/wiki/MD5"&gt;md5&lt;/a&gt; hash of an email address, along with the &lt;a href="https://en.gravatar.com/"&gt;Gravatar&lt;/a&gt; URL for that email.&lt;/p&gt;

&lt;p&gt;To define a function we need two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A file with the function called &lt;strong&gt;getHash&lt;/strong&gt; we’ll call the file &lt;strong&gt;handler.py&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;A serverless.yml function definition&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example of the serverless.yml definition:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;myCustomFunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.getHash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;On the first line, we have &lt;strong&gt;functions.&lt;/strong&gt; This is a section of the YAML file that lives under the provider section. In the functions section, we have &lt;strong&gt;myCustomFunctionName.&lt;/strong&gt; This name will be the Lambda function name in AWS Lambda, not the one used in the code.&lt;/p&gt;

&lt;p&gt;Next, we define the &lt;strong&gt;handler&lt;/strong&gt;. The handler is the path to the function using dot notation. This dot notation is similar to how imports work in Python. &lt;strong&gt;handler&lt;/strong&gt; is the file name and &lt;strong&gt;getHash&lt;/strong&gt; is the function name in that file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is our handler.py&lt;/strong&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;import&lt;/span&gt; &lt;span class="nn"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="n"&gt;CORS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'Access-Control-Allow-Origin'&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="s"&gt;'Access-Control-Allow-Credentials'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&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;getHash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'pathParameters'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'utf8'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;CORS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="s"&gt;"hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"avatar"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"http://gravatar.com/avatar/{}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&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;With the file defined and the function named getHash inside, our serverless.yml is ready to create our function on AWS Lambda. Before we deploy this, we need to enable access to this function via HTTP. To make this an HTTP endpoint, let’s add an events section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example functions with events:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;myCustomFunctionName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.getHash&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;md5/{email}&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get&lt;/span&gt;
          &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The event section ties our function to the API Gateway provided by AWS. In this section, we specify the path and the method of the HTTP endpoint. With this event configuration, you will be able to access your Lambda function via the path &lt;strong&gt;/md5/&lt;a href="mailto:some@email.com"&gt;some@email.com&lt;/a&gt;&lt;/strong&gt;. The response would be a JSON object with the md5 hash and a URL to the gravatar image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example output&lt;/strong&gt; &lt;strong&gt;with my email&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hash&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;97fbef641c6e4669b6a1ad4ffb3342f5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;avatar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;http://gravatar.com/avatar/97fbef641c6e4669b6a1ad4ffb3342f5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can go even further with this by requiring authentication and rate-limiting this endpoint. &lt;a href="https://serverless.com/framework/docs/providers/aws/events/apigateway/"&gt;More from the doc&lt;/a&gt;s.&lt;/p&gt;

&lt;p&gt;Now that we have our events, we can send get requests to this function from a frontend application and it will run our serverless function.&lt;/p&gt;

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

&lt;p&gt;This post scratches the surface of the serverless.yml file. I hope you understand a little more about serverless and dive deeper into this framework and technology. Serverless Framework, along with the cloud platforms available, empower people to create scalable products at a low cost. Building the infrastructure for an application is much easier than ever before and can be created by using a simple configuration file like serverless.yml.&lt;/p&gt;

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

</description>
      <category>aws</category>
      <category>basics</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Why you should not build your own authentication system?</title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Sat, 27 Jul 2019 23:00:20 +0000</pubDate>
      <link>https://dev.to/_rich/why-you-should-not-build-your-own-authentication-system-431e</link>
      <guid>https://dev.to/_rich/why-you-should-not-build-your-own-authentication-system-431e</guid>
      <description>&lt;p&gt;Now I know why people always say: “don’t roll your own authentication system.” Unless you want to create an authentication system for fun, I would advise against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity
&lt;/h2&gt;

&lt;p&gt;First of all, it’s a full-time job to create a robust authentication system. For example, you need many API routes, knowledge of encryption, a server to host the API, and a database server. That is just the minimum. Authentication systems are much more complicated than they seem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security &amp;amp; Multi-level dependencies
&lt;/h2&gt;

&lt;p&gt;You also need to keep up with security patches for your authentication systems application dependencies. Also, you need to keep up with the dependencies of the software you are using to build your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Wheel argument
&lt;/h2&gt;

&lt;p&gt;Another reason to avoid creating an authentication system is that there are already great ones available. Just take your pick:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Auth0&lt;/li&gt;
&lt;li&gt;Firebase&lt;/li&gt;
&lt;li&gt;Google Login&lt;/li&gt;
&lt;li&gt;Facebook Login&lt;/li&gt;
&lt;li&gt;Twitter Login&lt;/li&gt;
&lt;li&gt;Github Login&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All of these applications can be used as an authentication system for your application for minimal cost or free.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give it a try
&lt;/h2&gt;

&lt;p&gt;For me, I’ve always wanted to write an authentication system from scratch, and so I have written a few. It is a good idea to create an authentication system as a programming exercise, but you should use an existing authentication system for a production application.&lt;/p&gt;

&lt;p&gt;The two reason to create your own authentication system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Programming exercise&lt;/li&gt;
&lt;li&gt;You want to build an authentication SaaS product.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To conclude, you should “roll-your-own auth.” It’s usually very complex, there are many security dependencies to worry about, and there are already great solutions available. So build your application and integrate it with an existing authentication system. You’ll thank me later!&lt;/p&gt;

</description>
      <category>api</category>
      <category>authentication</category>
      <category>basics</category>
    </item>
    <item>
      <title>Crime Data Exploration with Python3 and Pandas: Part 2 </title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Tue, 23 Jul 2019 02:16:35 +0000</pubDate>
      <link>https://dev.to/_rich/crime-data-exploration-with-python3-and-pandas-part-2-23l1</link>
      <guid>https://dev.to/_rich/crime-data-exploration-with-python3-and-pandas-part-2-23l1</guid>
      <description>&lt;h2&gt;
  
  
  Objective
&lt;/h2&gt;

&lt;p&gt;The purpose of this post series is to explore datasets from the UCR (Uniforn Crime Reporting Program). In this post, we'll use Pandas to dig deeper into crime statistics for homicide. After preparing the dataset for comparison, we'll rank each state based on number of crimes per capita.&lt;/p&gt;

&lt;p&gt;Follow along or checkout the code on &lt;a href="https://github.com/rbk/Crime-Data-Analysis"&gt;Github.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About the data
&lt;/h2&gt;

&lt;p&gt;The dataset we are using is the &lt;code&gt;estimated_crimes.csv&lt;/code&gt; downloaded from the &lt;a href="https://crime-data-explorer.fr.cloud.gov/"&gt;Cime Data Explorer&lt;/a&gt; website. This file contains the estimated crimes for 7 types of crimes, from the years 1995 to 2017, for the United States. For more information about this dataset and how it is compiled visit the &lt;a href="https://crime-data-explorer.fr.cloud.gov/"&gt;Cime Data Explorer.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the data
&lt;/h2&gt;

&lt;p&gt;For data manipulation we will use Pandas. The first thing we need to do is download the dataset and load it into a Pandas dataframe.&lt;/p&gt;

&lt;p&gt;If you need the dataset you can download it here: &lt;a href="https://github.com/rbk/Crime-Data-Analysis"&gt;https://github.com/rbk/Crime-Data-Analysis&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the following code, we use pandas to open the &lt;strong&gt;estimated_crimes.csv&lt;/strong&gt; into a &lt;a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html"&gt;dataframe&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We specify the columns we want to work with by specifying the &lt;strong&gt;usecols&lt;/strong&gt; attribute. This attribute tells the &lt;strong&gt;read_csv&lt;/strong&gt; function to only load in the column with the headers that are in the cols array:&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;pandas&lt;/span&gt;

&lt;span class="n"&gt;cols&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s"&gt;'year'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'state_name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'population'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;'homicide'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'../data/estimated_crimes.csv'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;usecols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cols&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;raw_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Output:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   year state_name  population  homicide
0  1995        NaN   262803276     21606
1  1996        NaN   265228572     19645
2  1997        NaN   267783607     18211
3  1998        NaN   270248003     16974
4  1999        NaN   272690813     15522
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you are curious on how to find out what the headers of your CSV are, use the &lt;strong&gt;info&lt;/strong&gt; function:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'../data/estimated_crimes.csv'&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;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Output:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;class 'pandas.core.frame.DataFrame'&amp;gt;
RangeIndex: 1196 entries, 0 to 1195
Data columns (total 16 columns):
year                   1196 non-null int64
state_id               1173 non-null float64
state_abbr             1173 non-null object
state_name             1173 non-null object
population             1196 non-null int64
violent_crime          1196 non-null int64
homicide               1196 non-null int64
rape_legacy            1196 non-null int64
rape_revised           260 non-null float64
robbery                1196 non-null int64
aggravated_assault     1196 non-null int64
property_crime         1196 non-null int64
burglary               1196 non-null int64
larceny                1196 non-null int64
motor_vehicle_theft    1196 non-null int64
caveats                71 non-null object
dtypes: float64(2), int64(11), object(3)

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



&lt;h2&gt;
  
  
  Top 10 States Ranked By Total Homicides
&lt;/h2&gt;

&lt;p&gt;Now that we have our data loaded into a dataframe, we can start processing the data. The first thing we will do is rank the states by the number of homicides. &lt;/p&gt;

&lt;p&gt;This is a bad idea. Let's do it anyway to see why.&lt;/p&gt;

&lt;p&gt;This is a very simple task. First, we query the dataframe by the year:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Get 2017 state data
# We use notnull because the state name is not null for states
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'year == 2017 and state_name.notnull()'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next we sort the data using &lt;strong&gt;sort_values&lt;/strong&gt;.&lt;br&gt;
Using the &lt;strong&gt;by&lt;/strong&gt; attribute, we provide an array of columns to sort by. In this case we are sorting by the count of homicides.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Ranked By Total Homicides
&lt;/span&gt;&lt;span class="n"&gt;ranked_by_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'homicide'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ranked_by_total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ranked_by_total&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;ranked_by_total&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'index'&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;ranked_by_total&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Output:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   year      state_name  population  homicide
0  2017      California    39536653      1830
1  2017           Texas    28304596      1412
2  2017         Florida    20984400      1057
3  2017        Illinois    12802023       997
4  2017    Pennsylvania    12805537       739
5  2017            Ohio    11658609       710
6  2017         Georgia    10429379       703
7  2017        Missouri     6113532       600
8  2017  North Carolina    10273419       591
9  2017       Louisiana     4684333       582
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The homicide column above is sorted by count.&lt;/p&gt;

&lt;p&gt;From this simple sort we can say that California has the most homicides per year. Statistically this is true, but they also have the largest population of any state.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Top 10 States By Population&lt;/em&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   year      state_name  population  homicide
0  2017      California    39536653      1830
0  2017           Texas    28304596      1412
0  2017         Florida    20984400      1057
0  2017        New York    19849399       548
0  2017    Pennsylvania    12805537       739
0  2017        Illinois    12802023       997
0  2017            Ohio    11658609       710
0  2017         Georgia    10429379       703
0  2017  North Carolina    10273419       591
0  2017        Michigan     9962311       569
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ranking the states in this way doesn't make sense because the number of homicides is not proportional to the number of people in the states.&lt;/p&gt;

&lt;p&gt;From looking at the homicides ranked vs the populations, you can see that there is a strong correlation between the number of homicides and the population.&lt;/p&gt;

&lt;p&gt;Next, we will rank the states by homicide rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Top 10 States Ranked By Total Homicides Relative to the Population Size
&lt;/h2&gt;

&lt;p&gt;Now we will rank the states in homcide by the population size. This will give us a clearer picture of the homcide rate, e.g. the number of homicides per 100,000 people.&lt;/p&gt;

&lt;p&gt;First, we'll use Pandas &lt;strong&gt;apply&lt;/strong&gt; function to create a new row.&lt;br&gt;
The apply function takes the name of a function and "applies" the result of the function to each row. Our function is called &lt;strong&gt;per_capital&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The per_capita function takes each row of data and performs a calculation to normalize data.&lt;/p&gt;

&lt;p&gt;The result is that we have a column for each row with the number of homicides per 100,000 people.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Ranked By Total Homicides Relative to the Population Size
# Per 100,000 people
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;per_capita&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="s"&gt;"""Calculate the homcide rate per capita."""&lt;/span&gt;
    &lt;span class="n"&gt;total_homicides&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'homicide'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'population'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_homicides&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100000&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'per_captia'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_capita&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Ranked By Total Homicides
&lt;/span&gt;&lt;span class="n"&gt;ranked_by_population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sort_values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;by&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'per_captia'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ascending&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ranked_by_population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ranked_by_population&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;del&lt;/span&gt; &lt;span class="n"&gt;ranked_by_population&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'index'&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;ranked_by_population&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, we print all the rows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Output:
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    year            state_name  population  homicide  per_captia
0   2017  District of Columbia      693972       116   16.715372
1   2017             Louisiana     4684333       582   12.424394
2   2017              Missouri     6113532       600    9.814294
3   2017                Nevada     2998039       274    9.139307
4   2017              Maryland     6052177       546    9.021547
5   2017              Arkansas     3004279       258    8.587751
6   2017                Alaska      739795        62    8.380700
7   2017               Alabama     4874747       404    8.287610
8   2017           Mississippi     2984100       245    8.210181
9   2017             Tennessee     6715984       527    7.846951
10  2017              Illinois    12802023       997    7.787832
11  2017        South Carolina     5024369       390    7.762169
12  2017            New Mexico     2088070       148    7.087885
13  2017               Georgia    10429379       703    6.740574
14  2017              Oklahoma     3930864       242    6.156407
15  2017                  Ohio    11658609       710    6.089920
16  2017               Indiana     6666818       397    5.954865
17  2017               Arizona     7016270       416    5.929076
18  2017              Kentucky     4454189       263    5.904554
19  2017          Pennsylvania    12805537       739    5.770941
20  2017        North Carolina    10273419       591    5.752710
21  2017              Michigan     9962311       569    5.711526
22  2017              Delaware      961939        54    5.613662
23  2017                Kansas     2913123       160    5.492387
24  2017              Virginia     8470020       453    5.348275
25  2017               Florida    20984400      1057    5.037075
26  2017                 Texas    28304596      1412    4.988589
27  2017         West Virginia     1815857        85    4.680985
28  2017            California    39536653      1830    4.628616
29  2017              Colorado     5607154       221    3.941393
30  2017               Montana     1050493        41    3.902929
31  2017            New Jersey     9005644       324    3.597744
32  2017                  Iowa     3145711       104    3.306089
33  2017             Wisconsin     5795483       186    3.209396
34  2017            Washington     7405743       230    3.105698
35  2017          South Dakota      869666        25    2.874667
36  2017           Connecticut     3588184       102    2.842664
37  2017              New York    19849399       548    2.760789
38  2017                Hawaii     1427538        39    2.731976
39  2017               Wyoming      579315        15    2.589265
40  2017         Massachusetts     6859819       173    2.521932
41  2017                Oregon     4142776       104    2.510394
42  2017                  Utah     3101833        73    2.353447
43  2017               Vermont      623657        14    2.244824
44  2017              Nebraska     1920076        43    2.239495
45  2017             Minnesota     5576606       113    2.026322
46  2017          Rhode Island     1059639        20    1.887435
47  2017                 Idaho     1716943        32    1.863778
48  2017                 Maine     1335907        23    1.721677
49  2017          North Dakota      755393        10    1.323814
50  2017         New Hampshire     1342795        14    1.042601

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



&lt;h2&gt;
  
  
  What can we infer from this analysis
&lt;/h2&gt;

&lt;p&gt;The new column &lt;strong&gt;per_capita&lt;/strong&gt;, gives us a more accurate description of the homicide rate per 100,000 people for each state. For example, we could say that for every 100,000 people in Louisiana, there are 2.4 homicides reported. &lt;/p&gt;

&lt;p&gt;Here are a few more conclusions we can draw from this analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The District of Columbia has the highest homicide rate, ranking #1 for the most homicides per capita (per 100,000 people).&lt;/li&gt;
&lt;li&gt;Although California has the largest population, the homicide rate ranks #29 in the country.&lt;/li&gt;
&lt;li&gt;New Hampshire has the lowest homicide rate.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The lesson from this analysis is that sorting by count doesn't tell the full story about the data. California would be ranked #1 in homicides from the first analysis, but in reality, California has a lower homicide rate than 28 other states. This is a simple example of how data can be decieving.&lt;/p&gt;

&lt;p&gt;To recap, we used Pandas &lt;strong&gt;read_csv&lt;/strong&gt; to explore the Estimated Crime 2017 dataset. We ranked states by total homicides. Then we looked at the homicide rate, which gave of very different views of how the states rank in homicdes.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  FBI Disclaimer
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"The data found on the Crime Data Explorer represents reported crime, and is not an exhaustive report of all crime that occurs. It’s important to consider the various factors that lead to crime activity and crime reporting in a community before interpreting the data. Without these considerations the available data can be deceiving. Factors to consider include population size and density, economic conditions, employment rates, prosecutorial, judicial, and correctional policies, administrative and investigative emphases of law enforcement, citizens’ attitudes toward crime and policing, and the effective strength of the police force."&lt;/p&gt;

&lt;p&gt;--- &lt;a href="https://crime-data-explorer.fr.cloud.gov/explorer/state/new-york/crime"&gt;Crime Data Explorer, Retrieved 19:45, July 22, 2019&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ucr.fbi.gov/ucr-statistics-their-proper-use"&gt;For more information on the use of the UCR database&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dataexploration</category>
      <category>python</category>
      <category>pandas</category>
    </item>
    <item>
      <title>Crime Data Exploration with Python3 and Pandas: Part 1 </title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Sat, 13 Jul 2019 21:48:40 +0000</pubDate>
      <link>https://dev.to/_rich/crime-data-exploration-with-python3-and-pandas-part-1-3445</link>
      <guid>https://dev.to/_rich/crime-data-exploration-with-python3-and-pandas-part-1-3445</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Data is everywhere. Crime is too. The FBI runs a program called Uniform Crime Reporting (UCR) Program that collects crime data from ~18,000 agencies all over the United States. This database is a gold mine of interesting statistics about crime in the United States. Follow along and learn about how you can use Python to analyze this data. My hope is that you learn from this article and then go do some data exploration on your own.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Source code:&lt;/strong&gt; &lt;a href="https://github.com/rbk/Crime-Data-Analysis" rel="noopener noreferrer"&gt;https://github.com/rbk/Crime-Data-Analysis&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Tools We'll Use
&lt;/h2&gt;

&lt;p&gt;Data scientists are known to use Python for machine learning and data cleaning. What you may not know is that there are some fantastic libraries in Python for performing operations on JSON, CSV, and other data types.&lt;/p&gt;

&lt;p&gt;You are going to fall in love with Pandas very soon. No not the cute cuddly pandas you see at the zoo, Pandas the Python package. Pandas is a library that makes dealing with massive arrays of data a breeze as you will see in the next section. Pandas is built on top of Numpy. I recommend checking them both out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pandas.pydata.org/" rel="noopener noreferrer"&gt;https://pandas.pydata.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.numpy.org/" rel="noopener noreferrer"&gt;https://www.numpy.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Download the Dataset
&lt;/h2&gt;

&lt;p&gt;Grab the dataset to begin. You can use which ever method is easiest to you to download the dataset. Here is the URI of the dataset we will be working with:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://s3-us-gov-west-1.amazonaws.com/cg-d4b776d0-d898-4153-90c8-8336f86bdfec/estimated_crimes.csv" rel="noopener noreferrer"&gt;http://s3-us-gov-west-1.amazonaws.com/cg-d4b776d0-d898-4153-90c8-8336f86bdfec/estimated_crimes.csv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This dataset contains the esitmated counts of criminal incidents reported from 1995 to 2017 in all the United States.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2FScreenshot%2Bfrom%2B2019-07-13%2B12-41-54.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2FScreenshot%2Bfrom%2B2019-07-13%2B12-41-54.png" alt="FBI Crime Estimation CSV file opened in Libre Office Excel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before diving in to the code there is one more thing...disclaimer time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclaimer About Drawing Conclusions from this Crime dataset
&lt;/h2&gt;

&lt;p&gt;The crime dataset is a compilation of incident reports over time. The term "Crime Rate" is the number of crimes per person in a given population. It is important to note that this doesn't take into account the hundreds of risk factors associated  with the safety of a city or state. For example, New Mexico may have a higher crime rate than average, but statistically that doesn't New Mexico is a dangerous place to live. The data doesn't take into account the population density, economic conditions, employment rates, and the effective strength of the police force&lt;sup&gt;1&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, you cannot just assume that a certain state is more safe because the crime rate is below average. The reason this claim is invalid is that crime in certain areas could just not be reported because of the crime itself.&lt;/p&gt;

&lt;p&gt;Alright, enough of the disclaimer...&lt;/p&gt;

&lt;h2&gt;
  
  
  Time to Code!
&lt;/h2&gt;

&lt;p&gt;Fire up your IDE or editor or Jupyter Notebook ladies and gents. We are going in line by line. You should have a folder with a CSV file called &lt;code&gt;estimated_crimes.csv&lt;/code&gt;. In this folder you need a Python file. I usually use &lt;code&gt;main.py&lt;/code&gt;. This code will be in Python3. You'll also need to pip install pandas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;pandas
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Objective
&lt;/h2&gt;

&lt;p&gt;In the following steps we will transform the CSV file from the FBI into a new CSV with new columns that help us visually understand the data. Specifically, we are going to determine the average crime rate on the national level and then compare each US state's crime rate to show the percentage difference relative to the national average.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Load the CSV into a Pandas Dataframe
&lt;/h3&gt;

&lt;p&gt;The first thing we need to do is get control of our data. In its raw format it is a little awkward to work with. Pandas is the tool of choice for transforming data into different forms that are easier to work with.&lt;/p&gt;

&lt;p&gt;The first trick you must know about Pandas when working with CSV files is the amazing &lt;code&gt;read_csv&lt;/code&gt; function. The read_csv function will load any CSV file into a Pandas Dataframe. From this dataframe we can use all kind of pandas functions to manipulate and query the data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;

&lt;span class="c1"&gt;# Read the CSV into a Dataframe
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;estimated_crimes.csv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Once the data is read into a variable we can use the &lt;code&gt;head&lt;/code&gt; function to print the first 5 rows of the dataframe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Print the first 5 lines of the dataframe
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-01.png" alt="Print data in terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now before moving on, lets remove the columns of the data we don't need right now. To do this, read the CSV with the &lt;code&gt;usecols&lt;/code&gt; option. &lt;code&gt;usecols&lt;/code&gt; tells the read function to only use a specified list of columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;

&lt;span class="c1"&gt;# Which columns to use
&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;year&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;state_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;population&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;violent_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;property_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Get the data into a dataframe from csv
&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;estimated_crimes.csv&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;usecols&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you print the data it is easier to visualize.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Print the first 5 lines of the dataframe
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-02.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-02.png" alt="Print formatted data in terminal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Filter Data
&lt;/h3&gt;

&lt;p&gt;Now that you have the data in a dataframe you have unleashed the power of Pandas! The second trick of Pandas is the &lt;code&gt;query&lt;/code&gt; function. With the query function we can filter our CSV file to only contain rows for a specific year.&lt;/p&gt;

&lt;p&gt;Using our dataframe from above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;year == 2017&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that doesn't make you excited to use pandas I don't know what will. After running this query function our data should only contain rows in which the year column is 2017.&lt;/p&gt;

&lt;p&gt;Another filter we need to add is to remove row in which the state column is null. In this particular CSV the top rows are the compiled national stats, so the state column is not filled out. We can filter these rows by using the pandas &lt;code&gt;notnull&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;state_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;notnull&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any row in which the state column is null or NaN, will be removed from the dataframe.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Add new data columns with &lt;code&gt;apply&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Now that we have the data cleaned up. We'll add three columns. Using the pandas &lt;code&gt;apply&lt;/code&gt; function we can create new columns in the data in two steps.&lt;/p&gt;

&lt;p&gt;The first step is to define your function. This function will take each row from the dataframe. For example, the following function will calculate the crimes per 1000 people in each row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;crime_per_capita&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number_of_people&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;total_crimes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;violent_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;property_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;population&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_crimes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;population&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;number_of_people&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our dataframe can now use this function to create a new column by using &lt;code&gt;apply&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;crime_per_1000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crime_per_capita&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running print head will show a new column with the number of crimes for every 1000 people. &lt;/p&gt;

&lt;p&gt;Next we will compute the national crime rate, then use the national crime rate to compare each individual states crime rate. Once we compute the percentage difference of the national average crime rate to each US State, we will be able to quickly see the differences in crime rates across the US.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;
&lt;span class="c1"&gt;# 1 Get National Average
&lt;/span&gt;&lt;span class="n"&gt;total_population&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;population&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;total_crimes&lt;/span&gt; &lt;span class="o"&gt;=+&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;violent_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;property_crime&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;national_average_per_cap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_crimes&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;total_population&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;

&lt;span class="c1"&gt;# 2.0 Add column of diff to national average
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_diff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;crime_per_1000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;national_average_per_cap&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;diff&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;diff_of_national_average&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute_diff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 2.1 Add column of percent diff compared to national average
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_percent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;percent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;crime_per_1000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;national_average_per_cap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;percent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;percent_diff_national&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compute_percent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Drawing Conclusions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-all-03.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fblog.richardkeller.net%2Fposts%2Fcrime-data-analysis-01%2Fdf-head-all-03.png" alt="Terminal output of data with new columns of computed crime rate related to national average."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the data above we can see that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ohio and Maryland have the lowest crime rates 2% below the average. This means that there we fewer crimes reported for every 1000 people than the national average.&lt;/li&gt;
&lt;li&gt;Maryland has the fewest crimes per capita in 2017.&lt;/li&gt;
&lt;li&gt;The crime rate in the District of Columbia is nearly twice the national average (+91% above the national average).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The possibilities of data exploration are endless with this dataset and many others.&lt;br&gt;
Just keep in mind that you should take heed to the disclaimer before making assumptions about safety on just one dimensinal data like this. There are hundreds of factors that determine the actual safety of a city or neighborhood.&lt;/p&gt;

&lt;p&gt;To conclude, we looked at a dataset from the FBI UCR website called "estimated_crimes.csv". We used the Pandas python library to filter and transform the data so that it could be read easier. We then came up with a few conclusions about the data.&lt;/p&gt;

&lt;p&gt;Stay tuned for Part 2 where we dive deeper into the Crime datasets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources and References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[1] &lt;a href="https://crime-data-explorer.fr.cloud.gov/explorer/state/california/crime/1995/2017" rel="noopener noreferrer"&gt;https://crime-data-explorer.fr.cloud.gov/explorer/state/california/crime/1995/2017&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.fbi.gov/services/cjis/ucr" rel="noopener noreferrer"&gt;https://www.fbi.gov/services/cjis/ucr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://crime-data-explorer.fr.cloud.gov/downloads-and-docs" rel="noopener noreferrer"&gt;https://crime-data-explorer.fr.cloud.gov/downloads-and-docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://definitions.uslegal.com/c/crime-rate/" rel="noopener noreferrer"&gt;https://definitions.uslegal.com/c/crime-rate/&lt;/a&gt; -&amp;gt; "Population-based rates fail to take into account variations in risk."&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>dataexploration</category>
      <category>python</category>
      <category>pandas</category>
    </item>
    <item>
      <title>Building a PDF Generator on AWS Lambda with Python3 and wkhtmltopdf</title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Mon, 24 Jun 2019 12:09:19 +0000</pubDate>
      <link>https://dev.to/_rich/building-a-pdf-generator-on-aws-lambda-with-python3-and-wkhtmltopdf-50kl</link>
      <guid>https://dev.to/_rich/building-a-pdf-generator-on-aws-lambda-with-python3-and-wkhtmltopdf-50kl</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 07/18/2019: Source Code: &lt;a href="https://github.com/rbk/Lambda-PDF-Generator"&gt;https://github.com/rbk/Lambda-PDF-Generator&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;UPDATE 06/28/2019: For anyone attempting to follow this please read a follow up post about a font bug on the generated PDFs: &lt;a href="https://blog.richardkeller.net/wkhtmltopdf-bad-kerning-on-aws-lambda/"&gt;https://blog.richardkeller.net/wkhtmltopdf-bad-kerning-on-aws-lambda/&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Creating scalable APIs in 2019 is easier than ever before with serverless auto-scaling compute power being widely accessible. In this article I'll show you how I created a PDF generator API that can handle with 1000 concurrent requests.&lt;/p&gt;

&lt;p&gt;The purpose of this artice is to show you how I accomplished creating the API so that you will see how easy it is to create your own serverless APIs. When this project is complete, you will have an API endpoint in which you can POST a JSON object to, and recieve a link to a PDF on Amazon S3. The JSON object looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sample.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"html"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;It works! This is the default PDF.&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;strong&gt;What you'll need:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python3&lt;/li&gt;
&lt;li&gt;Aws CLI installed and configured&lt;/li&gt;
&lt;li&gt;Serverless installed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Serverless
&lt;/h3&gt;

&lt;p&gt;The first thing you need to do is initialize a new Serverless project. Serverless is a tool that greatly simplifies using AWS, Gcloud, and Azure services so you can create APIs without worrying about managing a server. If you need more information about Serverless visite their website: &lt;a href="https://serverless.com"&gt;Serverless.com&lt;/a&gt;. In your terminal run the following command to initialize your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: sls is short for serverless and can be used interchangably.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;This command will bootstrap a Python3 Lambda setup for you to work from.&lt;/p&gt;

&lt;h3&gt;
  
  
  WKHTMLTOPDF Binary
&lt;/h3&gt;

&lt;p&gt;Next we need to get the binary for turning HTML into PDFs. For this I used &lt;a href="https://github.com/wkhtmltopdf/wkhtmltopdf"&gt;WKHTMLTOPDF&lt;/a&gt;. &lt;strong&gt;Important:&lt;/strong&gt; You have to use version 0.12.4 becaused later versions of wkhtmltopdf require dynamic dependencies of the host system that cannot be installed on Lambda.&lt;/p&gt;

&lt;p&gt;Download version 0.12.4 here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz"&gt;https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have extract this tar file, copy the binary &lt;strong&gt;&lt;em&gt;wkhtmltopdf&lt;/em&gt;&lt;/strong&gt; to the binary folder in your project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;./binary/wkhtmltopdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;More information about wkhtmltopdf can be found on their website:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://wkhtmltopdf.org/"&gt;WKHTMLTOPDF&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Python3 Dependencies
&lt;/h3&gt;

&lt;p&gt;Now that we have the WKHTMLtoPDF binary, we need the Python library, &lt;strong&gt;&lt;em&gt;pdfkit&lt;/em&gt;&lt;/strong&gt; to use it. Since we are using Serverless and AWS Lambda we cannot just run &lt;em&gt;pip install pdfkit&lt;/em&gt;. We need a Serverless plugin to install our dependencies on Lambda.&lt;/p&gt;

&lt;p&gt;In our project folder install the &lt;strong&gt;python plugin requirements&lt;/strong&gt; module for Serverless.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sls plugin &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; serverless-python-requirements
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in your serverless.yml file, you need to add a custom section in the yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pythonRequirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dockerizePip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the serverless plugin requirements is installed, you can add a requirements.txt file to your project and it will be automatically installed on lambda when you deploy.&lt;/p&gt;

&lt;p&gt;Your requirements.txt for this project only needs to have pdfkit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Requirements.txt&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pdfkit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;For any issues with this module checkout the repository issue:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/UnitedIncome/serverless-python-requirements"&gt;Serverless Python Requirements&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Ready, Set, Code
&lt;/h2&gt;

&lt;p&gt;We are ready to code now. We only need to work with two files for this project: serverless.yml ad handler.py. Typically you want your serverless projects to be lightweight and independent of other parts of your codebase.&lt;/p&gt;
&lt;h3&gt;
  
  
  Serverless.yml
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;serverless.yml&lt;/strong&gt; file is our main configuration file. A serverless.yml file is broken down into a few important sections. If you are new to YAML, &lt;a href="https://learn.getgrav.org/16/advanced/yaml"&gt;checkout the documentation for YAML&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this serverless.yml configuration you'll need to create a file called config.yml. This will store the S3 bucket name. The serverless.yml will reference the config.yml to setup the correct bucket for your project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contents of config.yml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BucketName: 'your-s3-bucket-name'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Here is a high level overview of a serverless.yml file:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;service: pdf-services # name or reference to our project
provider: # It is possible to use Azure, GCloud, or AWS
functions: # Array of functions to deploy as Lambdas
resources: # S3 buckets, DynamoDB tables, and other possible resources to create
plugins: # Plugins for Serverless
custom: # Custom variables used by you or plugins during setup and deployment

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

&lt;/div&gt;



&lt;p&gt;Our serverless configuration will do a few things for us when we deploy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an S3 bucket called &lt;strong&gt;pdf-service-bucket&lt;/strong&gt; to store our PDFs&lt;/li&gt;
&lt;li&gt;Create a function that will create the PDFs&lt;/li&gt;
&lt;li&gt;Give our function access to the S3 bucket&lt;/li&gt;
&lt;li&gt;Setup an API endpoint for our Lambda function at:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://xxxx.execute-api.xxxx.amazonaws.com/dev/new-pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the full serverless.yml configuration. I've added a couple important comments in the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pdf-service&lt;/span&gt;
&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.7&lt;/span&gt;
  &lt;span class="c1"&gt;# Set environment variable for the S3 bucket&lt;/span&gt;
  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./config.yml):BucketName}&lt;/span&gt;
  &lt;span class="c1"&gt;# Gives our functions full read and write access to the S3 Bucket&lt;/span&gt;
  &lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt;  &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Allow"&lt;/span&gt;
       &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3:*"&lt;/span&gt;
       &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:s3:::${file(./config.yml):BucketName}&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;arn:aws:s3:::${file(./config.yml):BucketName}/*&lt;/span&gt;
&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generate_pdf&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.generate_pdf&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;new-pdf&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;post&lt;/span&gt;
          &lt;span class="na"&gt;cors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="c1"&gt;# Creates an S3 bucket in our AWS account&lt;/span&gt;
 &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;NewResource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::S3::Bucket&lt;/span&gt;
     &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;BucketName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${file(./config.yml):BucketName}&lt;/span&gt;
&lt;span class="na"&gt;custom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pythonRequirements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;dockerizePip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-python-requirements&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Handler.py
&lt;/h3&gt;

&lt;p&gt;Handler.py is the only Python file we need. It contains one function to generate the PDF and save it to Lambda. You can creat more functions in this file to split the code into reusable parts, but for this example one function was enough. Lambda functions take two arguments by default: Event and Context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context&lt;/strong&gt; contains environment variables and system information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event&lt;/strong&gt; contains request data that is sent to the lambda function.&lt;/p&gt;

&lt;p&gt;In this project we will send our function &lt;strong&gt;generate_pdf&lt;/strong&gt; a filename and HTML, and it will return the URI for a PDF it creates.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="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;pdfkit&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&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;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'s3'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Get the bucket name environment variables to use in our code
&lt;/span&gt;&lt;span class="n"&gt;S3_BUCKET_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'S3_BUCKET_NAME'&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;generate_pdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="c1"&gt;# Defaults
&lt;/span&gt;    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'deafult-filename.pdf'&lt;/span&gt;
    &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;It works! This is the default PDF.&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;

    &lt;span class="c1"&gt;# Decode json and set values for our pdf    
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;'body'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&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;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'body'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'filename'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'html'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 

    &lt;span class="c1"&gt;# Set file path to save pdf on lambda first (temporary storage)
&lt;/span&gt;    &lt;span class="n"&gt;filepath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/tmp/{key}'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create PDF
&lt;/span&gt;    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdfkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wkhtmltopdf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"binary/wkhtmltopdf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pdfkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;


    &lt;span class="c1"&gt;# Upload to S3 Bucket
&lt;/span&gt;    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&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;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ACL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'public-read'&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="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'rb'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;ContentType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;'application/pdf'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Format the PDF URI
&lt;/span&gt;    &lt;span class="n"&gt;object_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://{0}.s3.amazonaws.com/{1}"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;S3_BUCKET_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Response with result
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"Access-Control-Allow-Origin"&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="s"&gt;"Access-Control-Allow-Credentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="s"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;object_url&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;response&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Deploy
&lt;/h2&gt;

&lt;p&gt;Now that you have all the code ready it is time to deploy. In your project folder run the following command from your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sls deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After you run deploy, Serverless will create everything for you in AWS. You will get HTTP POST endpoint that you will use to generate PDFs. The endpoint will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/new-pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;strong&gt;curl&lt;/strong&gt; to test your function. The following curl command posts a JSON object to the lambda endpoint. The JSON object contains a filename and some html to turn into a PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"filename":"my-sample-filename.pdf", "html":"&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Custom HTML -&amp;gt; Posted From CURL as {JSON}&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"}'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-X&lt;/span&gt; POST REPLACE-WITH-YOUR-ENDPOINT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Replace "REPLACE-WITH-YOUR-ENDPOINT" with the endpoint you receive from Serverless.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;After running this command you should receive the URI to your generated PDF.&lt;/p&gt;

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

&lt;p&gt;Creating a scalable PDF generator is easy with of AWS and Serverless. In addition to having a scalable API, you don't have to worry about server maintenance. I encourage you to create more projects with AWS Lambda to get comfortable with the platform and configuration.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setup a custom domain with &lt;a href="https://github.com/amplify-education/serverless-domain-manager"&gt;Serverless Domain Manager&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Setup local testing with &lt;a href="https://github.com/dherault/serverless-offline"&gt;Serverless Offline&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Serverless Environment Variables - &lt;a href="https://serverless.com/framework/docs/providers/aws/guide/variables/"&gt;https://serverless.com/framework/docs/providers/aws/guide/variables/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Serverless CORS Guide - &lt;a href="https://serverless.com/blog/cors-api-gateway-survival-guide/"&gt;https://serverless.com/blog/cors-api-gateway-survival-guide/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fonts AWS Lambda - &lt;a href="https://forums.aws.amazon.com/thread.jspa?messageID=776307"&gt;https://forums.aws.amazon.com/thread.jspa?messageID=776307&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Boto3 API - &lt;a href="https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_file"&gt;https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Client.upload_file&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;S3 Argument Reference - &lt;a href="https://gist.github.com/rbk/926bfd3d886b2c25c53818eeb6e77d6a"&gt;https://gist.github.com/rbk/926bfd3d886b2c25c53818eeb6e77d6a&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published at &lt;a href="https://blog.richardkeller.net"&gt;https://blog.richardkeller.net&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What I Learned From Tulsa's Web Developer Conference 200OK</title>
      <dc:creator>Richard Keller</dc:creator>
      <pubDate>Mon, 10 Jun 2019 12:02:18 +0000</pubDate>
      <link>https://dev.to/_rich/what-i-learned-from-tulsa-8217-s-web-developer-conference-200ok-1jjm</link>
      <guid>https://dev.to/_rich/what-i-learned-from-tulsa-8217-s-web-developer-conference-200ok-1jjm</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is a collection of thoughts from my experience attending &lt;a href="https://200ok.us/"&gt;Tulsa's Web Developer Conference 200Ok&lt;/a&gt; in 2019. I would Like to point out that all of the talks at the conference were interesting and helpful in there own way. This article will just cover the parts I found most relevant.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There were three talks at the 200OK conference that really stood out to me. The three talks were about having the growth mindset, writing good APIs, and efficiency through kanban. I believe these three things are fundamental to being a good web developer. Let’s explore these areas briefly, one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Have a Growth Mindset
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H88gSFPX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/meditation.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H88gSFPX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/meditation.jpg" alt="" class="wp-image-496"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;The first talk I want to mention was a talk from &lt;a href="https://twitter.com/tech_christine"&gt;Christine Seeman&lt;/a&gt;, a Software Engineer. Her talk was titled &lt;strong&gt;“Hack your brain – Ways to improve your thought processes.”&lt;/strong&gt; The talk was really awesome and included a meditation session which made it even better.&lt;/p&gt;

&lt;p&gt;It is important for web developers to have a growth mindset. Having a growth mindset means that you look at problems as learning opportunities. There is always something new to learn in web development because the technology changes fast. The pace of technology can be overwhelming. Here are a couple tips I learned from this talk about having a growth mindset.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 Accept that you are not perfect
&lt;/h3&gt;

&lt;p&gt;This is a big one. You need to be humble since you cannot possibly know everything. It is important to accept that you are not perfect. Everyone wants to be the best at their job, which is understandable, but you need to also realize that you have limited time to learn and so you cannot be an expert at everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 Focus on the learning process, not the end result
&lt;/h3&gt;

&lt;p&gt;The end result looks great, but the process of learning is more important to focus on. You need to figure out and understand how you learn best, to help yourself learn better and faster. There are tons of resources online in which you can find out how to learn better. Here is a free online course that explains techniques like &lt;strong&gt;spaced repetition, recall,&lt;/strong&gt; and &lt;strong&gt;visualizaton&lt;/strong&gt; to help you learn and retain information better: Learning How To Learn, &lt;a href="https://www.coursera.org/learn/learning-how-to-learn"&gt;https://www.coursera.org/learn/learning-how-to-learn&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  APIs Should Be Documented and Consistent
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tJSBMZOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/rest.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tJSBMZOO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/rest.png" alt="" class="wp-image-497"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;The second talk I want to mention was from &lt;a href="https://twitter.com/micheletitolo"&gt;Michele Titolo&lt;/a&gt;, a Lead Engineer. Her talked was titled **”APIs: The good the bad the ugly.”**about the good and bad parts of REST APIs. I just want to mention a few things about what makes a good API. A good API has many characteristics, but the three characteristics that stand out to me the most are consistency, semantic, and documented.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 Documented
&lt;/h3&gt;

&lt;p&gt;Web developers usually loath writing documentation which is odd because they love consuming great documentation. Documentation is actually just one part of being a good web developer. Helping others understand how to use your code is essential for that code base to survive and thrive. An API that isn’t documented will probably never be used because it is not easy to understand and API from just looking at code alone.&lt;/p&gt;

&lt;p&gt;Good documentation of your API makes it better automatically by being more accessible. Here is a template I created for documenting a REST API as an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/rbk/c6d2e80c9f4830857cafa3d24e97e227"&gt;https://gist.github.com/rbk/c6d2e80c9f4830857cafa3d24e97e227&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2 Consistent
&lt;/h3&gt;

&lt;p&gt;Consistency of an API super important. Error codes, request payloads, and response types can be anything you want, just make sure it makes sense. This is important for code in general. You don’t want to mix JSON responses with XML responses. One way I have made error codes standard is by creating a standard object that follows the &lt;a href="https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#examples"&gt;API guidelines from Microsoft&lt;/a&gt; (Ironically they don’t always use this guide):&lt;/p&gt;

&lt;pre class="wp-block-code"&gt;&lt;code&gt;payload = {
    'error': {
        'code': 'InvalidParameter',
        'message': 'You sent the wrong parameter.'
    }
}
return Response(payload, status=406)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;
  
  
  Kanban is All About Flow Efficiency
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dvx8pIkD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/kanban-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dvx8pIkD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.richardkeller.net/wp/wp-content/uploads/2019/06/kanban-2.png" alt="" class="wp-image-498"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;The last talk I want to mention was from &lt;a href="https://twitter.com/paulmgower"&gt;Paul Gower&lt;/a&gt;. His talk was titled &lt;strong&gt;“Overcoming Delay – How The Best Devs Increase Productivity”.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I have heard the word Kanban, but I thought it meant moving todos from column to column. This talk opened my eye to the world of Kanban. Kanban is essentially about efficiency.&lt;/p&gt;

&lt;h3&gt;
  
  
  1 Flow Efficiency
&lt;/h3&gt;

&lt;p&gt;Kanban is not magic, it is a process to increase efficiency. The basic concept can be examined in “&lt;a href="https://en.wikipedia.org/wiki/Little%27s_law"&gt;Little’s Law.&lt;/a&gt;” The output stream is greater or equal to the input stream of work. This means having a stream of production move through an organization is imperative to satisfy customers on the other end of the production line to grow the business.&lt;/p&gt;

&lt;h3&gt;
  
  
  2 WIP (Work in progress)
&lt;/h3&gt;

&lt;p&gt;Kanban increases efficiency with the use of controlling WIP (Work in Progress). This control is intended to keep team from being overwhelmed with too much work like emails, questions, and tasks, etc that could decrease individual productivity.&lt;/p&gt;

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

&lt;p&gt;Tulsa’s 200OK Web Developer Conference is always a blast to attend. The conference always supplies me with relevant information that I can use in my day to day career as a Web Developer. I hope you found some of these tips and bits useful. Thanks for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  BONUS: Notes from the conference.
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Being a developer is not about money, it’s about solving problems.&lt;/li&gt;
&lt;li&gt;Developers need to be disciplined to finish projects.&lt;/li&gt;
&lt;li&gt;Algorithms and programming are two ways to express the same solution to a problem.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>growthmindset</category>
      <category>apis</category>
    </item>
  </channel>
</rss>
