Some Time Has Passed

I realized today that some time has passed since my last post. I don’t think I can go into great detail about what I’ve been doing in that time, but there has been a fair amount of new knowledge gained.

Working That Back Side

The most notable change in direction has been working with Node, Express, and MongoDB. I charged right through the FreeCodeCamp API Microservice projects and I’ve completed one of the full stack projects as well. Adding React into the mix was an interesting challenge, and I’ve still got a lot to learn in that regard.

One thing that I’ve found interesting in this part of the stack is how different the approach to problem solving is. For nearly any task I wish to accomplish on the back end, someone has created a library. This is not so dissimilar to the React ecosystem, but it does seem to take it to a whole new level. This has led me to a number of internal conflicts; am I wasting an opportunity to learn more by including these libraries, or would I be wasting time reinventing the wheel, so to speak, by trying to achieve on my own what these libraries are already capable of achieving?

Most talk of React and JavaScript fatigue come down to the ecosystem. To use React you need compilers, bundlers, this thingy and that thingy, and to learn React is to learn Webpack and Babel at the minimum, but more likely with Redux, react-redux, react-router-dom added in depending on the scope and complexity of your app. This is precisely how the back end feels. Sure, you can do most of it with just Node, but Express makes it so much easier. MongoDB is pretty straight forward, but why not use schemas with Mongoose? Sure, you can build your own authentication system, but Passport already has that covered. OAuth1, OAuth2, use existing social media credentials, more choices than you can imagine. At some point the sheer enormity of new libraries becomes a burden and I’ve found myself facing the fatigue that I never did experience with learning React.

So A Pause For The Cause

I took about a week off, writing no code and not really even thinking about it. Yesterday, I opened my Atom text editor for the first time in many days, feeling somewhat renewed and excited to tackle some new challenges. Today, I’m force-feeding some React into Electron, making my first desktop app. Don’t feel bad for Electron, I think it likes it.

Making API Calls (part 2)

In the first part of this tutorial, we used an API call to create a list of pokemon. This tutorial will pick up where we left off and work through to the final result.

Pagination

Our API call returned an array with 20 objects, but it indicated there were a total of 811 objects available. To see the remaining pokemon we will need to retrieve each page of results. Fortunately, we can use our existing code to do so, we just need to make some minor adjustments.

const container = document.querySelector('.pokedex');
const pageOneUrl = "https://pokeapi.co/api/v2/pokemon";

const getPokemonList = (url) => {
  axios.get(url)
       .then( (response) => {
          const data = response.data.results;
     
          data.map( (pokemon) => {
            const div = document.createElement('div');
            const text = document.createTextNode(pokemon.name);
             
            div.appendChild(text);
            div.className += 'pokeList';
            container.appendChild(div);
          });      
       })
       .catch( (error) => {
          throw error;
       });
}

getPokemonList(pageOneUrl);

I’ve moved our variable holding the api url outside of the function and renamed it pageOneUrl. I’ve added url as a parameter to our getPokemonList function so we can pass in other urls as needed. Now any url provided to this function will be used for the API call, making it possible to reuse this function for any data we may receive in the same format as our pageOneUrl returns.

Next we need to make sure that our parent container, the div with the class pokedex is empty before we add anything to it. We can do this with just three lines of code:

const container = document.querySelector('.pokedex');
const pageOneUrl = "https://pokeapi.co/api/v2/pokemon";

const getPokemonList = (url) => {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }

  axios.get(url)
       .then( (response) => {
          const data = response.data.results;
     
          data.map( (pokemon) => {
            const div = document.createElement('div');
            const text = document.createTextNode(pokemon.name);
             
            div.appendChild(text);
            div.className += 'pokeList';
            container.appendChild(div);
          });      
       })
       .catch( (error) => {
          throw error;
       });
}

getPokemonList(pageOneUrl);

This while loop looks in our container and checks for a child element, if one is found it removes that child. This loop continues until no more children are found. Piece of cake!

Next, we need some way to tell the app to load the next page. For this we will create buttons and add them to either side of our header. Let’s update the header html from this:

