<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Marc Nevin</title>
    <description>The latest articles on Forem by Marc Nevin (@m_nevin).</description>
    <link>https://forem.com/m_nevin</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%2F25456%2F353b5fbb-8310-407a-96f6-f951a59b3249.jpg</url>
      <title>Forem: Marc Nevin</title>
      <link>https://forem.com/m_nevin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/m_nevin"/>
    <language>en</language>
    <item>
      <title>Testing out Serverless Stack</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Thu, 18 Aug 2022 21:41:00 +0000</pubDate>
      <link>https://forem.com/m_nevin/testing-out-serverless-stack-4je9</link>
      <guid>https://forem.com/m_nevin/testing-out-serverless-stack-4je9</guid>
      <description>&lt;p&gt;A serverless approach can be really powerful. Developing software with serverless architectures and services can speed up development time, make managing infrastructure pain-free and typically are cheaper, more flexible solutions. But it's not without its challenges local testing and mocking can be a pain, debugging systems is more trawling logs than anything else, and monitoring and maintenance of dozens of small runtimes can be overly complex.  &lt;/p&gt;

&lt;p&gt;To alleviate these pains, people have been building a range of platforms and tools to help, with &lt;a href="https://www.serverless.com/" rel="noopener noreferrer"&gt;Serverless Framework&lt;/a&gt; being one of the best known, they allow you to build on the serverless promise and avoid some of the challenges. Some newer platforms are being developed leaning on lessons from earlier ones and leveraging some developments from cloud providers since. &lt;/p&gt;

&lt;h2&gt;
  
  
  A new challenger appears...
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://sst.dev/" rel="noopener noreferrer"&gt;Serverless Stack&lt;/a&gt; (SST), is one of the newer players that pitches itself to be the easiest way for your projects "to go from idea to IPO", selling itself as an end-to-end serverless development, deployment, and monitoring tool for building on AWS. It's pretty similar to the Serverless Framework but instead of relying on terraform, or specialised languages, it’s standing on the shoulders of &lt;a href="https://sst.dev/chapters/what-is-aws-cdk.html" rel="noopener noreferrer"&gt;CDK&lt;/a&gt;; allowing you to write and maintain your infrastructure in the same languages you're developing with and push them to AWS as configured stacks. &lt;/p&gt;




&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;p&gt;Serverless Stack has a few key features worth digging into. &lt;/p&gt;

&lt;h3&gt;
  
  
  Constructs
&lt;/h3&gt;

&lt;p&gt;Serverless Stack uses &lt;a href="https://aws.amazon.com/cdk/" rel="noopener noreferrer"&gt;CDK&lt;/a&gt;, one of AWS’ better &lt;a href="https://sst.dev/chapters/what-is-infrastructure-as-code.html" rel="noopener noreferrer"&gt;IaC&lt;/a&gt; tools, which allows you to write and persist your cloud infrastructure in familiar languages; a key feature of CDK and SST is its use of high level components called constructs. These are preconfigured infrastructure components and structures that allow you to build faster by leveraging predefined configurations, boilerplates, and pre-written glue logic. SST then builds on these constructs refining them even further, although currently it only supports a few services, into an even more concise version. Allowing for building out of several components that go into making something like an API in a few lines. They currently have a load of constructs supporting A few key patterns, you can see the full list &lt;a href="https://docs.sst.dev/constructs" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Live Lambdas
&lt;/h3&gt;

&lt;p&gt;Normally, when developing serverless functions, you've got to either deploy and test your changes with live invocations, or locally run the lambda with heavy mocking, using libraries or manual stubs and time; SST proposes a novel solution to this, &lt;a href="https://docs.sst.dev/live-lambda-development" rel="noopener noreferrer"&gt;Live Lambdas&lt;/a&gt;. For testing and debugging, they've built functionality that creates a local dev environment that you can invoke from a testing stack the CLI deploys, meaning invocations to a live stack are directed to your local environment rather than a hosted lambda. This allows for local testing, debugging and live reloads, by creating a stub in debug stack that's deployed which redirects invocations of the stub to a local WebSocket and then our Lambda code. This allows us to edit, watch and debug it live, with native support for a few major editors, such as VSC, allowing you to set and observe breakpoints in your editor. There’s a diagram from their docs that helps explain the flow. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  SST Dashboard
&lt;/h3&gt;

&lt;p&gt;Another feature, one you see with similar tools, is a browser based &lt;a href="https://docs.sst.dev/console" rel="noopener noreferrer"&gt;console&lt;/a&gt; for observation and monitoring of your local and deployed stacks. It allows you to inspect various aspects of your application, seeing real-time logs in your app, shows you all resources in your stacks and allows you to manually invoke and replay invocations to your services.  &lt;/p&gt;

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

&lt;p&gt;It also allows you to explore different resources, such as Databases and Cognito pools, allowing you to see and query the data, users, and configuration of components in your app. It can be connected to local and live remote environments allowing you to see test and debug data, or live data from CloudWatch and other services. Making it pretty useful in developing your application, preloading any data for testing and teasing out any issues when connecting services together. &lt;/p&gt;




&lt;h2&gt;
  
  
  Spiking the Service
&lt;/h2&gt;

&lt;p&gt;SST sounded promising, so to test it out, I spiked those key features, aiming for a quick test, I aimed to build out a serverless 3 tier application using it; building a simple React frontend, an API accepting form data, and a table storing the form data.  &lt;/p&gt;

&lt;p&gt;Since SST is built around a series of NPM packages, the only prerequisites it has is NPM and making sure you’ve the AWS CLI already &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html" rel="noopener noreferrer"&gt;configured&lt;/a&gt;. From there we can use SST and its templates to create our project structure, navigate into the created folder and kick off the project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;npx create-sst@latest &lt;span class="nt"&gt;--template&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;starters/typescript-starter react-app 

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;react-app 

&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;This uses an SST template to generate the structure we need for a TypeScript React app in seconds, from there we can start our stack from NPX and it’ll deploy the basic structure for the first time, within 5-10 minutes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;
npx sst start 

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

&lt;/div&gt;



&lt;p&gt;From this point, we’ve deployed a basic app that’s observable from the SST console and we can build on towards our goal, it’s fairly straight forward. Rather than repeating SST’s tutorials and “getting started” content here, it makes more sense to direct you to their a great guide covering a simple counter React App using the same services I used, that you can check that out &lt;a href="https://sst.dev/examples/how-to-create-a-reactjs-app-with-serverless.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Rather than abridging their guides, I’ve pulled out a sample to show just how concisely it allows you to build. The &lt;code&gt;stacks/MyStack.ts&lt;/code&gt; file allows you to implement the new resources in one line, so at the end of that guide the top of that file has;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

    &lt;span class="nx"&gt;StackContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

    &lt;span class="nx"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

    &lt;span class="nx"&gt;ReactStaticSite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

    &lt;span class="nx"&gt;Table&lt;/span&gt;  

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@serverless-stack/resources&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;With a few lines for defining each, for example an API with a POST endpoint is defined with;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Api&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;API&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

    &lt;span class="na"&gt;defaults&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

      &lt;span class="na"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

        &lt;span class="c1"&gt;// Allow the API to access the table &lt;/span&gt;

        &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 

        &lt;span class="c1"&gt;// Pass in the table name to the API &lt;/span&gt;

        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

          &lt;span class="na"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tableName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

        &lt;span class="p"&gt;},&lt;/span&gt; 

      &lt;span class="p"&gt;},&lt;/span&gt; 

    &lt;span class="p"&gt;},&lt;/span&gt; 

    &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 

      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST /&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;functions/lambda.handler&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 

    &lt;span class="p"&gt;},&lt;/span&gt; 

  &lt;span class="p"&gt;});&lt;/span&gt; 

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

&lt;/div&gt;



&lt;p&gt;This defined most of the bare bones of the API in a few lines, an API gateway with an endpoint directed at a Lambda Handler, the environment variables setup for the table you want to use accessible for it. It's easily extended allowing you to add more routes or features to get it production ready fairly easily.  &lt;/p&gt;

&lt;p&gt;Overall, its surprisingly painless to work with, the constructs enabled rapid standing-up of services, the live debugging was useful for testing and trying different requests and the console allowed us to monitor the debug stack and check invocations locally without having to constantly redeploy the stacks. It had a surprising amount of utility in the time we used it, living up to the simplicity and speed promises of the website. &lt;/p&gt;




&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;After spiking it there's still some broader benefits and limitations worth addressing. &lt;/p&gt;

&lt;h3&gt;
  
  
  NPM - It's the devil
&lt;/h3&gt;

&lt;p&gt;Package management was a challenge, there was a torrent of version clashes between libraries and dependencies that had no easy solution without diving into the weeds which was beyond the scope for me. I imagine with some time you could untangle the knots of dependencies, but a major issue or vulnerability logged with an old version could throw this all up again creating a maintenance overhead. &lt;/p&gt;

