How I Made a Twitterbot with Node.js

The other day, I decided to make a Twitterbot to help streamline my marketing efforts for my art brand. I wanted to make a bot that would retweet tweets from a different user, selected from a list of users. I wanted the bot to also run once a day.

For my project, I used the following:

  • Node.js
  • twit – Twitter API client for Node.js
  • Heroku – platform for deployed applications

Creating an Application with Twitter

To get started, I used the Twitter application form to register my application. The process is pretty straight forward, and once it was completed, I was able to grab the necessary consumer_key, consumer_secret, access_token, and access_token_secret.

Building the Bot

To get started with Node.js, I created a new project directory. Then I ran npm init.

I ran the following commands to ensure I had the right packages to build the application:

npm install --save dotenv http twit

Next, I created the environment variables. I created a .env file in the directory, where I added in my project keys:

CONSUMER_KEY="add_it_here"
CONSUMER_SECRET="add_it_here"
ACCESS_TOKEN="add_it_here"
ACCESS_TOKEN_SECRET="add_it_here"

In my index.js file, I connected the .env variables to the application:

require("dotenv").config();
const config = {
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  access_token: process.env.ACCESS_TOKEN,
  access_token_secret: process.env.ACCESS_TOKEN_SECRET
};

Then I added logic so the bot would retweet tweets from a list of users or retweet tweets tied to specific hashtags. First I set variables to use twit and to control the number of retweets the bot would make when the code was executed:

const twit = require("twit");
const Twitter = new twit(config);
const MAX_RT_COUNT = 1;

I found the Twitter ids for several users that I wanted to the bot to retweet. I used their ids instead of their screen names, in case a user decided to change their screen name. In order to keep track of who was who, I stored details about each user in a comment:

const USERS = [
  "15057943", // moma
  "14803372", // saam
  "5225991", // tate
  "22009731", // design museum
  "81783051", // artsy
  "17896874", // itsnicethat
  "158865339", // fastcodesign
  "21661279", // creative review
  "16336998", // print magazine
  "17623957", // design observer
  "418597196", // creativebloq
  "15446126", // design milk
  "18201801", // interior design
  "19038849" // how design
];

I made a function that would filter through the list of users, so that each day of the week, a different user would get a retweet from the bot:

const getUserOfTheDay = () => {
  let date = new Date();
  let dayOfMonth = date.getDate();
  let pickUserIndex = dayOfMonth % USERS.length;
  return USERS[pickUserIndex];
};

Next, I created the logic for retweeting tweets tied to different hashtags. I ultimately decided not to deploy this functionality, but I wanted to keep it around in case it’s useful in the future:

let retweetTags = async function() {
  try {
    const { data } = await Twitter.get("search/tweets", {
      q: "#art, #painting",
      result_type: "mixed",
      lang: "en"
    });

    const statuses = data.statuses.slice(0, MAX_RT_COUNT);
    // loop through the first n returned tweets
    for (const status of statuses) {
      // the post action
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

// retweetTags();

Lastly, I added the code for retweeting tweets from my list of users:

let retweetUsers = async function() {
  try {
    const { data } = await Twitter.get("users/show", {
      user_id: getUserOfTheDay()
    });

    const status = data.status;
    // make sure tweet isn't in reply to another user
    if (status.in_reply_to_status_id == null) {
      const response = await Twitter.post("statuses/retweet/:id", {
        id: status.id_str
      });
      if (response) {
        console.log("Successfully retweeted");
      }
    }
  } catch (err) {
    // catch all log if the search/retweet could not be executed
    console.error("Err:", err);
  }
};

To run the bot locally, I added retweetUsers(); to the file, then ran node index.js in the terminal.

Deploying the App to Heroku

Once I had my app up and running locally, I wanted to deploy it somewhere so it could run automatically. I did this by deploying it to Heroku.

I added a Procfile to the project, and added the line worker: node index.js to the file. Then I created a new Heroku project by running heroku create twitterbot-retweet. Next, I had to define the environment variables in Heroku by running heroku set:config key_name="key_value" in the terminal.

By accessing the Heroku dashboard online, I had to toggle on the worker for the bot (it was located under the “Dyno formation” section).

After deploying the bot, I realized I wanted the bot to run once every day, so I looked into options for how I could wake the application up once a day in order to execute the code. I ended up going with the simple setInterval method.

If your curious about how all the code looks, or want to see an up-to-date version of the project, you can find it on GitHub.

How I Found a Remote Job

Finding a remote job ended up requiring quite a bit of persistence on my part. Before looking for a fully remote job, I had no idea how competitive remote jobs are. What really helped me land quite a few interviews, some of which were with some pretty large companies, was the fact that I have a pretty big online presence. I not only blog on my web developer portfolio site, but I have created an online presence for my artwork. I was competing with a lot of applicants who have more of a Computer Science background, but I think my online presence helped me stick out.

When I was applying to various roles, I kept combing the following job boards/online services:

  • FlexJobs – this is a paid service, although if you’re unhappy with your subscription in any way, they’ll give you a refund
  • Hiring without Whiteboards – this repo includes companies that have remote roles
  • Remote.co
  • We Work Remotely (this one was my favorite, and is actually where I found the company where I landed a remote role)

It also helped that I have had previous experience working remotely for companies and contracting work, so I’m familiar with the various ways of communicating with colleagues in different cities. Many companies with remote employees are interested in if applicants have had previous experience working remotely, so they know if candidates are able to work remotely on their own. After all, remote work isn’t for everyone, and it’s a matter of trying it out to determine if it’s the type of environment you can thrive in.

Two Years Since GA: A Review of my Coding Bootcamp Experience

It’s hard to believe, but exactly two years ago I took leave from my company to attend General Assembly’s Web Development Immersive (WDI) program. Previously, I had hopped around with different web-related roles, learning coding on my own and picking up on best practices along the way. Since I didn’t have a background in Computer Science, I really wanted to get a better foundation, thus I decided to attend a coding bootcamp.

What was Great about General Assembly

WDI was an amazing experience in many ways. I’d have a say that I really appreciated the following:

  • Meeting a wonderful group of aspiring developers that came from all different backgrounds.
  • Being a part of an amazing community, and feeling much more confident about my abilities as a coder.
  • Having hands-on experience by building applications for labs, as well as creating four different projects (although I have to say I wasn’t proud of one of my projects, so it was more like having three different polished projects).
  • Getting introduced to new frameworks like Angular JS and popular libraries like React JS.
  • Having many “ah ha!” moments, where things would click and I realized that I had a much better understanding for different programming concepts and patterns.
  • Getting the tools I needed to become a better learner.
  • Feeling passionate again about technology and web development – prior to joining their program, I was feeling burned out at work. WDI helped motivate and inspire me again.

What Could Have Been Better

  • I wasn’t thrilled with their Outcomes programming. I enjoyed the panels they had and an interview workshop, but overall I felt like too much time was spent away from working on projects while focusing on things like resumes and cover letters (which I felt like I already knew enough about). I’d say it would have been better if there was less mandatory Outcomes programming, with the option to participate in some of their activities.
  • Technical interview prep would have been nice. We barely scratched the surface when it came to technical interviews, and I didn’t feel at all prepared for technical interviews once I started interviewing for developer jobs.
  • Better communication about how difficult it is to land a dev job earlier in your career. It felt like they kept saying it was easy if you worked hard enough, which is a bit vague and not terribly helpful.
  • More focus on frameworks and libraries. I had a different background than a lot of my peers in the program, since I had a bit of experience with programming. The first few weeks felt a lot like review for me, and once I started working with new frameworks and libraries, it seemed like we rushed over the material. I would have preferred less basics for HTML, CSS, JavaScript, and Ruby, and more detailed work with React JS.

Other Thoughts

Overall, I thought General Assembly’s WDI was an amazing experience, and I definitely don’t regret it. Was it perfect? No, but it helped me in just the right ways. I enjoyed the people I met and the community that I was a part of. I kept referring to it as being like camp for grownups. It was a lot of fun, was incredibly challenging at times, but was well worth it.

Can I Host Multiple Sites with GitHub?

The other day I was looking into hosting websites on GitHub Pages, and I found myself wondering if it’s possible to host multiple custom domains for a single GitHub account. I came to the conclusion that it isn’t possible. You can use one custom domain per account, and that custom domain can effect different types of repositories within your account. For instance, if I used megancoyle.com for my custom domain, it would be the new URL used to access my GitHub site page that was previously accessed via megancoyle.github.io. Then project pages would no longer have the URL megancoyle.github.io/hangman, but would use megancoyle.com/hangman instead.

So if you want to keep your other repos more separate from your personal page, you may want to rethink how you use a custom domain. Or you’ll possibly want to think about how you’d like to brand your different repositories.

Here are a couple of articles that can help you with linking your domains to GitHub Pages:

View story at Medium.com

Linking Namecheap to GitHub Pages

How to Make Requests to Yelp’s API v3 (Fusion)

I recently worked on updating an app I made a couple of years ago, that was using Yelp’s API. I was running into some issues deploying the older version of the app to Heroku, so I decided to update the API it was using to the latest version for Yelp, v3.

As I’m writing this, I found that the Yelp API documentation was a little confusing. The older API required a consumer key, consumer secret, token, and token secret. The Yelp Fusion API only requires an Authorization parameter.

Authentication for the Yelp API is outlined here, although I had to do a bit of fiddling around until I was able to successfully make an API GET request. Here’s what Postman looked like once I was able to make a successful call (click the image to see a larger view):

Something I wasn’t aware of from the APIs I’ve worked with, is that the Headers required a Content-Type with the value application/json and an Authorization with a value that started with the word Bearer, a space, and then the API key I had received from Yelp. So the value looked something like Bearer 203498lksjsdlkfej9if

If you’re curious about how I wrote the code for my application, you can take a look at my github repo for the app, What am I Even Doing?

New Design for Nextgov

Earlier this year, I joined Atlantic Media as a Web Developer. Last week, I got to be part of the first major launch while working for the company – relaunching Nextgov with a redesigned website.

Nextgov redesign

I got to work with Python and Django, and learned a lot about the company’s deployment process. It was interesting joining a team when they were in the middle of a project – I had to try to make sense of unfamiliar code, as well as do my best to catch up to speed with the project. It was fun working on the different apps integrated within their website, and I enjoyed learning more about the back-end development process with Django.

A Brief Overview of Ruby

Iterators

  • Iterators make it easier to write code
5.times do
  puts “hello”
end
  • Integers/floats: times, unto, down to, step
  • Range: each, step
  • String: each, each_line, each_byte
  • Array: each, each_index, each_with_index
  • Hash: each, each_key, each_value, each_pair

Methods

  • Values are passed in when they are called, and they are sometimes abbreviated as args
  • Operators are also methods in ruby
  • Syntactic sugar refers to simplifying the code
  • Syntactic vinegar – not so tasty code
  • Methods are all lowercase with underscores

Classes

  • Classes use camel case (they always start with a capital letter): SomeName
  • Classes group the code into discreet, well-categorized areas
  • Can define methods inside a class
class Animal
  def make_noise
    “Moo!”
  end
end
animal.make_noise
  returns “Moo!”
  • make_noise object is created from the class and then we can tell it to do things
  • Objects let us organize code into well-categorized areas
  • Allow complex behaviors using simple statements
  • Instance: an object created from a class
animal = Animal.new
puts animal.make_noice
  • Animal.new is an instance which is an object
  • .new is a class method

Instance Variables

  • Instance variables start with an @ symbol – @variable
  • Instance variables are used within the instance of a class
  • Allow us to keep track of attributes
  • Never have access to instance variables from outside the instant
  • We can access methods within instance, so need to use methods to get instance variable
  • Setter methods – sets a variable equal to value
  • Getter methods – getting that value back

Attribute Methods

  • Methods that we put into classes – takes symbols and turns them into methods
    • attr_reader
    • attr_writer
    • attr_accessor (creates a reader and a writer method)

Additional Terms

  • Instantiated = creating a new instance
  • Class Method – a method that can be called on a class even without an instance of the class
  • Class attributes – store values that apply to the class generally stored in a class variable @@variable
  • Instance variables are only inside the instance
  • Inheritance – inherits the methods and attributes of another class
  • Can only inherit from one super class
  • Modules are wrappers around classes

DevOps Fundamentals

DevOps is the practice of operations development engineers participating together in the entire service lifecycle, from design through the development process to production support

CAMS model

  • Culture – having dev and ops teams communicate more with each other
  • Automation – people over process over tools
  • Measurement – ability to measure – what’s happening, and if your changes are making any improvements (Mean time to recover MTTR appears, cycle time, costs, revenue, employee satisfaction)
  • Sharing

Concept to Cash

  • Amplifying feedback loops to help you with multi processes
  • Work culture that’s open to learning new things and experimentation (instead of falling into analysis paralysis)

DevOps Methodologies

  • People over process over tools
  • Continuous delivery (practice of coding, testing, and releasing features in small batches)
  • Lean Management (work in small batches, work in progress limits, feedback loops, visualization)
  • Change control (eliminate fragile artifacts, create a repeatable build process, manage dependencies, create an environment of continuous improvement)
  • Infrastructure as Code (systems treated like code, checked into source control, reviewed, built, and tested, and managed programmatically)

Practices for Success in DevOps

 

  • Kaizen is a popular dev ops cultural practice – means change for the better and we might roughly translate it to continuous improvement
  • Going to the actual place where the value’s created or where the problem is
  • Management by walking around
  • Define what you intend to do and what you expect the results to be, then you execute on that. Then you analyze the result and make any alterations needed
  • If newest plan is better than previous base line, it’s now the new base line
  • Plan, do, check, act gives people critical thinking skills
  • Five Whys, when there’s a problem, you ask the question why did it happen? And when you get an answer you ask why did that happen? Yu can repeat this as much as necessary, but five times is generally enough to exhaust the chain down to the root cause
  • Focus on underlying causes not symptoms (don’t accept answers like not enough time, do not accept human error as a root cause)

Agile Software Development

  • Process is iterative
  • Stresses collaboration
  • Promotes sustainable development
  • Waterfall goes through stage by stage

Seven Principles of Lean Software

  • Eliminate waste
  • Amplify learning
  • Decide as late as possible
  • Decide as fast as possible
  • Empower the team
  • Build in integrity
  • See the whole

Muda: work that absorbs resources but adds no value

Muri: unreasonable work imposed on workers and machines

Mura: work coming in unevenly instead of a constant or regular flow

Seven Wastes of Software

  • Partially done work
  • Extra feature
  • Relearning
  • Handoffs
  • Delays
  • Task switching
  • Defects

Build – Measure – Learn

  • Build the minimum viable product
  • Measure the outcome and internal metrics
  • Learn about your problem and your solution
  • Repeat. Go deep where it’s needed

Continuous Delivery

  • Code is always in a working state
  • Continuous Integration is the practice of building and unit testing the entire application frequently
  • Continuous Delivery is the additional practice of deploying every change to a production like environment and performing automated integration and acceptance testing
  • Continuous Deployment extends this to where every change goes through full enough automated testing. It’s deployed automatically to production.
  • Time to market goes down with continuous delivery
  • Quality increase, not decreases – gives room for experimentation
  • Limits your work in progress
  • Shortens lead times for changes
  • Improves mean time to recover
  • Builds should take less than five minutes
  • Make smaller commits
  • Don’t leave the build broken
  • Use a trunk-based development flow
  • Don’t allow flaky tests
  • Build should return a status, a log, and an artifact

Continuous Delivery Pipeline

  • Only build artifacts once
  • Artifacts should be immutable – doesn’t change during different stages
  • Deployment should go to a copy of production
  • Stop deploys if a previous step fails
  • Deployments should idempotent

Continuous Delivery: need to focus more on testing

  • Unit testing
  • Code hygiene (linting, formatting)
  • Integration testing
  • Security testing
  • TDD/BDD/ATDD (test-driven development – state desired outcome as a test, write code to pass the test, repeat; behavior-driven development – work with stakeholders, describe business functionality, tests are based on natural language descriptions; acceptance-test-driven development – end user perspective, use case automated testing, testing is continuous during development)
  • Infrastructure testing (starting up hosts)
  • Performance testing (load tests, etc good for nightly runs)

Container

  • Bundle app and dependencies in container and use that as the deployable artifact

Serverless

  • Functions as a service
  • Firebase
  • AWS lambda

RESTful Web API Design

An API is a set of routines or functions. It’s an interface used for performing tasks, retrieving data, and manipulating data. APIs use HTTP methods, which are used on a resource to GET, POST (submit form data), PUT (for updating files), PATCH (a partial update), and DELETE.

Adding an API

  • Bolt-on strategy – when you already have an application and are adding an API to it
  • Greenfield strategy – no underlining application. There’s complete freedom and flexibility to do what you want. Generally the “API first” or “mobile first” mentality.
  • Facade strategy – wraps existing logic with replace as you go. This is ideal for legacy systems so the application is always functional.

Designing the Relationship

  • Independent – the resources may exist regardless of the other existing but they may reference each other
  • Dependent – one resource cannot exist without the parent
  • Associative – they are independent of each other but the relationship contains additional properties to describe it

Planning the Relationships

  • Ask yourself the following questions:
    • Can both resources exist without the other?
    • Does one resource only exist when the other exists?
    • Does the relationship between resources require more information than just the links between them?
  • It should be relatively easy to map out the flow, action, etc for each resource. If not, you need to revise your design.
  • Consider using notecards to write down each resource action

REST

  • REST stands for Representational State Transfer
  • It’s an architecture for designing network-based applications
  • It is not a protocol, framework, or standard

Benefits of Stateless Servers

  • Visibility – monitoring systems and developers do not need to look beyond the request to trace a bug
  • Reliability – easy to recover from system failures

Drawbacks of Stateless Servers

  • Network Bandwidth – client sends state for every request
  • Complexity – all clients must handle their states

Benefits of Caching

  • Performance – for stateless and caching, many requests do not need to go all the way to the server
  • Scalability – server gets fewer requests so it can handle more clients

Drawbacks of Caching

  • Data reliability – clients might use stale data

Facets of a Uniform Interface

  • Self descriptive messages
  • Server includes metadata, such as Content-Type, to help clients process the responses
  • Hypermedia as the engine of application state (HATEOAS)
  • Client only assumes a fixed entry-point to the API, the server tells clients all other available actions through hyperlinksBenefits of a Layered System
  • Encapsulation (simplify an interface to a legacy server)
  • Scalability (layers enable load balancing)
  • Security (add access control rules to data crossing a boundary, just like a firewall)

Drawbacks of a Layered System

  • Latency – adding layers increases latency

A Brief Overview of GraphQL

GraphQL is a query language designed to make data fetching easier. It allows you to get data from the server to the client. It is language agnostic and became open source in 2015.

Overview

  • Input types include: integer, float, string, boolean, null, enum, list, object
  • It has a built-in documentation for the schema
  • Can create operation names to help identify different queries
  • Creates changes through mutations
  • API determines what mutations are allowed

Benefits

  • Avoids multiple REST calls
  • Is backward compatible and version-free
  • Can wrap around existing APIs
  • Queries can have comments