<div class='header'>Pokeapi Pokedex</div>

To this:

<div class='header'>
  <div class='nav' id='prev'>&lsaquo; Prev</div>
  Pokeapi Pokedex
  <div class='nav' id='next'>Next &rsaquo;</div>
</div>

In our css we’ll change the header to:

.header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  
  margin: 10px;

  font-size: 36px;
  font-weight: bold;
  font-family: arial;
  text-align: center;
}

And we’ll add our new nav class to the css:

.nav {
  font-size: 18px;
  font-weight: bold;
  color: #e5a5a5;
  
  cursor: pointer;
}

Our app now looks like this:

A view of the pokedex app after adding nav buttons

All that is left is adding the onclick handlers to make the buttons work. The data returned in our API call has keys named "previous" and "next" which are populated with urls to the next page of results. We can add some onclick handlers to our new buttons with this information.

const getPokemonList = (url) => {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
  
  axios.get(url)
       .then( (response) => {
          const data = response.data.results;
          const prev = response.data.previous;
          const next = response.data.next;
    
          data.map( (pokemon) => {
            const div = document.createElement('div');
            const text = document.createTextNode(pokemon.name);
            
            div.appendChild(text);
            div.className += 'pokeList';
            container.appendChild(div);
          });
    
          if (prev) {
            document.getElementById('prev').onclick = () => {
              getPokemonList(prev);
            }
          }
    
          if (next) {
            document.getElementById('next').onclick = () => {
              getPokemonList(next);
            }
          }
       })
       .catch( (error) => {
          throw error;
       });
}

Now, if our API call returns a url for "previous" or "next" we will add an event listener to our new buttons which when clicked will call our getPokemonList function with the url to the appropriate page of results.

Creating Cards For Selected Pokemon

Looking at lists of pokemon names is fun. Super fun. With 20 results per page, and 811 total results, we can look at 41 pages of pokemon names. For some, this may be enough but I think we can take this a step further and display information about each pokemon on demand.

To accomplish this, we need to have some way of selecting which pokemon we want to look at. Each list item already looks like a button, let’s make it behave like one as well.

data.map( (pokemon) => {
  const div = document.createElement('div');
  const text = document.createTextNode(pokemon.name);
            
  div.appendChild(text);
  div.className += 'pokeList';
  div.onclick = () => { getPokemonDetails(pokemon.url); };
  container.appendChild(div);
});

In our Array.map() method we’ve added an onclick event handler to each list item. This event handler will take the url we received in each object and pass it to a new function which looks like this:

const getPokemonDetails = (url) => {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
  
  axios.get(url)
       .then( (response) => {
          
       })
       .catch( (error) => {
          throw error;
       });
}

Look familiar? The only thing that’s changed is the name! If we were following the D.R.Y. (Don’t Repeat Yourself) principle we’d just modify our existing function to handle our new data format we’ll receive, but for the sake of simplicity we will just create a new function to handle the api calls for pokemon details. They call this W.E.T. instead of DRY (We Enjoy Typing!)

If you want you can log the result of this call to your console, I will again go to Postman to see what we can expect.

A view of the results of our API call in Postman

Aaaaaaand it’s huge. Really huge. 9018 lines, in Postman. If you are more industrious than I am, you can go through all the information we have available here, but I am going to choose some data and we’ll ignore the rest.

Since we’re only dealing with one data set instead of an array of data, we don’t need to map through anything so this will be pretty simple. Into our call response we will add:

.then( (response) => {
  const data = response.data;
    
  const nameDiv = document.createElement('div');
          
  nameDiv.appendChild(
    document.createTextNode(data.species.name)
  );
  nameDiv.className = 'pokeName';
  container.appendChild(nameDiv);
    
  const img = document.createElement('img');
    
  img.src = data.sprites.front_default;
  img.className = 'pokePic';
  container.appendChild(img);
    
  const statsDiv = document.createElement('div');
    
  statsDiv.className = 'stats';
  statsDiv.appendChild(
    document.createTextNode("Height: " + data.height + " || Weight: " + data.weight)
  );
  container.appendChild(statsDiv);
})