&lt;h3&gt;
  
  
  Live Lambdas ... are Live?
&lt;/h3&gt;

&lt;p&gt;Live lambdas are pretty effective, but they are still &lt;em&gt;live&lt;/em&gt; and how easy they were to deploy seems like we could easily accidentally leave some resources running and lead to a wave of security confusion or unplanned cloud spend without any awareness. Security given you might have unprotected and poorly configured endpoints live and spend from leaving resources running accidentally. There's very clearly easy remediations here but in reading the docs it wasn't something jumping out, seems like an easy way to burn yourself on the tool. &lt;/p&gt;

&lt;h3&gt;
  
  
  Console Sync
&lt;/h3&gt;

&lt;p&gt;The console and the CLI tool are pretty great, fairly easy to use and straightforward. Unless you manage to have a change in the stack that isn't reflected in the SST Console; when they end up out of sync, fixing them wasn't as simple as turning them off and on, it lead to a lot of manual stack task killing, and console reviews until finally killing off enough that the console accepted something had went wrong and it was able to successfully tear down its own provisioned stack. Recommendation here would be making sure whatever IAM role you setup to use with SST is configured that you can manage its resources and add separate monitoring. &lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;Frustratingly, a lot of the places SST struggled, where also the places with the most utility and hope. &lt;/p&gt;

&lt;h3&gt;
  
  
  NPM - Package management for the whole team
&lt;/h3&gt;

&lt;p&gt;As much as dependency issues are a nightmare, when working in a team, a lot of people have had some interactions with NPM, so they're often somewhat familiar with how it works, how to use it and working with it in a team. It feels "lightweight" and familiar to a lot of people and familiarity would make adopting something like SST into your team a lot more straightforward. &lt;/p&gt;

&lt;h3&gt;
  
  
  Local Debugging and Testing
&lt;/h3&gt;

&lt;p&gt;Working in VSC and setting breakpoints without having to worry about stubs and mocks was a dream, it sped up the process of chasing down any issues in the course of this spike and it seems like scaling this out to a full-scale project it'd pay dividends for larger features. &lt;/p&gt;

&lt;h3&gt;
  
  
  Detailed Dashboards
&lt;/h3&gt;

&lt;p&gt;A lot of similar tools have UIs and consoles like this, and much like those, it has a fair amount of utility, being able to inspect and review different aspects of requests to the API, replay them and trace locally would be invaluable. Being able to inspect and review Cognito setups or data in a DB locally would save time trawling through the AWS console, even to those well acquainted. It was a big-time saver and generally just improved the Developer Experience (DevEx). &lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;SST is an interesting tool; it feels like it’s still maturing but it's got a lot of potential and if you can afford / make an early adoption of it on a project I think you'll be able to see fairly big payoff for DevEx and time saving down the line at the cost of some granular control and power. Overall, I think a small team who want to move fast and build an early version of an AWS backed application could do some great things with it early.  &lt;/p&gt;

&lt;p&gt;Personally, I’m going to try it out on something larger scoped next and see about working with it more in a collaborative setting before looking at a larger adoption.  &lt;/p&gt;




&lt;p&gt;Cover Image Credit - Photo by &lt;a href="https://unsplash.com/@rstone_design?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Ryan Stone&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/stacks?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image Credit - &lt;a href="//sst.dev"&gt;ServerlessStack&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>productivity</category>
      <category>cloud</category>
    </item>
    <item>
      <title>A Guide to Giving Better Feedback</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Wed, 21 Oct 2020 09:48:29 +0000</pubDate>
      <link>https://forem.com/m_nevin/a-guide-to-giving-better-feedback-2bf4</link>
      <guid>https://forem.com/m_nevin/a-guide-to-giving-better-feedback-2bf4</guid>
      <description>&lt;p&gt;Feedback is essential for growth, and by encouraging the right behaviours, you'll see your team develop their skills and an increase in their overall performance. Feedback doesn't need to wait for an annual review; frequent focused feedback and communication helps you build a better relationship with your team based on mutual understanding and candour. &lt;/p&gt;

&lt;p&gt;Taking the time to give and get regular feedback can be a building block towards psychological safety within your team that you'll see real benefits from. But giving good feedback is a skill, and like every skill, it gets better with practice; this post is written to help you focus, structure and deliver your feedback in a better way, today.&lt;/p&gt;

&lt;p&gt;First, it's important to think about why you want to give someone feedback - what's your motivation for it? The goal should be to improve their performance and help develop your team, not to vent some grievances with the individual. Giving good feedback can feel easy, and bad feedback can be hard to handle objectively, focusing on what makes it constructive and an asset to the individual is where we start. &lt;/p&gt;

&lt;h1&gt;
  
  
  What makes good feedback?
&lt;/h1&gt;

&lt;p&gt;There are a few aspects you should consider when planning feedback you want to give someone;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Specific&lt;/strong&gt;: Feedback should contain specific, factual examples rather than a generalisation, examples help them tie it back to their experience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Usable&lt;/strong&gt;: Try to tie the feedback to clear actions and goals, don't make it esoteric, enable the individual to improve their performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clear&lt;/strong&gt;: Clarify understanding, make sure they are getting the most out of the feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Punctual&lt;/strong&gt;: Feedback should be given as soon as possible after the situation, giving it closer to the event helps reinforce good behaviour or action bad. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Desired&lt;/strong&gt;: Feedback can still be effective even in those who don’t actively seek it, but it can also affect trust and relationships if demonstrated inappropriately. This extends to where you deliver it, pick a safe environment, don't air dirty laundry in public.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objective&lt;/strong&gt;: Feedback should be unbiased and unprejudiced; don't let your personal relationship with the person get in the way, especially if it's formal feedback that'll be stuck with them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Structuring with Feedback Models
&lt;/h1&gt;

&lt;p&gt;There are a bunch of models you can use to better structure feedback and help focus on concise points, rather than dancing around it. We'll cover the three most popular here;&lt;/p&gt;

&lt;h2&gt;
  
  
  "The Feedback Sandwich" (aka "s*** sandwich")
&lt;/h2&gt;

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

&lt;ol&gt;
&lt;li&gt;Give positive feedback;&lt;/li&gt;
&lt;li&gt;Constructive or negative feedback;&lt;/li&gt;
&lt;li&gt;End with targeted feedback to build trust and comfort&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is a fairly weak model, it's common and easy to recognise; often feels like a cheap move as its often used really to convey negatives wrapped to some placid ones. People see through it. It develops into a culture built on saving face and evasion, not of candour and respect. Avoid it, we can do better.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;S&lt;/strong&gt;ituation, &lt;strong&gt;B&lt;/strong&gt;ehaviour, &lt;strong&gt;I&lt;/strong&gt;mpact
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bmct2TJ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uljc7qg0crzxhrbkfdo4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bmct2TJ4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/uljc7qg0crzxhrbkfdo4.png" alt="Situation Behaviour impact diagram" width="880" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the situation the feedback refers to;&lt;/li&gt;
&lt;li&gt;Define the specific behaviours you want to address, for good or for bad;&lt;/li&gt;
&lt;li&gt;End by describing how their behaviours impacted you or others.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A much better model, and one I find myself using the most; it's a simple structure that lends itself to a more concise piece, often of written feedback, that feels real and direct. The idea of focusing on specific situations and impacts helps keep emotion out of the feedback and allows for a truer reflection on their actions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pendleton’s Model of Feedback
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iSrjMAbx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmfhp31xjwn55m5kmmvq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iSrjMAbx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/xmfhp31xjwn55m5kmmvq.png" alt="Pendletons's Model Diagram showing different stages of the process" width="880" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask them to highlight positive behaviours, reinforce what went well;&lt;/li&gt;
&lt;li&gt;Then ask to highlight areas for improvement, reinforce what could be improved;&lt;/li&gt;
&lt;li&gt;Discussion of an improvement plan going forwards;&lt;/li&gt;
&lt;li&gt;Agreeing on the plan and summarising key points.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A structure that only works when feedback is sought out, it allows the individual receiving the feedback to be more open and start the conversation; It helps them feel like they have a voice. It's good for building trust and mutual understanding and works well in a longer-term ongoing system of feedback.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next Steps
&lt;/h1&gt;

&lt;p&gt;Giving feedback can feel daunting, but with an understanding of the components of good feedback and some structure, it should be easy to start compiling some feedback for your colleagues when they come looking for it!&lt;/p&gt;

&lt;p&gt;Think about who would appreciate some feedback from you today, who can you start preparing feedback for and who will really appreciate it?&lt;/p&gt;




&lt;p&gt;This post was compiled from my notes on the topic over the last few months, if you have a good method or any tips I've missed, please share it below or reach out with any questions you might have!&lt;/p&gt;

