How to Manage State by Using the React Context API

When I work on large-scale applications, I use Redux for state management. However, when it comes to building smaller applications and smaller personal projects, Redux can feel cumbersome. So, what’s the best light-weight solution for state management of these smaller applications? React hooks work really well for smaller applications, but sometimes you need to share state between components, and passing that state through components via props can get a little clunky. That’s where React Context comes to the rescue.

By utilizing the React Context API, you can avoid prop drilling. It also helps keep your components cleaner and simpler.

Let’s walk through what this would look like if we’re adding React Context to an application. First, I like to organize my context within a contexts folder within the src directory. Then I create a context file where all the global state will live. For this example, let’s call the file ItemContext.js:

import { createContext, useState } from "react";
import PropTypes from "prop-types";
const ItemContext = createContext();
const ItemProvider = ({ children }) => {
  const [items, setItems] = useState([]);
  const addItem = (item) => {
    const index = items[items.length - 1].id + 1;
    item.id = index;
    const updatedItems = [...items, item];
    setItems(updatedItems);
  };
  const editItem = (id, item) => {
    const index = items.findIndex((e) => e.id === id);
    const updatedItems = [...items];
    updatedItems[index] = item;
    setItems(updatedItems);
  };
  const removeItem = (id) => {
    const updatedItems = [...items];
    setItems(updatedItems.filter((item) => item.id !== id));
  };
  const context = {
    addItem,
    editItem,
    items,
    removeItem,
  };
  return <ItemContext.Provider value={context}>{children}</ItemContext.Provider>;
};
export { ItemContext, ItemProvider };
ItemProvider.propTypes = {
  children: PropTypes.object,
};

Next, within the src directory, if you don’t already have a hooks directory, create one where we’ll add a new hook file, useItemContext.js:

import { useContext } from "react";
import { ItemContext } from "../contexts/ItemContext";
const useItemContext = () => {
  return useContext(ItemContext);
};
export default useItemContext;

This file probably looks fairly small, but it will help us cut back on copying and pasting the same lines of code when we want to reference this global state. Now, when we want to access the global state or update the state via various components, we can do so by importing the context hook:

import useItemContext from "../hooks/useItemContext";
const ExampleComponent = () => {
  const { addItem, editItem, removeItem } = useItemContext();
  const handleAdd = (item) => {
    addItem(item);
  };
  const handleRemove = () => {
    removeItem(item.id);
  };
  const handleSave = (item) => {
    editItem(item.id, item);
  };
  return (
    {Add your presentation logic here}
  );
};
export default ExampleComponent;

Lessons Learned from a Mass Tech Layoff

This year was the first time I was ever laid off from a company, and I figured I’d share my lessons learned from the experience. Maybe you’ll find them helpful if you ever find yourself in a similar situation or if you’re going through the same thing at the moment.