This may seem a little complicated, but basically we’re just creating new html elements, assigning them some attributes like class or src and then adding them into our app.

Since we’re adding some classes here let’s go ahead and define them in our css by adding:

.pokeName {
  margin: 20px;
  
  font-size: 28px;
  font-weight: bold;
  text-align: center;
}

.pokePic {
  width: 250px;
}

.stats {
  font-size: 18px;
  font-weight: 600;
}

Now, when we click a name in our list we should see:

A view of the pokemon card

Not bad! As I said earlier, there is a lot of information returned for each pokemon so if you wanted to improve on the card you could add all kinds of cool information. For the purposes of this tutorial, I just want to add one more thing and make one small change.

While viewing a card in the pokedex it would be nice to be able to return to the list, so let’s add a button at the bottom of the card allowing us to do just that.

To make this work, we need to know where we’ve been, so we will add a second parameter to the getPokemonDetails function, which will allow us to pass the url of the list we were just viewing. Then we can set an onclick event handler which will reload the previous list. Our getPokemonDetails function should now look like this:

const getPokemonDetails = (url, listUrl) => {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
  
  axios.get(url)
       .then( (response) => {
          const data = response.data;
    
          const nameDiv = document.createElement('div');
          
          nameDiv.appendChild(
            document.createTextNode(data.species.name)
          );
          nameDiv.className = 'pokeName';
          container.appendChild(nameDiv);
    
          const img = document.createElement('img');
    
          img.src = data.sprites.front_default;
          img.className = 'pokePic';
          container.appendChild(img);
    
          const statsDiv = document.createElement('div');
    
          statsDiv.className = 'stats';
          statsDiv.appendChild(
            document.createTextNode("Height: " + data.height + " || Weight: " + data.weight)
          );
          container.appendChild(statsDiv);
    
          const button = document.createElement('div');
    
          button.className = 'back';
          button.appendChild(
            document.createTextNode("Back")
          );
          button.onclick = () => { getPokemonList(listUrl) };
          container.appendChild(button);
       })
       .catch( (error) => {
          throw error;
       });
}

Since this function is now expecting us to pass two parameters when it’s called, we also need to update the onclick event in our getPokemonList function so it sends everything we need.

div.onclick = () => { getPokemonDetails(pokemon.url, url); };

Now we can return to our list and browse other pokemon! Our finished card looks like this:

A view of the finalized card

The last thing I’d like to do is just clean up one little bit of UI/UX that is bugging me. Currently while viewing a card if we click the Prev or Next buttons it will load the previous or next list. What I’d like to do is just disable those buttons.

In our getPokemonDetails function let’s add something to do just that:

const getPokemonDetails = (url, listUrl) => {
  while (container.firstChild) {
    container.removeChild(container.firstChild);
  }
  
  document.getElementById('prev').onclick = () => {
    return false;
  }
  
  document.getElementById('next').onclick = () => {
    return false;
  }
  
  axios.get(url)

And there you have it. We’ve successfully made a whole lot of API calls and used the data to build an app, and in the process learned about promises and async tasks.

You can view the finished project here.

Making API Calls

This tutorial uses some ES6 syntax. You can learn about const here and arrow functions here.

I suggest coding along with this tutorial to get the most out of it. Writing code seems to cement concepts better than copy/pasting other people’s code.

The project we will be making is a simple Pokemon Pokedex, using the Pokeapi V2 API.

One thing I see many people struggle with is making API calls. I had a lot of trouble learning how to do this, and was surprised to find most suggested using jQuery to get the job done. jQuery has a few different tools to make calls with, but I still don’t believe it’s necessary to import a giant library for a tiny task.

What About A Tiny Library?

Now we’re talking. I’m not against using tools outside of vanilla JavaScript, and I do so often. My favorite for making API calls is Axios.

Axios describes itself as a “Promise based HTTP client for the browser and node.js.” Most of these terms beginners should understand, but the difficult concept here is “promise based.” It took me a while to understand promises, so let’s look at what happens when we make an API call and see if we can understand the process a little better.

Before we get to that, though, let’s get some of the code out of the way

For those of you following along in CodePen, please add the axios CDN into the JavaScript area of the settings menu. Any code depicted between <style> tags goes in the box labeled CSS, everything between the <body> tags goes in the html box, and everything in the <script> tags goes in the JavaScript box.

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8'>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.min.js'></script>
    <style>
      html, body {
        margin: 0;
        padding: 0;
      }
      
      .container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        
        width: 100vw;
        min-height: 100vh;
      }
      
      .main {
        width: 450px;
        height: 600px;
        
        background-color: #84152b;
      }
      
      .header {
        margin: 10px;
        
        font-size: 36px;
        font-weight: bold;
        font-family: arial;
        text-align: center;
      }
      
      .pokedex {
        margin: 10px;
        
        height: 520px;
        
        border: 1px solid black;
        background-color: #a39e9f;
      }
    </style>
    <script>

    </script>
  </head>
  <body>
    <div class='container'>
      <div class='main'>
        <div class='header'>Pokeapi Pokedex</div>
        <div class='pokedex'>
          
        </div>
      </div>
    </div>
  </body>