&lt;p&gt;Cover photo by &lt;a href="https://unsplash.com/@charlesdeluvio?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Charles Deluvio&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>career</category>
      <category>productivity</category>
      <category>leadership</category>
      <category>management</category>
    </item>
    <item>
      <title>Wisdom of the Crowds, Using Twitter API v2</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Thu, 24 Sep 2020 21:33:35 +0000</pubDate>
      <link>https://forem.com/m_nevin/wisdom-of-the-crowds-using-twitter-api-v2-jln</link>
      <guid>https://forem.com/m_nevin/wisdom-of-the-crowds-using-twitter-api-v2-jln</guid>
      <description>&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Wisdom_of_the_crowd" rel="noopener noreferrer"&gt;Wisdom of the Crowds&lt;/a&gt; is a concept that states that averaging a large group's opinions, or guesses, smoothes out their bias and noise to give a measured opinion or the right answer. Using this concept and the new Twitter API - can we start winning some competitions?&lt;/p&gt;




&lt;h1&gt;
  
  
  The Idea
&lt;/h1&gt;

&lt;p&gt;It's a pretty interesting concept and reading about it again recently in &lt;a href="https://amzn.to/3i3rRLW" rel="noopener noreferrer"&gt;Thinking, Fast and Slow&lt;/a&gt; got me thinking about a short project to try out the new Twitter API. The author points specifically at challenges to guess the number of 'things' in a jar, individuals are often wrong but in theory, averaging the values should give you the winning answer!&lt;/p&gt;

&lt;p&gt;So, there's the odd competition like this on Twitter, let's see if we can weaponise the new Twitter API to win some prizes?&lt;/p&gt;

&lt;h1&gt;
  
  
  Twitter API
&lt;/h1&gt;

&lt;p&gt;The new version of Twitter's API is in early access with a limited number of endpoints but it already looks interesting; it can't be worse than the restricted original right?&lt;/p&gt;

&lt;p&gt;To test out this idea, we'll need a developer account to get started, you can &lt;a href="https://developer.twitter.com/en/apply-for-access" rel="noopener noreferrer"&gt;apply for access here&lt;/a&gt;. Once approved there are a few steps for setting up a &lt;a href="https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/quick-start" rel="noopener noreferrer"&gt;new project&lt;/a&gt; that are covered well in their new guides and far quicker than the original. I already had an account and more or less right away had a project set-up with keys generated. No more long waiting just to test out some ideas in a throwaway project.&lt;/p&gt;

&lt;p&gt;Before building something out, we'll need to see if we can access the tweets for the competitions and prototype the calls we'll need to get the guesses. The docs &lt;a href="https://documenter.getpostman.com/view/9956214/T1LMiT5U" rel="noopener noreferrer"&gt;link off&lt;/a&gt; to a prebuilt collection for Postman that lets us get started right away! (+1 for API V2)&lt;/p&gt;

&lt;h1&gt;
  
  
  Postman Prototyping
&lt;/h1&gt;

&lt;p&gt;We'll pick this competition as our target since it's already over and we have the answer;&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1293279536294105088-459" src="https://platform.twitter.com/embed/Tweet.html?id=1293279536294105088"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1293279536294105088-459');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1293279536294105088&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;Then rushing in without reading the &lt;a href="https://developer.twitter.com/en/docs/twitter-api/tweets/filtered-stream/introduction" rel="noopener noreferrer"&gt;docs&lt;/a&gt;, we can use the Tweet's ID (from the URL) and the &lt;a href="https://developer.twitter.com/en/docs/twitter-api/tweets/lookup/quick-start" rel="noopener noreferrer"&gt;Tweet Lookup Request&lt;/a&gt; we can get the &lt;a href="https://developer.twitter.com/en/docs/twitter-api/conversation-id" rel="noopener noreferrer"&gt;conversationID&lt;/a&gt;, which all replies and retweets will include, so we can use to filter tweets for it. We need to add in our Bearer Token before we can get the response, we can generate it through the Auth page for the project on the Twitter Developer Portal. When that's in we can send the request and get something like this;&lt;/p&gt;

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

&lt;p&gt;Great - now we have the conversation ID, we can use the &lt;a href="https://developer.twitter.com/en/docs/twitter-api/tweets/filtered-stream/introduction" rel="noopener noreferrer"&gt;Filtered Stream&lt;/a&gt; endpoint to get the guesses!&lt;/p&gt;

&lt;p&gt;Adding a rule to the stream to filter for the conversation ID, starting to stream in... nothing? Wait, what?&lt;/p&gt;

&lt;p&gt;Back to the docs... ohhhh, ohhhh, oh.... oh. &lt;/p&gt;

&lt;p&gt;So that's not how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/l3fZOxBdAIOiyt8CQ/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l3fZOxBdAIOiyt8CQ/giphy.gif" alt="That's not how the force works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, streaming - very cool but; &lt;br&gt;
1) doesn't work on Postman, &lt;br&gt;
2) It's a stream... it's new, not historic... &lt;/p&gt;

&lt;p&gt;The docs quite clearly state that it's for monitoring an event in real-time, streaming tweets in when the competition starts we'd be able to calculate the average as it changes, but for proving out our idea it's not much use. I'll be revisiting the streaming endpoint soon though - looks interesting.&lt;/p&gt;
&lt;h1&gt;
  
  
  Recent Search
&lt;/h1&gt;

&lt;p&gt;The correct endpoint is &lt;a href="https://developer.twitter.com/en/docs/twitter-api/tweets/search/introduction" rel="noopener noreferrer"&gt;Recent Search&lt;/a&gt;, here we can search for tweets that meet our filters up to one week old. &lt;br&gt;
Why one week? Good question - seems like it's because the API is in early access, historic tweets are on their &lt;a href="https://trello.com/b/myf7rKwV/twitter-developer-platform-roadmap" rel="noopener noreferrer"&gt;platform roadmap&lt;/a&gt; but not something we can use today.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Due to the time restriction, we can't recreate the response for running this on the competition above. It was well over a week when I initially drafted this. Picking some trending topic today will show it working. Luckily we have the data from the initial run after the competition ended.&lt;/p&gt;

&lt;p&gt;Running Recent Search with some parameters;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;query=conversationID:&amp;lt;id&amp;gt;&lt;/code&gt; - the competition tweet to filter for,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max_results=100&lt;/code&gt; - the maximum tweets per response,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tweet.fields=text&lt;/code&gt; - just giving us the text of the tweets&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;We get a response with a data section that has the tweets with that conversation ID and a &lt;code&gt;next_token&lt;/code&gt; parameter in the meta section. We can use this as a parameter in the next request, to get the next 'page' of tweets. As long as there's a &lt;code&gt;next_token&lt;/code&gt; parameter in the response, we know there are more pages to parse!&lt;/p&gt;

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