Lessons I learned from getting laid off from my Senior Software Engineering role:

  1. Instead of diving into job hunting immediately, take some time to rest beforehand. I dove into job hunting immediately, although I was still feeling devastated from being laid off from a company that had been a dream job for me. I was processing my grief over losing a job while also feeling extremely exhausted from staying up late studying for technicals and waking up early for my scheduled interviews. This made it difficult to perform at my best during those interviews.

  2. Don’t apply to too many places at once. Right after getting laid off, I panic-applied to a lot of companies. As a result, I had several companies responding to me at the same time to set up interviews. My calendar was crammed with interviews – recruiter calls, technicals, and take home assessments. I ended up feeling extremely overwhelmed and was spread too thin, and ultimately bombed too many interviews because I overextended myself. If I could go back and do things differently, I would have been more selective at the beginning of my job hunt. That way I wouldn’t have been so exhausted in the beginning.

  3. Filter the unsolicited advice you’re getting from others and focus on what makes sense for you and your situation. I had a lot of friends/family give me their take on how I should approach the job hunting process. At first, I was trying to listen to too many people at once, and as a result, I was not only overwhelmed from everything that was going on in my life, but I was also overwhelmed from all the advice I was getting. What works for one person may not work for you, and that’s totally okay. Do what makes sense for you and makes the job hunting process manageable for you. For me, this meant cutting back on the interviews I was scheduling each week. I know that people mean well when they give you unsolicited advice, but no one truly knows what you’re going through better than you do, and ultimately you know better about what works for you.

  4. Prioritize your mental health. Losing my source of income and my health insurance, processing the emotions from getting laid off, as well as dealing with the rejection that comes with the job hunting process, took a toll on my mental health. At first I was interviewing too much and not giving myself enough space to continue to pursue my hobbies or doing things that make me happy. Later, I realized I had to cut back on interviews so I could protect my happiness and mental health, and make time to do things that would bring me joy during this difficult time.

  5. Have a strategic approach for the companies/roles that you apply to. At first, I didn’t have a strategy other than to apply to any role that fit my skill set at companies I was familiar with/really liked. Later, I realized the interview process was very important to me since I’m primarily self-taught, and live coding/whiteboarding interviews have always been tough for me. I ended up applying to companies that had tech screens that catered to my strengths while spending some of my free time working on LeetCode problems and studying CS so that I could move back to live coding/whiteboarding interviews in the future.

  6. You can negotiate your severance. I had no idea you could negotiate your severance, so I just signed off on what was offered to me. If I could go back, I would have tried to negotiate, although the layoff my company did was one where there probably wasn’t much room for negotiation since so many people were laid off.

  7. Listen to your gut. When you no longer have a job, it’s easy to feel desperate and feel like you should accept the first offer you get. If you’re financially able to hold off on doing that, I’d recommend waiting until you get an offer that excites you. I had a couple potential offers in the beginning of my search, but I wasn’t excited about them at all. And I think that’s definitely a red flag – you don’t want to start working for a company if off the bat you have some resentment about the offer.

  8. Network and use social media to your advantage. I was able to get a lot of leads on possible job opportunities by reaching out to people who used to work at my previous companies. I was also getting a lot of help from strangers reaching out to me when I posted about getting laid off on LinkedIn.

Hopefully this is helpful for anyone else going through something similar. If you recently found a new job, congrats! If you’re still on the search for something new, good luck and hang in there!

How I went from being a Mid-Level Software Engineer to a Senior Software Engineer

My background in engineering isn’t the typical path – although what’s great about the tech industry is that I’ve met many software engineers who have nontraditional backgrounds as well. I studied painting and creative writing in school, and fell into coding when I had to put together a portfolio site for my artwork for a class. I taught myself the basics of HTML, CSS, and JavaScript. And since then, I’ve been hooked – I like how coding is it’s own art form. I like how I get to build things and solve complex problems.

So how did I go from being an Art/English Major to a Software Engineer, and then a Senior Software Engineer? After college, I held a number of web-related roles where I picked up different languages like Ruby and Python. The common thread in all my roles was that I was working with JavaScript in one form or another. I worked for a few nonprofits before I ventured over to working for startups. While working at one nonprofit, I took several night classes in web development (frontend development, backend development, and JavaScript development) before taking a couple months of leave to go through a web development immersive program. Although I was self taught up until that point, I wanted to ensure I hadn’t picked up any bad habits while working on small teams where I was usually the only one that did the type of work I do. After the program, I continued to work on learning as much as I could outside of work.

While working at a startup, I started to approach my work in a different way. I kept an eye out for ways I could improve my team’s process through automation. I would often propose feature work outside of the requests my team was getting, so that I could build out improvements that would automate our workflow. I noticed patterns in the repetition of the requests we were receiving and thought about how we could move away from a more manual process to an automated one. And through automation, I was able to cut down the number of requests my team had to handle manually from about 20+ a day to about 2 or 3 a week (sometimes we wouldn’t get any requests at all). This allowed my team to shift our focus to other products and merge with a different team within the company.

Aside from automation, I also looked for ways to help my fellow engineers. If I noticed that any of less experienced engineers were struggling with a language or process, I’d either look into a tool that could automate the process, or sometimes I’d create documentation to serve as a cheatsheet. When I was working on a team of primarily frontend engineers, and a couple of the less experienced engineers were overwhelmed by the command line or working with Ruby, I compiled a list of handy commands to make their lives easier. And whenever I ran into any issues with local development, I’d share any solutions I found with the team to ensure no one else would run into the same blockers. I also made myself available for pairing to help out other team members whenever they were blocked. And by finding solutions to bottlenecks in our processes via automation or tooling, as well as mentoring others, I got promoted to Senior Software Engineer.

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 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?

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