</html>

This gives us just a simple layout that looks like:
A view of the basic layout
As you can see, we’re not aiming for anything fancy here. We just need a place to display the information we get back from our API call.

Promises

API calls, along with many other methods we’ll use in web development, execute asynchronously. JavaScript is a single-threaded application, which means that when we write an algorithm it executes from the top to the bottom, in order. This gives us predictable behavior and makes it easy to understand the order in which our code will execute. Asynchronous (async) tasks get called in order as you’d expect, but they can take some time to complete so the rest of the code gets called while the async task finishes up behind the scenes. This makes sense, because we don’t want to just sit around and wait for an API call to complete before moving on with the rest of our code. Users are impatient.

The difficulty here is that if we don’t wait for the call to complete, the information returned will not be available when the rest of the script executes. This can lead to a lot of frustration for a developer because when we look at it in our code it all makes sense. Make this API call, put the results here, here and here. The problem is the call hasn’t finished before we try to use the results.

This is where the magic that is promises comes into play. In the simplest terms, a promise is like an event listener. We’ve used those before, where we tell the app to listen for a button being clicked or a key to be pressed, and then execute a bit of code in response. Promises work in much the same way, but the event we will be ‘listening’ for here is the API call to complete. Then it will execute a bit of code for us, using the results of the API call.

Let’s go ahead and make a call to our Pokeapi so we can see what kind of information it will return, then we can figure out how we want to display it in our app. I like to use a Chrome app called Postman to play around with APIs, this allows us to easily try out the necessary query strings and API parameters before adding them into our app. I find it’s much easier than making a series of console.log() statements.

Using https://pokeapi.co/api/v2/pokemon as our api url in Postman, we get back an object that looks like this:

A view of our api call in Postman