&lt;p&gt;But we can't do this paging or the logic we'll need to find our answer in Postman; it does allow us to convert the request to a bunch of popular tools and languages though. So, we can output a Python 3 (and requests as we don't hate ourselves) snippet and copy directly to a separate script.&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;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.twitter.com/2/tweets/search/recent?max_results=100&amp;amp;tweet.fields=text&amp;amp;query=conversation_id:&amp;lt;id&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;headers&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;Authorization&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;&amp;lt;Bearer Token&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&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;payload&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf8&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;h1&gt;
  
  
  Paging and Parsing
&lt;/h1&gt;

&lt;p&gt;Using the sample as a basis we need to add a little logic to handle the paging and parsing the tweets for the guesses. With a recursive call to handle the paging and a little regex to filter the numbers out we end left with something like this;&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;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ENDPOINT&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="n"&gt;conv_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;POSTFIX&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;next_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ENDPOINT&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="n"&gt;conv_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;POSTFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;TOKEN_PREFIX&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;next_token&lt;/span&gt;

    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&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;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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;tweetObj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweetObj&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="c1"&gt;# Regex - maybe not the most pythonic
&lt;/span&gt;        &lt;span class="n"&gt;guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\b\d+\b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tweet&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;guess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;guesses&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;guess&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;next_token&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;meta&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;token&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;meta&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;next_token&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="nf"&gt;build_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&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;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The Wisdom
&lt;/h1&gt;

&lt;p&gt;This leaves us with the list of 206 guesses, which some python builtins make short work of and give us an average of 820 beans in the jar.&lt;/p&gt;

&lt;p&gt;Which is exactly 100 out, the correct answer was 720 beans.&lt;/p&gt;

&lt;p&gt;Giving the theory the benefit of the doubt and a little visualisation later, I discovered there's a lot of outlier guesses. Some people entered things like '1' or values far too big to be a real guess; well that or they think the jar is massive.&lt;/p&gt;

&lt;p&gt;We can use &lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.trim_mean.html" rel="noopener noreferrer"&gt;SciPy's&lt;/a&gt; trimmed mean to take out around 10% of the values out from the ends gives us an answer of 761 beans - A much closer guess!&lt;/p&gt;

&lt;p&gt;With this relatively small sample of 206 guesses, I thought it was pretty impressive; unfortunately for us, someone guessed exactly right. But this theory was still considerably closer than my initial guess of 460. It'll be interesting to try it with a larger sample on the next competition I see!&lt;/p&gt;




&lt;p&gt;Overall, a quick intro to the Twitter API makes it look really interesting and I'll have to revisit it in future. You can read about more of my Python-related posts &lt;a href="https://dev.to/m_nevin"&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;span&gt;Cover photo by &lt;a href="https://unsplash.com/@morningbrew?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Morning Brew&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/span&gt; - They actually write a good newsletter - sign up &lt;a href="https://www.morningbrew.com/daily/r/?kid=0af228c8" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>postman</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Facial Analysis with Python and Amazon Rekognition</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Tue, 19 May 2020 14:31:22 +0000</pubDate>
      <link>https://forem.com/m_nevin/facial-analysis-with-python-and-amazon-rekognition-2il9</link>
      <guid>https://forem.com/m_nevin/facial-analysis-with-python-and-amazon-rekognition-2il9</guid>
      <description>&lt;p&gt;Cameras are getting smarter, they're changing how we manufacture goods, how we drive our cars and even, for good or bad, how surveillance is being carried out. &lt;/p&gt;

&lt;p&gt;And now it's getting even easier than ever to add this functionality to your solutions; it's becoming more democratised, allowing anyone to add features like facial analysis to their projects. One of the big players driving this is AWS, their goal is to put machine learning into the hands of every developer. For vision, they're doing it with &lt;a href="https://aws.amazon.com/rekognition/" rel="noopener noreferrer"&gt;Amazon Rekognition&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Amazon Rekognition
&lt;/h1&gt;

&lt;p&gt;Rekognition makes it easy to add image and video analysis to your applications using pre-trained models that require no machine learning know-how. It unlocks the ability to identify objects, people, text, and actions in images and videos, as well as detecting inappropriate content. &lt;/p&gt;

&lt;p&gt;One of the most impressive features is the highly accurate facial detection; you can use it to detect, analyze, and compare faces for a whole range of verification, behaviour and public safety use cases. This post will focus on those facial detection features and I'll cover some of the others in the future. &lt;/p&gt;

&lt;p&gt;So, let's get started!&lt;/p&gt;

&lt;h1&gt;
  
  
  Pre-requisites
&lt;/h1&gt;

&lt;p&gt;To try out Rekogniton you'll need to an &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/setting-up.html" rel="noopener noreferrer"&gt;AWS account&lt;/a&gt;, the team at AWS have a great guide on getting your account set-up properly with roles for developers; if you're starting fresh, you'll also need to install and configure the &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/setup-awscli-sdk.html" rel="noopener noreferrer"&gt;CLI&lt;/a&gt; - it'll handle storing credentials for the SDKs to use with Rekognion. For experimenting with Rekognition the &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/security_iam_id-based-policy-examples.html" rel="noopener noreferrer"&gt;full access role&lt;/a&gt; from the docs will work well, but for anything further, stick to granting the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege" rel="noopener noreferrer"&gt;least possible&lt;/a&gt; permissions.&lt;/p&gt;

&lt;p&gt;The examples covered in this post should fall under the AWS &lt;a href="https://aws.amazon.com/free/" rel="noopener noreferrer"&gt;Free Tier&lt;/a&gt; but it's worth checking out the &lt;a href="https://aws.amazon.com/rekognition/pricing/" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; for any service before getting started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Set-up
&lt;/h1&gt;

&lt;p&gt;We'll be using Python3 so we'll need the Python AWS SDK, called &lt;code&gt;boto3&lt;/code&gt;, to access Rekognition as well as any other AWS services,&lt;/p&gt;

&lt;p&gt;First, you need to install boto3 using &lt;a href="https://pypi.org/project/boto3/" rel="noopener noreferrer"&gt;PIP&lt;/a&gt;;&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;


&lt;p&gt;Then we can import boto into a new python file and set up a client, which acts as an interface to AWS to start using the facial detection functionality;&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;boto3&lt;/span&gt;

&lt;span class="c1"&gt;# Create a Rekognition client
&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rekognition&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;h1&gt;
  
  
  Detection
&lt;/h1&gt;

&lt;p&gt;Once you've got a client set up you can call the &lt;code&gt;detect_faces&lt;/code&gt; method with an image, the response will contain a full batch of info on any faces it detects. There's two ways to load images to Rekognition: byte arrays and S3.&lt;/p&gt;
&lt;h2&gt;
  
  
  S3
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The way&lt;/strong&gt; to store blobs on AWS - to use with Rekognition we just specify the bucket and file, pass it to Rekognition through our client and get our response.&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;response&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="nf"&gt;detect_faces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Image&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;S3Object&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;Bucket&lt;/span&gt;&lt;span class="sh"&gt;'&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&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;Using S3 allows easier integration to other services and images can be &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/user-guide/upload-objects.html" rel="noopener noreferrer"&gt;uploaded to S3&lt;/a&gt; anyway you normally would.&lt;/p&gt;
&lt;h2&gt;
  
  
  Byte Array
&lt;/h2&gt;

&lt;p&gt;We can also &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/images-bytes.html/" rel="noopener noreferrer"&gt;send images&lt;/a&gt; straight to Rekognition as a byte array. You can open the files as you would load any file in Python, using the built-ins;&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;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="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rekognition&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;photo.jpg&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;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&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="nf"&gt;detect_faces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Image&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;Bytes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&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;You can also try using webcams and directly firing images to Rekognition, you can access them with OpenCV, this Gist shows how you can use your Webcam with Rekognition;&lt;/p&gt;


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



&lt;h2&gt;
  
  
  Attribute Option
&lt;/h2&gt;

&lt;p&gt;There's another argument you can add to the request; &lt;code&gt;Attributes&lt;/code&gt;, you have two options &lt;code&gt;ALL&lt;/code&gt; or &lt;code&gt;Default&lt;/code&gt;. &lt;code&gt;Default&lt;/code&gt; returns BoundingBox, Confidence, Pose, Quality, and Landmarks for any faces in the image, so it &lt;em&gt;just&lt;/em&gt; detects the faces. &lt;code&gt;All&lt;/code&gt;, takes a fraction longer and returns a fuller set of information for any faces, everything from &lt;code&gt;Default&lt;/code&gt; and more interesting aspects like predicted emotions, age and gender.&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;response&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="nf"&gt;detect_faces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Image&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;S3Object&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;Bucket&lt;/span&gt;&lt;span class="sh"&gt;'&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;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;Attributes&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;ALL&lt;/span&gt;&lt;span class="sh"&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;h1&gt;
  
  
  Response
&lt;/h1&gt;

&lt;p&gt;After making the request, the response contains a set of "face details" for each face it detects in the image (up to around 40 faces). Here's a sample of an &lt;code&gt;ALL&lt;/code&gt; response;&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="p"&gt;{&lt;/span&gt;
   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FaceDetails&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
      &lt;span class="p"&gt;{&lt;/span&gt; 
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AgeRange&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;High&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Beard&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BoundingBox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Height&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Left&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Top&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Width&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Emotions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
            &lt;span class="p"&gt;{&lt;/span&gt; 
               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Type&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;string&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="p"&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;Eyeglasses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EyesOpen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Gender&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&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;string&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;Landmarks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
            &lt;span class="p"&gt;{&lt;/span&gt; 
               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Type&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;string&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;X&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Y&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
            &lt;span class="p"&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;MouthOpen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Mustache&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Pitch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Roll&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Yaw&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Quality&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Brightness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sharpness&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Smile&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;},&lt;/span&gt;
         &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sunglasses&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;boolean&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
   &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OrientationCorrection&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;string&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;A full breakdown of the response can be found in the &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectFaces.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt; but let's take a look at some of the most interesting aspects like landmarks and emotions.&lt;/p&gt;
&lt;h2&gt;
  
  
  Landmarks
&lt;/h2&gt;

&lt;p&gt;Landmarks are coordinates for points on the face, they're used for detecting the face itself and are points like different spots on the nose, eyes and jawline. This image from the docs shows roughly where they all are on the face:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F74d3g9ww4pzauwwxvz2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F74d3g9ww4pzauwwxvz2i.png" alt="Man's face with facial landmarks noted"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;From AWS docs&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Landmarks can provide a different way of understanding detected faces, to spark some ideas of interesting ways of using landmarks; here's a rough demo to work out what a male's face shape might be;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin243" rel="noopener noreferrer"&gt;
        Nevin243
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin243/face-shaper" rel="noopener noreferrer"&gt;
        face-shaper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      PoC to test if you can use CV to get someones "face-shape"
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  Face Details
&lt;/h2&gt;

&lt;p&gt;The details returned with the &lt;code&gt;ALL&lt;/code&gt; attributes call can be really useful, these are aspects like estimated age range, predicted gender, if they've facial hair and if the person is wearing glasses. &lt;/p&gt;

&lt;p&gt;Rekognition returns a dict that contains a boolean for the aspect and the confidence in the analysis. Here's a snippet for parsing the response to show the dict for detecting glasses on the faces in the scene:&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;for&lt;/span&gt; &lt;span class="n"&gt;faceDetail&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FaceDetails&lt;/span&gt;&lt;span class="sh"&gt;'&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;faceDetail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Eyeglasses&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="c1"&gt;# Example Output
# {'Value': False, 'Confidence': 98.8663558959961}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Detecting aspects like glasses or age allows us to do better understand demographics to tailor services during testing or verify information about who our users could be!&lt;/p&gt;
&lt;h2&gt;
  
  
  Emotions
&lt;/h2&gt;

&lt;p&gt;One of the most interesting aspects of Rekognition is the emotional analysis it can do. Understanding your user with the other details is useful but being able to see and understand exactly how they're reacting can create open up some really interesting opportunities.&lt;/p&gt;

&lt;p&gt;This snippet parses the emotions of the response and displays them all,  confidence indicates how likely the face is displaying that emotion:&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;for&lt;/span&gt; &lt;span class="n"&gt;faceDetail&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;FaceDetails&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Emotions: &lt;/span&gt;&lt;span class="se"&gt;\t&lt;/span&gt;&lt;span class="s"&gt; Confidence&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&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;emotion&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;faceDetail&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Emotions&lt;/span&gt;&lt;span class="sh"&gt;'&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="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;emotion&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Type&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="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\t\t&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="n"&gt;emotion&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Confidence&lt;/span&gt;&lt;span class="sh"&gt;'&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="sh"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Sample Output
# Emotions:     Confidence
# HAPPY     0.051588401198387146
# ANGRY     7.0355730056762695
# SAD       0.04484181851148605
# DISGUSTED 0.11442316323518753
# CONFUSED  0.2994600534439087
# FEAR      0.013996988534927368
# CALM      90.5924301147461
# SURPRISED 1.8476886749267578
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This on can be quite fun to play around with trying to see what gets a 'Disgusted' response rather than 'Calm' but it can be really useful, being able to even get a rough sentiment read on someone interacting with your application can be really valuable. &lt;/p&gt;
&lt;h1&gt;
  
  
  Streaming, Comparing and Videos
&lt;/h1&gt;

&lt;p&gt;Rekognition features are a lot broader than what's been covered here but when it comes to faces, you can stream pictures in with &lt;a href="https://aws.amazon.com/kinesis/" rel="noopener noreferrer"&gt;kinesis&lt;/a&gt;, pass batches of images or create collections of images to sample and analyse. &lt;br&gt;
You can use &lt;a href="https://docs.aws.amazon.com/rekognition/latest/dg/API_CompareFaces.html" rel="noopener noreferrer"&gt;compare faces&lt;/a&gt;among these data collections, check if the faces are celebrities, or even begin to track movement across images and video. &lt;/p&gt;

&lt;p&gt;To take any of these further you'll want to take a proper look at the &lt;a href="https://docs.aws.amazon.com/rekognition/index.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;!&lt;/p&gt;



&lt;p&gt;Hopefully, this has shown you that when used responsibly it can be a fantastic tool and how to start experimenting with facial detection and analysis! &lt;/p&gt;

&lt;p&gt;Want to see some really impressive Rekognition example projects to check out? There's a bunch at the official AWS samples &lt;a href="https://github.com/aws-samples?q=rekognition&amp;amp;type=&amp;amp;language=" rel="noopener noreferrer"&gt;repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to learn more about AWS in general? A great place to start is their Certs here's a post I wrote after getting my first!&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/m_nevin" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F25456%2F353b5fbb-8310-407a-96f6-f951a59b3249.jpg" alt="m_nevin"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/m_nevin/a-journey-through-the-amazon-3amh" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;A Journey Through the Amazon&lt;/h2&gt;
      &lt;h3&gt;Marc Nevin ・ Mar 2 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#aws&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#career&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#devops&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;And don't forget to take a look at other posts with the AWS Tag:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__tag ltag__tag__id__397"&gt;
    &lt;div class="ltag__tag__content"&gt;
      &lt;h2&gt;#&lt;a href="https://dev.to/t/aws" class="ltag__tag__link"&gt;aws&lt;/a&gt; Follow
&lt;/h2&gt;
      &lt;div class="ltag__tag__summary"&gt;
        Amazon Web Services (AWS) is a collection of web services for computing, storage, machine learning, security, and more

There are over 200+ AWS services as of 2023.
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>aws</category>
      <category>python</category>
      <category>cv</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How Are You Staying Healthy During Lockdown?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Wed, 22 Apr 2020 12:07:47 +0000</pubDate>
      <link>https://forem.com/m_nevin/how-are-you-staying-healthy-during-lockdown-23pd</link>
      <guid>https://forem.com/m_nevin/how-are-you-staying-healthy-during-lockdown-23pd</guid>
      <description>&lt;p&gt;How is everyone handling staying healthy and happy during your lockdown? any tips/tricks? What's working for you and what's not?&lt;/p&gt;

&lt;p&gt;It's made me take running up again, and I'm starting to actually enjoy it! After work, if I've not been on a run, I've been going on a pretty big walk - try and make up for sitting in all day.&lt;/p&gt;

&lt;p&gt;Been really conscious of what I'm eating too and keeping a good record of my weight too (I actually have a dataset which is kinda weird) since I'm generally being less active&lt;/p&gt;

&lt;p&gt;How's everyone else coping?&lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What Makes A Great Tutorial?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Fri, 17 Apr 2020 11:17:17 +0000</pubDate>
      <link>https://forem.com/m_nevin/what-makes-a-great-tutorial-2jc1</link>
      <guid>https://forem.com/m_nevin/what-makes-a-great-tutorial-2jc1</guid>
      <description>&lt;p&gt;Everyone learns in different ways but something you usually can't escape is tutorials for new concepts, but what makes a tutorial great for you?&lt;/p&gt;




&lt;p&gt;My team and I spend our time jumping around a load of different stacks or pieces of tech to test concepts for the business, build out some prototypes and try and integrate some of the newer ideas into our existing solutions!&lt;/p&gt;

&lt;p&gt;To build these ideas out, we end up reading a load of docs, academic papers and combing search results for what the best tutorials or breadcrumbs to start out - over time we've got this down to a fine art. Most of the time, we can quickly pick up a post and decide to move on or keep reading,&lt;/p&gt;

&lt;p&gt;There are some standout points that push one a tutorial one way or the other for me are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clarity &amp;amp; communication - how easy it is to read&lt;/li&gt;
&lt;li&gt;Length &amp;amp; depth - is it a simple vertical or a step by step to a specific goal&lt;/li&gt;
&lt;li&gt;Explained code snippets as a % of the content&lt;/li&gt;
&lt;li&gt;Links to further resources &amp;amp; repos&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is my personal preference, and I'm sure everyone has something different, so what makes a &lt;strong&gt;great&lt;/strong&gt; tutorial for you?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>tutorial</category>
      <category>writing</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Learn a New Language: Ruby or Go?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Thu, 09 Apr 2020 11:25:22 +0000</pubDate>
      <link>https://forem.com/m_nevin/learn-a-new-language-ruby-or-go-3ifh</link>
      <guid>https://forem.com/m_nevin/learn-a-new-language-ruby-or-go-3ifh</guid>
      <description>&lt;p&gt;I'm lucky enough that I can take my time on lockdown to build some backlogged projects, draft some posts and develop some new skills, one thing I've been thinking about is learning some core concepts of a new language.&lt;/p&gt;

&lt;p&gt;After looking at what I enjoy, what's &lt;a href="https://www.tiobe.com/tiobe-index/"&gt;popular&lt;/a&gt; and what's actually used, I've narrowed it down to Ruby and Go,&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for Ruby
&lt;/h2&gt;

&lt;p&gt;So many tools I love to use are built with Ruby and loads of great websites are written in Rails. Makes me think there's some real utility there I could start leveraging in my own solutions, not to mention Rails opens a new avenue for webdev!&lt;/p&gt;

&lt;p&gt;The only hold-ups I have, it's not got a popular reputation locally, there are a few product teams that use it and talk regularly about how there's not many jobs in it and that they hope to migrate to something else...&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for Go
&lt;/h2&gt;

&lt;p&gt;Go has a certain appeal to me - most of my stack is Python-based with some JavaScript, using AWS; I used to work in a C/C++ stack and the promises of efficiency, combing my old domain with my current and "easy" integration to my current stack make it hard to not notice.&lt;/p&gt;

&lt;p&gt;And again a lot of great tools and services are being built in it or things that were once Python (still my fav) are being ported to Go now, it seems a little less broad spectrum of services built with it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Decisions, decisions
&lt;/h2&gt;

&lt;p&gt;I'm leaning towards Go, but want some input, I know very few people who actively use either to draw from, anything I've found normally has a strong agenda, so I want to ask here, see what people think and crowdsource some opinions!&lt;/p&gt;

&lt;p&gt;Which would you recommend starting with and why? &lt;/p&gt;

&lt;p&gt;or if you've any strong experiences working on either, think one is easier to learn etc etc&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ruby</category>
      <category>go</category>
      <category>beginners</category>
    </item>
    <item>
      <title>When's the Best Time to Post on Dev.to?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Sat, 04 Apr 2020 14:53:45 +0000</pubDate>
      <link>https://forem.com/m_nevin/when-s-the-best-time-to-post-on-dev-to-5824</link>
      <guid>https://forem.com/m_nevin/when-s-the-best-time-to-post-on-dev-to-5824</guid>
      <description>&lt;p&gt;&lt;em&gt;Using Python to work out visualise the best times and topics on Dev.to&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Having an international community on Dev.to means that there are users active all around the clock, that makes it hard to understand when the community is the most active. Knowing this helps understand your audience more and helps you get the most engagement with the content you're posting.&lt;/p&gt;

&lt;p&gt;With some simple Python, we can work out as much as we can about the users of Dev.to and their behaviour, like when we should be posting to get it in front of as many people as we can. Not to mention, its a good chance to learn something about data prep and manipulation.&lt;/p&gt;




&lt;p&gt;Last year, I worked on a project to understand what users were posting on my company's Yammer, think company Facebook; we were using python to track engagement on topics my team were interested in, how they were being perceived and when they were being interacted with. While looking around for some visualisation ideas, I saw &lt;a href="https://dev.to/daolf"&gt;Pierre's&lt;/a&gt; post about the best time to post here,&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/daolf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F128882%2F9f096743-b461-4de9-b6fa-660a294dc1c6.png" alt="daolf"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/daolf/-what-is-the-best-time-to-post-on-devto-a-data-backed-answer--1kob" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What is the best time to post on dev.to? a data-backed answer 🕰🦄🤷‍♂️&lt;/h2&gt;
      &lt;h3&gt;Pierre  ・ Mar 24 '19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#python&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#meta&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Now that I've started posting here more regularly, I thought I'd try something similar, so I decided to try a short project to understand more about the users here when they are reading, are there any trends and what topics they interact with the most. &lt;/p&gt;




&lt;p&gt;To try to understand the reader, we need to work out what determines a successful post - normally that's read numbers, comments and reactions. &lt;/p&gt;

&lt;p&gt;Since we can't get reads numbers for every post, we'll look at reactions as the two are strongly linked; more reacts, more reads and more reads, more reacts. So, reactions will be the metric we use to determine the users behaviour or response to a post!&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting Data
&lt;/h1&gt;

&lt;p&gt;First, we need data.&lt;/p&gt;

&lt;p&gt;We need to know how the previous posts have performed, luckily the team here have a great &lt;a href="https://docs.dev.to/api/"&gt;API&lt;/a&gt; for us to use! &lt;/p&gt;

&lt;p&gt;Using Python and the &lt;a href="https://requests.readthedocs.io/en/master/" rel="noopener noreferrer"&gt;requests&lt;/a&gt; library, we can call the API and build up a JSON lines file of every post:&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;# To get the first page on articles on Dev.to
&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://dev.to/api/articles&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;payload&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;page&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;raise_for_status&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Splitting out the payload lets us iterate up the page value and get all posts up to a set page number, using this we can grab every post or aim for a rough date.&lt;/p&gt;

&lt;p&gt;Running this we can build up a dataset, but it needs some cleaning up, to get it into a more parsable format for the next library we're going to use - Pandas, alongside &lt;a href="https://numpy.org/" rel="noopener noreferrer"&gt;Numpy&lt;/a&gt; it's the backbone of data manipulation in Python.&lt;/p&gt;

&lt;p&gt;Using Pandas and a simple &lt;a href="http://book.pythontips.com/en/latest/generators.html" rel="noopener noreferrer"&gt;generator&lt;/a&gt; we can load the data into a 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;# Generator for data
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_line_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&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;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;

&lt;span class="n"&gt;json_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;json_line_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./data.json&lt;/span&gt;&lt;span class="sh"&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;json&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json_response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_json&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;sort&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html" rel="noopener noreferrer"&gt;Data frames&lt;/a&gt; are really useful, basically, it's a table with labelled rows and columns, that are highly flexible with a lot of functionality built-in. They're easily scaled and manipulated enabling a whole world of data manipulation with one library.&lt;/p&gt;
&lt;h1&gt;
  
  
  Prepping our Data
&lt;/h1&gt;

&lt;p&gt;Getting the data frame set-up, we can do some initial exploration and see we need to do the same thing Pierre did; split the date and time into their own columns to make it easier to manipulate. While we're here we can also drop the columns we're not interested in, like the cover image or canonical URL;&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;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;unwanted_columns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Splitting Timestamp into hour and day of week
&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hour&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;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;published_at&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hour&lt;/span&gt;
&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;day_of_week&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;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;published_at&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%A&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;h1&gt;
  
  
  When's the Best Time to Post?
&lt;/h1&gt;

&lt;p&gt;One of the first things we'll want to know about users is when they read posts and we can see this from when they are reacting to the posts. Part of the reason we broke it down into hours and not minutes is so we can make a generalisation, trying to estimate the time down to the minutes is too granular and won't really aid us any more than knowing the hour will.&lt;/p&gt;

&lt;p&gt;The best way to visualise this then, will be as a heatmap - we start by grouping the data we need, reaction count and timing, before pivoting the table so that its columns will be the days of the week:&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;# Get the average reactions per post at a given timeslot
&lt;/span&gt;&lt;span class="n"&gt;reaction_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;day_of_week&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;hour&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Pivot the dataframe &amp;amp; reorganise the columns
&lt;/span&gt;&lt;span class="n"&gt;reaction_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reaction_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hour&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;day_of_week&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;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;reaction_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reaction_df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Monday&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;Tuesday&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;Wednesday&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;Thursday&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;Friday&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;Saturday&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;Sunday&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;Then we use &lt;a href="https://seaborn.pydata.org/" rel="noopener noreferrer"&gt;Seaborn&lt;/a&gt;, a data visualisation library, to generate a heatmap:&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;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;sns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;heatmap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reaction_df&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coolwarm&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;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa6l8rb3wk0dzzh1jkkhd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa6l8rb3wk0dzzh1jkkhd.png" alt="Heatmap with outliers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And we hit a problem, there's no clear trend, sometimes that's just the case but this one hour on Sunday seems like an outlier. That time is a lot darker than the others - let's check, we can use a boxplot as a simple way of checking, again from Seaborn:&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;sns&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;boxplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reaction_df&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;Definitely an outlier, since we're making a generalisation, let's filter out the outliers and see how it affects our visualisation. Using &lt;a href="https://en.wikipedia.org/wiki/Standard_score" rel="noopener noreferrer"&gt;z score&lt;/a&gt; we can remove some of the outlier posts from our original data frame;&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;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zscore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reaction_df&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;reaction_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reaction_df&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;all&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;p&gt;This filtering removes some of the top-performing posts of all time, but enables a far more general view of how most posts perform when we generate our heatmap again!&lt;/p&gt;

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

&lt;p&gt;So that leaves us with a clear band; around midday UTC during the week!&lt;/p&gt;

&lt;p&gt;This is similar to Pierre's findings on time, but on a tighter band, could be down to the site's presence growing and having an even broader user base or just having another year worth of data!&lt;/p&gt;
&lt;h1&gt;
  
  
  Writing for a Specific Tag
&lt;/h1&gt;

&lt;p&gt;The heatmap was a very general, what if you only are interested in producing content around some specific tags, let's try out one of my favourites - Discuss;&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;# Tag to find map for
&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;discuss&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="n"&gt;tag_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;tag_df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tags&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;case&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;na&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;tag_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;day_of_week&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;hour&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;tag_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset_index&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pivot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hour&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;day_of_week&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;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;tag_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tag_df&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Monday&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;Tuesday&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;Wednesday&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;Thursday&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;Friday&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;Saturday&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;Sunday&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;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhn2qnz644xzzr7jm94r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhn2qnz644xzzr7jm94r8.png" alt="Discuss heatmap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Less clear, the problem is we're cutting out so much of our dataset, that we'll just start missing data that will begin skewing results. That said some of the most popular tags might have enough data to look into.&lt;/p&gt;
&lt;h1&gt;
  
  
  Engagement and Comments
&lt;/h1&gt;

&lt;p&gt;The discuss tag made me try something else, can we check for the link between how many people read and react to a post and how many people comment on it? This would be especially relevant for tags like discuss but generally if you want readers to interact with your post beyond just a react.&lt;/p&gt;

&lt;p&gt;We can use a &lt;a href="https://en.wikipedia.org/wiki/Partial_regression_plot" rel="noopener noreferrer"&gt;regression plot&lt;/a&gt; to compare the reactions with comments and see if there's a correlation:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sns.regplot(comment_df["comments_count"], comment_df["positive_reactions_count"])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;That's showing a moderate correlation, now that doesn't imply causation, but it's worth investing and trying out to investigate the link in the future.&lt;/p&gt;

&lt;p&gt;If we replace the reaction count in our previous heatmaps, with the comment count column and generate a new heatmap:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;comment_df = comment_df.groupby(["day_of_week", "hour"]) ["comments_count"].mean()
comment_df = comment_df.reset_index().pivot('hour', 'day_of_week', 'comments_count')
comment_df = comment_df[["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]]

plt.figure(figsize=(16, 16))
sns.heatmap(comment_df , cmap="coolwarm")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


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

&lt;p&gt;We can see there are two big clusters we can test in the future:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Very early mornings UTC on Saturday and Sunday&lt;/li&gt;
&lt;li&gt;And early evening 5/6 PM UTC Tuesday - Sunday&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using these trends could lead to a more engagement on your posts through comments and discussion, worth a shot to see if there is causation or if you want to engage more with your users.&lt;/p&gt;
&lt;h1&gt;
  
  
  What topics should we write about?
&lt;/h1&gt;

&lt;p&gt;Let's jump back to tags then, what if someone wants to go full SEO? What're the most popular topics and does this tell us anything about the community?&lt;/p&gt;

&lt;p&gt;To start we need to split the tag list column out into individual items, in Pandas, this used to be a massive pain but now its just a method call:&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;popular_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;popular_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;explode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tag_list&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fill in any gaps
&lt;/span&gt;&lt;span class="n"&gt;popular_df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tag_list&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;popular_df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tag_list&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;fillna&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;None&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;From there, we could sum by occurrences, but turns out this has already been done for &lt;a href="https://dev.to/tags"&gt;us&lt;/a&gt;! Some big ones you'd expect, Javascript etc, so definitely what users like to post about, but is this what the community wants? are these the most interacting with?&lt;/p&gt;

&lt;p&gt;If we first get the average reactions for comparison:&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;popular_df&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can then use our dataset, with outliers removed, to generate a list of the top tags with the highest average reaction count:&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;popular_sum_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;popular_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;groupby&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tag_list&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;positive_reactions_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;mean&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Get top 50 average posts
&lt;/span&gt;&lt;span class="n"&gt;popular_sum_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort_values&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="nf"&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;After giving some of the tags a check most are still fairly skewed by a couple highly reacted posts, compared to the average but some of the top tags aren't one-offs. They are tags that consistently performing well with good interaction, some at a quick look are;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Career&lt;/li&gt;
&lt;li&gt;Beginners&lt;/li&gt;
&lt;li&gt;Hooks&lt;/li&gt;
&lt;li&gt;SQL&lt;/li&gt;
&lt;li&gt;Learned&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(The full list of tags is available in the repo, take a look at them there)&lt;/p&gt;

&lt;p&gt;Some I expected (Careers), some I didn't (SQL) but it allows us to look at what content our users are really interested in and what's not. This means will can filter content that would work best on this site, playing off trends or topics that people care about here.&lt;/p&gt;


&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;Understanding your audience through data is only part of the puzzle, just posting at these times won't just instantly increase your read count. You still need to focus on understanding the end reader and producing high-quality content first!&lt;/p&gt;

&lt;p&gt;There's scope to take this further; what length or type of content performs best, is there any sentiment or structural aspects of a post that engages better and what topics are trending at a given time.&lt;/p&gt;

&lt;p&gt;To do any of this, we'd need to build a richer dataset, the API looks like it could be manipulated to do that but that's content for another post.&lt;/p&gt;

&lt;p&gt;If you want to try and start building something bigger, do this yourself or look at how quickly something like this can be done in python, the Jupyter notebook and scripts are available here;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Nevin243" rel="noopener noreferrer"&gt;
        Nevin243
      &lt;/a&gt; / &lt;a href="https://github.com/Nevin243/data-driven-posting" rel="noopener noreferrer"&gt;
        data-driven-posting
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      For working out the best times to post on Dev.to
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Now go spend some time trying to understand your reader, happy posting!&lt;/p&gt;

</description>
      <category>meta</category>
      <category>python</category>
      <category>jupyter</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Creating a Shared Vision</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Thu, 26 Mar 2020 15:58:51 +0000</pubDate>
      <link>https://forem.com/m_nevin/creating-a-shared-vision-1g77</link>
      <guid>https://forem.com/m_nevin/creating-a-shared-vision-1g77</guid>
      <description>&lt;p&gt;It can be tough to keep teams motivated. &lt;/p&gt;

&lt;p&gt;One thing we know works is making sure everyone understands and appreciates the impact of the teams work, that their working on something that's not just interesting but really valuable for the company as a whole.&lt;/p&gt;

&lt;p&gt;We're noticing now that we're remote, some of the newer rotations into the team are struggling to see the value of their work and we're trying to be a bit proactive here; talking about the team's previous work and impact.&lt;/p&gt;

&lt;p&gt;But we're thinking longer-term how can we help create and foster a shared vision for the teams work going forwards?&lt;/p&gt;

&lt;p&gt;Currently, we're thinking;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making the team's guiding strategy more open and accessible&lt;/li&gt;
&lt;li&gt;Having the team's short and long term goals more visible&lt;/li&gt;
&lt;li&gt;Getting the whole team more involved in helping review the current mission statement&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We know there's always room to improve so, I'm interested in what else we can do to help the team really understand their value? How we can help encourage a shared vision? or what else we can do to make sure everyone's on the same page!&lt;/p&gt;

&lt;p&gt;If you've got any ideas or just want to share your thoughts please share below!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>motivation</category>
      <category>career</category>
      <category>remote</category>
    </item>
    <item>
      <title>How Do You Support Remote Juniors?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Mon, 16 Mar 2020 14:45:35 +0000</pubDate>
      <link>https://forem.com/m_nevin/how-do-you-support-remote-juniors-1nfo</link>
      <guid>https://forem.com/m_nevin/how-do-you-support-remote-juniors-1nfo</guid>
      <description>&lt;p&gt;With the recent news, a few of us are trying to encourage more remote working across the team and company, we've broad support and every day we're seeing more people moving remote!&lt;/p&gt;

&lt;p&gt;A few of us have been reading up on some good practices, reading some people's experiences and a pretty good &lt;a href="https://smile.amazon.co.uk/Remote-Required-David-Heinemeier-Hansson-ebook/dp/B00CZ7OC46/ref=sr_1_1?keywords=remote+book&amp;amp;qid=1584358588&amp;amp;sr=8-1"&gt;books&lt;/a&gt; on it!&lt;/p&gt;

&lt;p&gt;But something we're trying to understand is how we best support Juniors. Our team is currently pretty junior; from apprentices to graduates, this can mean they need a fair degree of support, from advice and direction to whiteboarding out problems with them.&lt;/p&gt;

&lt;p&gt;We want to make sure they continue to develop when we're not as easily accessible for just grabbing for 5 minutes while walking past.&lt;/p&gt;

&lt;p&gt;What can we do to better support Juniors? Are there tools and techniques you have found that work well? What's your experience working with junior staff remotely?&lt;/p&gt;




&lt;p&gt;Photo by &lt;a href="https://www.pexels.com/@bongkarn-thanyakij-683719"&gt;Bongkarn Thanyakij&lt;/a&gt; from Pexels&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>remote</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>What's your Conference Plan?</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Mon, 09 Mar 2020 11:26:01 +0000</pubDate>
      <link>https://forem.com/m_nevin/what-s-your-conference-plan-192n</link>
      <guid>https://forem.com/m_nevin/what-s-your-conference-plan-192n</guid>
      <description>&lt;p&gt;Recently, my job has had me going to a lot of conferences and events, &lt;a href="https://techcrunch.com/2020/03/06/sxsw-cancelled/"&gt;current news aside&lt;/a&gt;,  conferences are going to eventually start back up, &lt;/p&gt;

&lt;p&gt;During this conference lull, I've been thinking about how to get the most out of them when they're back and some people have been giving me advice on "How to conference"&lt;/p&gt;

&lt;p&gt;Some of its been pretty solid advice;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't try to plan more than two things you want to do a day&lt;/li&gt;
&lt;li&gt;Don't feel you need to "get your money's worth"&lt;/li&gt;
&lt;li&gt;Try and attend one thing a day outside normal events you'd attend&lt;/li&gt;
&lt;li&gt;Conferences are the best time to catch local people you've been struggling to find time with&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;But now, it's time to crowdsource some wisdom!&lt;/p&gt;

&lt;p&gt;How do you plan for conferences? Do you have any tips? How do you get the most out of the opportunities and networking?&lt;/p&gt;




&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@jakobdalbjorn"&gt;Jakob Dalbjörn&lt;/a&gt; on Unsplash&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>career</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Journey Through the Amazon</title>
      <dc:creator>Marc Nevin</dc:creator>
      <pubDate>Mon, 02 Mar 2020 14:06:02 +0000</pubDate>
      <link>https://forem.com/m_nevin/a-journey-through-the-amazon-3amh</link>
      <guid>https://forem.com/m_nevin/a-journey-through-the-amazon-3amh</guid>
      <description>&lt;p&gt;&lt;em&gt;A guide to understanding and getting started with AWS Certifications&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;AWS and the Cloud can be a tough subject when you’re starting out.&lt;/p&gt;

&lt;p&gt;The variety and different types of &lt;a href="https://aws.amazon.com/certification/" rel="noopener noreferrer"&gt;certifications&lt;/a&gt; can all seem a bit much, but cutting through it all with some training you can come out with a better developer with a broader skillset. Not to mention some in-depth knowledge about one of the widest used cloud platforms, here’s how to get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Get Certified?
&lt;/h1&gt;

&lt;p&gt;It’s a choice to make and not always a cheap one, but if you can afford it or your company are willing to sponsor you, it's a great way to highlight your technical skills and can help show off what you can do, plus AWS themselves list a load of &lt;a href="https://aws.amazon.com/certification/benefits/" rel="noopener noreferrer"&gt;benefits&lt;/a&gt; including communities and stores!&lt;/p&gt;

&lt;p&gt;But if you've not worked in the space much the education working towards a cert can really develop your knowledge and skillset. The journey to getting exam ready will teach you a lot about the underlying concepts, the services and standards when building solutions on AWS.&lt;/p&gt;

&lt;p&gt;Personally, my first cert was to address a skill gap in my team, we were building on top of AWS but no one had taken the time to learn the best practice and its starting to really help the team having more people understand the base concepts. I didn't know how little I knew, it was the difference between thinking I knew how to build things on AWS and knowing how to build.&lt;/p&gt;

&lt;h1&gt;
  
  
  What Cert Is Best For Me?
&lt;/h1&gt;

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

&lt;p&gt;It really comes down to what you want to learn and what you find interesting, the certs are broken down into three levels and a set of specialities;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloud Practitioner&lt;/strong&gt; for those just starting out, teaching basic concepts of AWS and cloud best practice&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Associate Level&lt;/strong&gt; (SysOps, Architecture and Developer) which are fairly broad and focus mostly on 'core' AWS services&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Professional Level&lt;/strong&gt; (DevOps and Architecture) built on the Associate skills area but far more in-depth focus into the specifics of AWS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speciality&lt;/strong&gt; (5 and &lt;a href="https://aws.amazon.com/certification/coming-soon/" rel="noopener noreferrer"&gt;growing!&lt;/a&gt;) in-depth focus in a set of services focusing on one area &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re not sure but are keen to learn, you can check out the AWS guide to help scope out your &lt;a href="https://aws.amazon.com/training/learning-paths/" rel="noopener noreferrer"&gt;learning path&lt;/a&gt; but I’d recommend starting with one of the general certs in the first two tiers. &lt;/p&gt;

&lt;p&gt;I got my first cert recently and decided &lt;a href="https://aws.amazon.com/certification/certified-solutions-architect-associate/" rel="noopener noreferrer"&gt;Solution Architect&lt;/a&gt; best met my interests and needs. Going out and reading the descriptions of what each cert covers will roughly help you scope out which will line up directly with what you want. Looking at the &lt;a href="https://aws.amazon.com/training/learning-paths/" rel="noopener noreferrer"&gt;learning paths&lt;/a&gt; I think I might look at going towards the &lt;a href="https://aws.amazon.com/certification/certified-machine-learning-specialty/" rel="noopener noreferrer"&gt;ML Speciality&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It's worth mentioning, the certs are constantly being developed and it's worth keeping an eye on what's &lt;a href="https://aws.amazon.com/certification/coming-soon/" rel="noopener noreferrer"&gt;coming up&lt;/a&gt; before committing to a learning path!&lt;/p&gt;
&lt;h1&gt;
  
  
  How Do I Get Started?
&lt;/h1&gt;

&lt;p&gt;Unless you’re already an expert and are just out for the recognition, you’ll need to do some training to get exam ready.&lt;/p&gt;

&lt;p&gt;AWS offers some solid advice in &lt;a href="https://aws.amazon.com/certification/certification-prep/" rel="noopener noreferrer"&gt;preparing for their exams&lt;/a&gt;, it breaks down into, exam outlines, sample questions and links to relevant whitepapers and FAQs for each different certification. The prep guides will also cover any of the online AWS training they recommend.&lt;/p&gt;

&lt;p&gt;But sometimes it’s best to leave this to someone who knows what they’re talking about, there's a bunch of training providers who will cover everything you need, covering theory, resources and labs. &lt;/p&gt;

&lt;p&gt;There’s a variety of providers, here's some crowd favourites to start looking at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://acloud.guru/" rel="noopener noreferrer"&gt;ACloudGuru&lt;/a&gt; (Actually used them myself in the end)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://linuxacademy.com/" rel="noopener noreferrer"&gt;Linux Academy&lt;/a&gt; (They were recently acquired by ACG and will be merging eventually)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloudacademy.com/" rel="noopener noreferrer"&gt;Cloud Academy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.whizlabs.com/" rel="noopener noreferrer"&gt;WizzLabs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all have benefits and drawbacks, check out some reviews and decide which best lines up with your learning style. I’d recommend picking a  practical heavy course and one that goes beyond &lt;em&gt;just&lt;/em&gt; the exam, teaching you the topics with optional courses for topics you're interested in, this makes it go so much further even if it seems tough.&lt;/p&gt;

&lt;p&gt;The best advice I can give is to practice what you’re learning, AWS has &lt;a href="https://aws.amazon.com/free" rel="noopener noreferrer"&gt;free tier&lt;/a&gt; accounts available that are great for testing out the services and working through labs that come with a lot of the training providers.&lt;/p&gt;

&lt;p&gt;After coving of some training and some practice there's a few more things for getting ready - it's worth taking some time and reading;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/faqs/" rel="noopener noreferrer"&gt;FAQs&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/whitepapers" rel="noopener noreferrer"&gt;Whitepapers&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/architecture/well-architected/" rel="noopener noreferrer"&gt;AWS Well-Architected&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After all this, you should be ready to sit an exam and come out the other side with a certification!&lt;/p&gt;
&lt;h1&gt;
  
  
  What Did I Get From It?
&lt;/h1&gt;

&lt;p&gt;Besides a sheet of paper that says I can AWS, the training has changed how I build out services and gives me loads more confidence when I open up the AWS console.&lt;/p&gt;

&lt;p&gt;Not to mention, it's got me reading more and more about AWS and it's changing how the future of Development and where my career might go!&lt;/p&gt;

&lt;p&gt;——&lt;/p&gt;

&lt;p&gt;Good luck if you decide to start your journey,&lt;/p&gt;

&lt;p&gt;If you’ve any strong feelings pro or anti-cert, I’d love to hear or let me know what you’ve got from certs over the years;&lt;/p&gt;

&lt;p&gt;If you want to read more about AWS check out the tag here;&lt;/p&gt;


&lt;div class="ltag__tag ltag__tag__id__397"&gt;
    &lt;div class="ltag__tag__content"&gt;
      &lt;h2&gt;#&lt;a href="https://dev.to/t/aws" class="ltag__tag__link"&gt;aws&lt;/a&gt; Follow
&lt;/h2&gt;
      &lt;div class="ltag__tag__summary"&gt;
        Amazon Web Services (AWS) is a collection of web services for computing, storage, machine learning, security, and more

There are over 200+ AWS services as of 2023.
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;





&lt;p&gt;Original cover by &lt;a href="https://www.pexels.com/photo/rainforest-during-foggy-day-975771/" rel="noopener noreferrer"&gt;David Riaño Cortés&lt;/a&gt;, Edits by Me&lt;/p&gt;

</description>
      <category>aws</category>
      <category>beginners</category>
      <category>career</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