{
  "count": 811,
  "previous": null,
  "results": [
    {
      "url": "http://pokeapi.co/api/v2/pokemon/1/",
      "name": "bulbasaur"
    },
    {
      "url": "http://pokeapi.co/api/v2/pokemon/2/",
      "name": "ivysaur"
    },
    {
      "url": "http://pokeapi.co/api/v2/pokemon/3/",
      "name": "venusaur"
    },
    {
      "url": "http://pokeapi.co/api/v2/pokemon/4/",
      "name": "charmander"
    },
    {
      "url": "http://pokeapi.co/api/v2/pokemon/5/",
      "name": "charmeleon"
    }
  ...
}

I forgot to update the api url to https instead of http for the images above, but calling https://pokiapi.co/api/v2/pokemon will return the above objects with all of the urls updated to https

We have a key for “count” showing us how many pokemon have been returned, and the meat of our data, a key called “results,” an array of objects representing the first 20 of 811 pokemon this API has returned to us. Arrays are easy to iterate through, so this is good news. Let’s go ahead and add our API call using axios to our app with the following code:

<script>
const container = document.querySelector('.pokedex');

const getPokemonList = () => {
  const url = "https://pokeapi.co/api/v2/pokemon";
  
  axios.get(url)
       .then( (response) => {
          console.log(response);
       })
       .catch( (error) => {
          throw error;
       });
}

getPokemonList();
</script>

This is all it takes to use axios. We pass the API url into axios, and chain onto the initial call with .then(). This is the promise. This tells our app to listen for that API call to complete, and execute whatever code we’ve put in our .then() function. In this case, for right now we are logging the API response to the console so we can see what our response will look like. Also, we have a .catch() statement added to handle any errors our API call may generate.

A view of the dev console after making initial api call

This looks a lot different that what we saw in Postman, it’s a good thing we checked before trying to use the data. It looks like Axios must build a default response object with header information, and the information we want is stored in the key labeled “data.results” Let’s update our script a little and run it again to be sure.

<script>
const container = document.querySelector('.pokedex');

const getPokemonList = () => {
  const url = "https://pokeapi.co/api/v2/pokemon";
  
  axios.get(url)
       .then( (response) => {
          console.log(response.data.results);
       })
       .catch( (error) => {
          throw error;
       });
}

getPokemonList();
</script>

This results in:

An updated view of the api call results logged in the dev console

That’s much better. We’ve trimmed it down to just the array of objects representing the different Pokemon. Now we can loop through this array and add the information to our display. Let’s add some style for our list of pokemon, then we’ll change our axios call to handle the data we receive.

.pokeList {
  width: 90%;
  
  margin: 3px;
  
  font-size: 16px;
  font-weight: bold;
  color: #160105;
  text-align: center;
  
  border: 1px solid black;
  
  cursor: pointer;
}

And our updated axios call:

const getPokemonList = () => {
  const url = "https://pokeapi.co/api/v2/pokemon";
  
  axios.get(url)
       .then( (response) => {
          const data = response.data.results;
    
          data.map( (pokemon) => {
            const div = document.createElement('div');
            const text = document.createTextNode(pokemon.name);
            
            div.appendChild(text);
            div.className += 'pokeList';
            container.appendChild(div);
          });      
       })
       .catch( (error) => {
          throw error;
       });
}

We take the response from our axios call and assign the information stored in the data.results key to a variable named data. Since this information is an array, we can use the method Array.map() to iterate through the array and generate our list of pokemon dynamically. For each item of the array we create a new <div> element, set the text of the element to the name of the pokemon and add our new class we created in the css section. This repeats for every item in the array, giving us the following result:

A view of our pokedex app with api data added

Next week we’ll finish this up by adding pagination to the list, allowing us to view the remaining pokemon in the database, as well as adding functionality which will allow us to view the stats of each pokemon.

A New Thing

I’ve been actually getting some views on this little blog, so rather than only writing myself notes I though I might try to add some content others might find useful. Beginning today you should start seeing some posts tagged as “Tutorial.” These will be posts aiming at teaching how to use some of the tools I’ve found helpful in my journey, many of which I still use today.

Drawing Some Charts With D3

I have to admit, I was pretty intimidated by learning D3. This is the second part of the FreeCodeCamp data visualization section, the first part being React. After all the trouble I had learning React (or more to the point, finding anything current to learn React) I was dreading starting D3. As it turns out D3 is pretty simple, once you get the hang of the basics.

The Basics

I was surprised to find that D3 is a lot like (shudder) jQuery in syntax. Most methods return an object – allowing method chaining – which greatly simplifies the entire process. Once I started thinking of D3 in these terms the projects practically coded themselves.

The only other learning curve seems to be getting comfortable with svgs, which fortunately I have used in previous projects so there wasn’t much new there. In fact, I think most of the code I wrote for my D3 projects was to handle svgs and relatively little pertained to D3 or the data being used.

In a nutshell, D3 takes a whole lot of data and turns it into pictures. This is probably a great over-simplification which would likely irritate Mike Bostock (creator of D3), and really doesn’t do it justice, but there you go. Data to pictures.

Let’s Look At Some Code

This comes from a great, if outdated tutorial by Scott Murray written in the time of D3 v3, but all of this code will work in v4

First up, using D3 to add an SVG element to our page

const w = 500;
const h = 100;
const barPadding = 1; 

const svg = d3.select("body")
              .append("svg")
              .attr("width", w)
              .attr("height", h);

SVGs have default width and height attributes, so you do not necessarily have to specify these values, but I can’t imagine that the defaults will always be the size you’re after. So it’s good practice to specify these values.

D3 will loop through all provided data once it’s bound, applying your logic to each item in your dataset. That happens here:

svg.selectAll("rect")
   .data(dataset)
   .enter()
   .append("rect")
   .attr("x", (d, i) => {
     return i * (w / dataset.length);
   })
   .attr("y", (d) => {
     return h - d * 4;
   })
   .attr("width", w / dataset.length - barPadding)
   .attr("height", (d) => {
     return d * 4;
   })
   .attr("fill", (d) => {
     return "rgb(0, 0, " + (d * 10) + ")";
   });

I’ll leave it to you to read through Scott Murray’s tutorial to see what’s going on here. You can view the final results of this code here.

To Wrap This Up

D3 is different, but not scary. It’s powerful, but not difficult. Getting a simple chart onto the screen takes very little effort and the learning curve is not at all steep. Fear not the D3.

An Ode To Flexbox

A few months ago I made the courageous decision to not use Twitter Bootstrap anymore, and instead learn some CSS. I do not regret this decision even a little. Not too long ago I was peeking under the skirt of someone’s bootstrap website in Chrome Dev Tools and noticed something really odd: the custom bootstrap grid classes were just flexbox!

Okay, this is probably not news to most people, but to me it was kind of a big deal. I had moved away from bootstrap to learn flexbox and css grid for positioning, and then find out that what I just learned is what I had been using before. The biggest difference is that flexbox has native browser support, and bootstrap requires adding some pretty hefty libraries. Granted, you can get by with just bootstrap.css but if you wander into some of the other bootstrap classes you could find yourself in need of bootstrap.js, which requires adding jQuery. I had found myself adding in 3 libraries just to position content on the page, and that seemed just a little bit silly.

About That Flexbox

It turns out, flexbox is pretty simple to learn. There are a number of great resources out there, from my favorite site css-tricks.com to flexbox froggies and flexbox zombies. These last two are pretty entertaining and give you some good hands-on experience with flexbox.

The basic premise of flexbox seems to be creating either rows or columns as parent containers with:

.myRow {
  display: flex;
  flex-direction: row;
}

.myColumn {
  display: flex;
  flex-direction: column;
}

It’s pretty intuitive so far. We have to specify that the container is using flexbox, then we designate which direction to add the content. Worthy of note here is that the flex-direction: row is the default value and doesn’t have to be specified.

I’m not going to iterate through each available property, and I don’t intend this to be a tutorial. The remaining properties are all about how the content is displayed in the flex containers. Some handle spacing, some alignment, and there are plenty of tutorials (including those mentioned previously) which will give you a great idea of how flexbox works. I do, however, want beginners out there to know there are alternatives to Bootstrap.

But What’s Wrong With Bootstrap?

The answer to this, of course, is that there’s nothing wrong with Bootstrap. It is a well developed, well documented resource and I’m sure there are situations where I would be happy to use it. My initial statement is that it’s a bit unnecessary to import 3 huge libraries just to handle a little positioning. Bootstrap does make some tasks much easier, such as responsive design, but for me that’s not enough to justify adding it to a project. I am very fond of media queries and since I’ve discovered the wonder that is SCSS using those media queries is a piece of cake.

And Finally …

Since we’re on the topic of importing huge libraries for small tasks, I have to mention jQuery. Yes, it’s useful. Yes, it simplifies some very common tasks. Take for example, selecting items from the DOM:

/* selecting class "myClass" and changing the html to 
   "<em>Hello World</em>" and the text color to red in jQuery */

$(".myClass").html("Hello World)
             .css("color", "red");

/* doing the same in Vanilla JavaScript */

const myElement = document.querySelector(".myClass");

myElement.innerHTML = "<em>Hello World</em>";
myElement.style = "color: red";

The syntax for jQuery is much cleaner, being able to chain methods off of a single selector, and I believe at runtime (at least theoretically) the jQuery will execute quicker since it’s only searching the DOM once for a single selector (I have not tested this).

It’s not enough to get me to add jQuery to my projects. Just like the gains from Bootstrap are not enough to get me to use it either. There are situations where they both would have their uses, but for me it’s not in anything I’m currently working on. Also, there’s always the fact that React.JS is very jealous about controlling the DOM and doesn’t like to share. jQuery is all about DOM manipulation so there could be some turf wars.

Soft Skills

My ultimate goal is to one day be employed as a web developer. I don’t expect that to happen today, or even within the foreseeable future. It is the end goal, though, so I continue to work towards it.

As it turns out, learning to code is only half the challenge. I’ve read stories from some recruiters saying that they do not advertise for junior web developers anymore, because the second the ad goes up they get 1000+ resumes. I can’t imagine anyone wants to go through 1000+ resumes to find the perfect candidate, and I really can’t imagine what I could do to stand out in a field that size.

So nobody advertises for juniors anymore, but they still need to hire juniors. This is where the soft skills come in.

What The Crap Are Soft Skills?

Well, I guess Wikipedia says it best:

Soft skills are a combination of interpersonal people skills, social skills, communication skills, character traits, attitudes, career attributes, social intelligence and emotional intelligence quotients among others that enable people to effectively navigate their environment, work well with others, perform well, and achieve their goals with complementing hard skills.

I know the stereotype about coders. We’re all a bunch of anti-social shut-ins, more comfortable with email and message boards than face-to-face interaction. While this is mostly false, there is a kernel of truth here. I myself do not look forward to social interaction. Rarely do I find myself thinking, “Yay, I get to talk to people! Maybe even strangers!” I’d like to think, however, that I possess the skills to get through those situations and leave a favorable impression.

Soft skills are learned skills, and they require practice. I know it sounds silly. We’ve all been talking to other people our whole lives, why would we need to practice it? I’m fortunate to have a job what requires me to interact with people daily, both inside and outside of my company. When I first accepted my current position I didn’t realize just how much of it involved dealing with other people, but having to use those skills has given me a chance to grow those skills. How does that relate to finding a job?

The old saying goes, “It’s not what you know, but who you know.” This is pretty accurate, as I understand it, when looking for a junior position. You do need some coding skill, but the way to land that junior dev job is to know the people who are looking for junior devs.

Unfortunately, I’ve not been able to find a simple, lazy way to meet hiring managers or recruiters. There is not (to the best of my knowledge) a Tinder for junior web devs, nobody is going to be swiping right on your profile looking for a match. The best thing I’ve found is to go where I know I can find other people already working in the industry.

Slack, Discord, and Meetups, Oh My.

The big one here is the Meetups. Meeting people face to face, and having the necessary soft skills to make a favorable impression will take you a long way. I’m not suggesting going to these things in full-sell mode, approaching each individual as though you were a time-share salesman desperate for commission, but do be aware that the situation is a bit more than casual. If you make a bad impression here, people will remember that when faced with the prospect of seeing you every day at work. When you put someone down as a reference, you want them to tell the recruiter that you’re a super okay person who doesn’t smell and can form coherent sentences. Okay, maybe we should set the bar a bit higher than that. When I go to these meetups I ultimately want to meet people with the same passion as I have. I enjoy reading about code. I enjoy writing about code. I enjoy writing code and I really like talking to other people about code. These meetups give me a chance to do just that and the fact that some of these people might one day be coworkers makes it even better. Always, though, remember to present yourself as someone others would want to work with.

Slack and Discord are great ways for me to stay in touch with the people I meet at these meetups. Again, in these public settings it’s important to act professionally. It takes very little effort to ruin a good impression and an awful lot to improve a bad one. Even though I am not currently trying to “sell” myself to potential employers, it’s important not to tarnish the brand before the product goes to market.