Understanding Redux (or, How I Fell in Love with a JavaScript State Container)

Introduction

While researching which flux implementation to use for our team's final project at Hack Reactor, my friend Nick enthusiastically recommended Redux. (Nick is a brilliant front-end engineer who I worked with at Udacity, and is among the most curious and inventive people I know. So when he gets super excited about something, I pay attention.)

If you haven't heard of Redux yet, that's OK. The creator, Dan Abramov, announced it at React-Europe 2015, which, at the time of this writing, was 2 months ago. Was it risky adopting something so new for our team's project? Yes. But the more I learned about Redux, the more obsessed I (and my team) became. And we were not alone.

Goals of this Article

By the end of this article, you should:

  • Be able to explain to a friend what Redux is, and why it makes so much sense to use it with React.
  • Be able to describe the basic concepts behind Redux and React, particularly in contrast to traditional MVC architecture.  
  • Know where to go for high-quality resources to get started! 

Non-Goals

  • This is not a tutorial or a code lab. There will be very little, if any, code in this article. I'm working on a Redux/React/Webpack tutorial (follow me on Twitter for updates), and there are a number of great resources listed in the last section, if that's what you're looking for. 
  • This is not a deep discussion of MV*-whatevers. We can go on and on about the pros and cons (and many have) of various frameworks, but here's the truth. No matter what you choose -- a framework, a library, or nothing at all -- every programmer needs their app to do two things: Display stuff to the user, and track data. That's it. Redux/React is just one way to accomplish those two, age-old tasks. 

Assumed Prior Knowledge

I assume that you've heard of React, and ideally have read Thinking in React. If you haven't, you might not get as much out of this article because Redux is really, really brilliant when paired with React. If this is all new to you, it can be hard to tell where React stops and Redux begins (it was for me anyway), so having prior knowledge of React will make these conceptual distinctions more clear. 

I also assume that you know what MVC frameworks are, and ideally have used one before. While this prior knowledge is not required to grasp the concepts in this article, it's helpful because part of how I understand and communicate  Redux/React is by comparing it to well-known MVC frameworks like Backbone and Angular. 

What is Redux? 

I'm going to start with an analogy. Imagine you have a room with a sofa and a table, like this:

You want to swap the positions of the sofa and table, and you need it done FAST, so you hire two butlers, Alfred and Rudy, to complete the task at once. 

Alfred is in charge of the sofa, and Rudy is in charge of the table. You give them instructions to coordinate, so they aren't crashing furniture into each other. 

First, Rudy moves the table out of the way, then Alfred moves the sofa in position. 

Next, Rudy moves the table where the sofa used to be. The room now reflects its new desired state.

Super! I've just described a common implementation pattern found in MVC architecture. That wasn't so bad, but let's take it up a notch.

Now imagine you have a GENIE. This Genie provides a completely new instance of the room whenever you want to make a change to anything inside of it. And by "new instance" I mean, unlike Alfred and Rudy, she does not go inside Room A and move stuff around until Room A looks like Room B. She actually creates a new, unique room that is exactly Room B. If that wasn't enough, she also reads your mind. I know, right? It's an excellent setup you've got here. 

Instead of giving instructions to multiple butlers about what goes where, all you do is think, Hey Genie, I want this room to be this other room, which right now exists in our shared mind palace.

And POOF. Your Genie returns that new room in real life, so you now have TWO rooms, like this: 

The Genie? That's what Redux achieves with React. That's right. THE GENIE IS REAL.

Why is this desirable? Let's say the new furniture configuration is problematic for some reason. Like, maybe the sofa blocks a doorway, which creates suboptimal feng shui, and, also, a fire hazard. Instead of having Alfred and Rudy go back and re-position the furniture to where it was, you can just toss aside Room B, and flip back to Room A. 

Or, you can think of a completely different configuration, Room C, and your Genie will return it. If you ever want to revisit Rooms A or B, you can flip back to them. You might think that producing new rooms in this manner is wasteful and slow. It's not. Why? Because she's a motherfucking genie. This is her thing. 

Seriously though, right now, it's not important to know why it's fast, just know that it is very, very fast -- in fact, it's faster than the "If this, do that, then do this other thing..." approach embodied in the butlers example.

The capability to create new, immutable states is somewhat grandiosely (or maybe just dorkily) called "time travel" because you can traverse between your app's states. This is what React/Redux gives you. React provides the ability to spin up new rooms, and Redux provides the Genie mind-reader logic behind their production. This logic is very important, and is different from other implementations of a concept called flux, which we'll discuss briefly, next. 

OK, What is Redux, Actually? 

Redux, according to the docs, is "a predictable state container for JavaScript apps." It's a very lightweight (2kB) implementation of flux. If you haven't heard of flux before, that's fine. Nick explained it to me in about 10 seconds. 

Basically, flux is like a sedan. It's a concept with many agreed-upon characteristics associated with it, but it's not, itself, a tangible thing. Just as there's no single definitive "Sedan" that you can go out and buy, there's no definitive "Flux" that you can download and install. Instead, you choose one specific implementation of it. I don't know much about cars, but whatever the most minimal, stripped down, yet highly performant sedan is, that's Redux. 

The basic idea behind flux is, you have a dispatcher that sends actions to the data store, and updates the view. It's an overall data flow architecture, where -- unlike the two-way data binding of MVCs -- updates only go one way. If you've ever been in getter/setter hell trying to track what view is touching what model, you can understand how a one-way data flow might be beneficial. 

Note: This isn't a knock on frameworks like Angular (which I still think is pretty magical) or Backbone (which I... respect as a thing), or any other MVC. In general, I try not to get attached to any one way as the best way for everyone. What constitutes the "best" approach really depends on your application, your use case, and your organization's needs and constraints.

With all that said, here's a helpful diagram from Facebook's Flux documentation:

flux-simple-f8-diagram-1300w.png

One huge implication of one-way (or unidirectional) data flow is that your data store is not touched by your view. At all. 

Redux is one particular implementation of a subset of flux concepts. The main differences between Redux and full flux implementations are:

  • There are no discrete dispatchers in Redux; your store listens directly for actions, and uses a function called a reducer (more on this later) to return a new app state each time an action is dispatched. 
  • Redux holds your entire application's state in one place.
  • Your app's state is immutable.

Consider your app state as a tree, with a root and child nodes. If you want to make a change to a child node, you can't change it directly because state is immutable, so you make a copy of the target node and apply your changes. You also make a copy of the target node's parent, because it wouldn't make sense to have one parent produce two versions of the exact same node. Maybe you append a child node to the new node, too. That's fine. At the end of all this, you just need to attach the existing, unchanged nodes to your new ones. Like this: immutable

The best part is, the original state (the blue one) still exists. The unchanged blue nodes are not re-rendered in the new state, just the orange nodes. This makes debugging really easy because you can isolate the action that caused the state change, and go back and forth at any time. Redux dev tools also happen to be unusually good (see the next section for an example), and, combined with React dev tools, have basically spoiled me for life.  

Another implication of this design pattern: You really cut down on the number of dependent asynchronous operations in your data flow. Going back to the room example, recall how you managed the butlers: "Wait for the table to be out of the way, then move sofa..." 

Contrast that to the declarative statement: "Sofa and table are positioned at (fill in the x,y coordinates here)." The end. No waiting for Rudy or Alfred or whoever to clear the way first.

Intuitively, this makes sense. If you want a room with a sofa and table in it, positioned in a certain way, then why should it matter the order in which  items are placed? This straightforwardness is what really won me over -- it just feels right to me. 

How Does Redux Work?

Redux is astonishingly simple. It uses a function called a reducer (a name derived from the JavaScript reduce method) that takes two parameters: An action, and a next state.

The reducer has access to the current (soon to be previous) state, applies the given action to that state, and returns the desired next state.

Reducers are designed to be pure functions; meaning, they produce no side effects. If you pass the same input values to a reducer 100 times, you will get the exact same output value 100 times. Nothing weird happens. They are completely predictable. As someone with a prominent "NO SURPRISES" sticky note on my monitor, this is a wonderful idea to contemplate.

Reducers do not store state, and they do NOT mutate state. They are passed state, and they return state. This is what reducers look like in action (did I mention that the dev tools are awesome?):

The above is the console after two actions: "Fetch Friend," followed by "Save Gifts." The first action passed FETCH_FRIEND to the reducer with an updated friend object that is returned in the next state. The second action passed SAVE_GIFTS to the reducer, along with an array of 4 gifts. The next state reflects this updated gift array. As usual, you can see exactly what existed in the state before and after this action occurred by simply inspecting each object.

Note that the reducer is passed only the slice of state that requires updating (the friend object and the gifts array, respectively), and it returns a new state after each action is dispatched.

How Do I Get Started? 

Woohoo! You are entering a brave new world with me! Yay! It is very exciting, and also, at times, a real pain in the bottom. So before you dive in, some caveats:

  • Redux and React are often used with a module bundler called Webpack. Webpack is incredibly powerful, and one day, it will be well-documented and easy to use (or it will wither and die of JSPM). In any case, that day is not today (Sept. 15, 2015). For now, do NOT worry about it, and just focus on learning the fundamentals of Redux and React with the resources below. 
  • Most code examples you see will use ES6 syntax. This can be confusing, and looks sort of... like Python and Coffeescript got drunk and had a baby. Fear not! Use Babel's transpiler tool. Just cut and paste the ES6 on the left, and you'll see familiar old ECMA5 on the right. Believe it or not, you'll get used to ES6 pretty fast (even the switch statements, I promise).

If you are looking for polished, well-documented code examples, and stable builds, then this is not the right time for you to try Redux. And that's totally fine. You can always come back in a few months, or when you have more time to dig through documentation. 

Selected Resources 

I've gone through a horrifying quantity of material on flux, Redux, React, Webpack, ES6/7, and god knows what else. I think at one point I was reading about Drupal (don't ask). Below are the best resources I've found, optimizing for fundamentals, clear examples, and sound teaching strategies. 

Required Basics (listed in order)

Live React -- 30-min talk by Dan Abramov, who basically invented Redux on accident (just like penicillin!). He explains Redux in beautiful amazing live code. It's especially useful to see, step-by-step, how he came upon reducers while paring down his flux workflow. 

Thinking in React -- A fantastic guide to React by Facebook's Pete Hunt that helped me fully grasp how React and Redux are perfect for each other. 

Redux Tutorial by François Bonnefont -- Of all the Redux tutorials and code examples I've reviewed (at least 20), this is easily the best at explaining the fundamentals, and walking you through each step. I recommend forking and cloning the repo, and replicating the code samples as you go along. Make sure to read the README. It includes important instructions on how to run the code examples from your terminal. 

Advanced: After you complete the above, and are ready to build a full-stack app from scratch using Test-Driven Development practices, check out @Teropa's Full-Stack Redux Tutorial

Extra Credit 

Immutable Data and React -- 30-min talk by Facebook's Lee Byron from React-Europe that explains why persistent, immutable data structures are the way of the future. 

What the Flux, Let's Redux -- A good overview of why Redux is exciting. The author, Henrik Joreteg, also made a great Webpack template, if you need it later. But, as I said, don't worry about Webpack while you're still learning the basics of Redux. 

Building CircleCI's Front-End with Om -- While not about Redux, specifically, Brandon Bloom does a really nice job of explaining the benefits and trade-offs of a similar implementation in the wild.  

Important References

Official Redux Documentation -- Redux is still new, so keep in mind that documentation is still a WIP. Check out the examples when you're ready. Implement the Counter example to get a quick start. The most helpful example for me was the Real World one. 

Awesome Redux -- A comprehensive resource list of everything Redux. I found this a little overwhelming to start with, but once you know what you're looking for, it's a great resource. 

Official React Documentation -- The React docs are kind of hit or miss, but definitely worth reviewing and bookmarking. You will be referencing them a lot as you get to know React. 

 

Calculating days between dates in JavaScript

I'm working on a React/Redux app that pulls your friends' upcoming birthdays from Facebook, and recommends gifts for them based on their profile data. Our team finished the MVP (aka, "minimally viable product") this week, and one of the last TODOs was to render a user's friends list by upcoming birthday. We wanted the soonest birthday to show up first. 

I took on the task, and had a lot of fun understanding the problem, and discovering edge cases. I also learned more about JavaScript's Date object, which is very handy. 

My Approach

  1. Get today's date, which you can do with JavaScript's Date.getDate() method. This will return the number of milliseconds between January 1, 1970 and today (long story). Add 1 to the month because JavaScript starts counting at 0, and you want to set January to 1, not 0.
  2. Get friend's birthday from Facebook, also in milliseconds
  3. Change friend's birth year to the current year, since their upcoming birthday is what you care about
  4. Subtract today's date from friend's birthdate. If result is negative, that means that your friend's birthday has already passed, so add 365 to get the number of days until their next birthday (TODO: account for leap years)
  5. Do some work to order your friends by upcoming birthday, soonest first

You can find the commented code on GitHub here. I also added it below, for convenience.

// Redux uses switch statements in its reducers. 
// It's not so bad once you get used to it, I promise.
case FETCH_FRIENDS:

  var getDaysFromToday = function(birthday) {
    if(!birthday) {
      return null;
    }
    // create new Date for today
    var today = new Date();

    // add 1 to current month because getMonth returns months starting at 0
    var currentMonth = today.getMonth() + 1;
    var currentYear = today.getFullYear();
    var currentDD = today.getDate();
    // create new Date for today, reflecting adjusted month
    today = new Date(currentYear, currentMonth, currentDD);

    // initialize array to hold friend's 'MM/DD/YY' bday as [ 'MM', 'DD', 'YY' ]
    var friendBdayArray = birthday.split('/');
    var friendBdayMonth = friendBdayArray[0];
    var friendBdayDD = friendBdayArray[1];

    // create new Date, replacing birth year with current year
    var friendBday = new Date(currentYear, friendBdayMonth, friendBdayDD);

    // calculate time between now to friend's day -- getTime() returns time in ms
    // NOTE: if day is in the past, elapsed will be negative
    var elapsed = ( friendBday.getTime() - today.getTime() );
    // divide by 86,400,000 to convert milliseconds to days
    var daysFromToday = Math.floor(elapsed / 86400000);
    // add 365 to any negative daysFromToday value to get days until next year's date
    daysFromToday > 0 ? daysFromToday = daysFromToday : daysFromToday = daysFromToday + 365;
    
    return daysFromToday;    
  };
  // append daysFromToday to each friend object and push to friends array
  var friends = [];
  action.friends.forEach(function(friend) {
    friend.daysFromToday = getDaysFromToday(friend.birthday);
    friends.push(friend);
  });

  // sort friends in array by daysFromToday in descending order
  friends.sort(function(friendA, friendB){
    if (friendA.daysFromToday === null) {
      return 1;
    }
    if (friendB.daysFromToday === null) {
      return -1;
    }
    return friendA.daysFromToday - friendB.daysFromToday;
  });
  // finally, return the updated state (es6 syntax)
  return Object.assign({}, state, { friends: friends });

How to run/build JavaScript code in Sublime

Confession: I setup a Node build system in Sublime before I even know what Node was. As soon as I installed Sublime, I wondered, "Why can't I run anything in JavaScript in here?" 

So I googled and figured it out. Of course, I promptly forgot how I did it (people at Hack Reactor have asked, and I just stare at them blankly). 

Luckily, Eliot Winder has documented this process for us! Check it out.

CMD-B, y'all. It's a game changer. 

One App, Three Ways: PhotoMVC with Backbone, Angular and React

There's a great resource called TodoMVC that takes the classic Todo app, and implements it using every MVC/MV* framework imaginable. This weekend, I embarked on my own version of TodoMVC with a photo app that displays a selected photo from a list, and lets you give that photo a rating.

Here's the finished product:

 Angular version, with help from Bootstrap 

Angular version, with help from Bootstrap 

I built all three apps from scratch. My experience was all over the map. I had moments of great enlightenment, and I had stretches where everything felt like a godawful ordeal. If you're at all shaky on MVC/MV* frameworks, I strongly recommend doing this exercise with the frameworks of your choice. It really drives home the concepts of state management and rendering, and gives you a newfound appreciation (or, at times, outright dismay) for how different client side frameworks manage the age-old tasks of updating data and displaying views. 

Here's a quick breakdown of my impressions (repos linked): 

  • Backbone is the least magical experience of all
  • Angular is super magical and intuitive, but it can feel kind of hacky at times
  • React is the Backbone of the future, and -- coupled with Redux -- is the most exciting thing that I'm learning right now 

I'll post more about React/Redux and the One State Container to Rule Them All later this week, so watch this space if you're interested in such matters.  Until then, commence hacking! 

Prime Numbers and the Sieve of Eratosthenes

A friend of mine pointed me to Harvey Mudd's CS for All, and I fell madly in love with this section, in particular: The Sieve of Eratosthenes

In fact, I believe my exact words upon learning about this method of finding primes was, "WHERE HAS THIS BEEN ALL MY LIFE?!" 

Now I'm working on a function to implement it in JavaScript, and it's super fun. 

Highly recommend checking out the Harvey Mudd link -- it's an awesome CS resource.

 

Back to JavaScript Basics: VARIABLES!

We are officially in the "senior" portion of the program at Hack Reactor, and are moving towards more project-based work, and hiring/career skills prep. To help prepare for mock interviews, I'm reviewing some of my notes from earlier in the year. It's been nice to go back and get a refresher on the basics, this time coming with a much stronger sense of the subject material.

So, let's talk about variables. First, a definition:

Variable: A label that points to a value that is stored in memory. Once a variable is assigned, you can refer to it later in your code.

OK, that's nice, you might think. But what's the big? There are TWO big reasons why we care about this property of variables that I'll go over real quick.

Building efficient programs

var storedNum = (1+1)*2;
console.log(result); // 4
console.log(result); // 4
In this example, the variable storedNum is computed only once, and the computed result is logged twice. If you ran console.log((1+1)*2); each time you needed to access the stored number, the computer would have to compute the result each time. Maybe that's fine for this super simple example, but you can imagine how this would be meaningfully inefficient if you had a complex computation that required a non-trivial amount of memory. What else should you know about variables? You can use them to point to the values stored in other variables!
var storedNum = (1+1)*2;
console.log(storedNum); // 4
var other = storedNum; 
storedNum = 5;
console.log(other); // 4

If you're wondering why other still evaluates to 4, even after storedNum is set to 5, it might help to think of variables as physical labels, or nametags.

Let's say you have a "cookie" nametag on a box of Oreos, and then you stick a "milk" nametag on the same box. Now imagine you peel off the "cookie" nametag and put it on a box of Teddy Grahams. What happens to the "milk" nametag? It's still on the box of Oreos. Just because you moved the "cookie" nametag to the Teddy Grahams box, it doesn't mean that the "milk" nametag moves to the Teddy Grahams. The "milk" nametag stays on the Oreos until it's moved and affixed to something else.

Man. Now I really want Oreos.

Here's another way to think about variables pointing to other variables:

var storedNum = (1+1)*2;
console.log(storedNum); // 4
var other = storedNum + 0; 
storedNum = 5;
console.log(other); // 4

One helpful trick is to assign other a value of storedNum + 0. This the exact same thing as before, but makes it clearer that other is independent of the storedNum variable.

* But, seriously, why do we care? *

Accessing certain values

The second major reason that we care about variables is because sometimes it's not possible to type out a literal that represents a value in your program. For example, let's say you need a random number:

var randomNum = Math.random();
console.log(randomNum);

Since you don't know what the random number will be, you have to store the value in a variable if you want to access that random number value later.

Finding the Perfect Color Scheme

I love colourz!!

I've spent entirely too much time perusing color schemes while designing my apps, and you can too! 

Recommended Resources

Color Hunt

  • Updates daily with a new theme of 4 colors.
  • Dead simple to use. Color values are super easy to copy/paste into your CSS.
  • No login required to pin and save your favorite themes.
 A few of my favorite swatches

A few of my favorite swatches

 I'm partial to "Mustang"

I'm partial to "Mustang"

  • 5 colors per theme. 
  • Requires login to save favorite themes, and/or to create your own custom themes.
  • More advanced functionality than Color Hunt, but the interface can be confusing.
  • Pro Tip: Click "edit copy" to get the RGB and HEX values all in one view.
  • Super Pro Tip: Definitely read the comments under your favorite swatches. Listening to people talk about colors is... weirdly uplifting.

Favorite Schemes

Quiet Cry

Screen Shot 2015-08-20 at 10.16.06 AM.png

I think what I love best about this theme is the name. I can imagine the colorist weeping softly while adjusting RGB values to achieve the precise mixture of coolness and melancholy that captures a quiet cry in the bath. 

Also, the user comments for this theme are touchingly intimate.

I've been using this theme on my personal resume site. It has a nice combination of weight and cheerfulness to it. Color Hunt doesn't give names to their themes, so I made one up!

   

How to Use ESLint (and JSHint) with Sublime Text

I used to be a copy editor and pride myself on catching syntax errors, so the fact that I've named the superhero version of myself the "Human Linter" is not at all sad. In spite of my linting prowess, if it's late, or if I'm staring at 5 nested callbacks, using an actual linter can be a godsend. 

What is a linter, you ask? A linter is like a spell-check/grammar-check tool for code. Linters are very useful for catching syntax errors in static code that could break your program.

JSHint vs. ESLint

For the last few months, I've been using JSHint with Sublime Text.  This is a pretty good system and catches most major errors right out of the box. JSHint is a fairly relaxed linter by default. For example, it doesn't catch anything here:

 Can you spot the flaws in this code? 

Can you spot the flaws in this code? 

You can configure JSHint to be stricter, but if you need advanced customizations, you might be better off starting with ESLint. It takes a few more steps to install using command line and Sublime's Package Manager, but it has a ton of rules that are easy to configure exactly how you want. You can even make your own rules. 

The default settings will extend ESLint's recommended rules, which are fairly strict. Here is the same file linted with ESLint, using its default settings:

 Two errors caught in ESLint that we didn't see with JSHint.

Two errors caught in ESLint that we didn't see with JSHint.

I configured a few ESLint rules to match my workflow and style preferences. Specifically, I relaxed the no-console rule to be a warning (in yellow) vs. an error. I also enabled the no-comment rule to detect "TODO" statements and mark them as warnings. Finally, I added a style warning to enforce spaces after keywords ("if," "else," "for", etc) and before blocks. 

This is the test file again, with my customizations added to the ESLint defaults:

 My linted heart is happy.

My linted heart is happy.

Here is my .eslintrc configuration file. As you can see, it's simple to override and specify rules:

 Rules rules rules... 

Rules rules rules... 

I changed the default indent to use spaces instead of tabs, with a width of 2 spaces per indent. You can find more info on indent rules here

To install and set-up ESLint, follow the instructions in the documentation, here

After you run eslint --init, answer a few questions and your .eslintrc file will be created for you. Then just open that file and modify it to your heart's content!

Using both ESLint and JSHint

If ESLint is too heavyweight for what you need right now, but you can imagine using it in production, you can toggle between linters easily in Sublime, with the keyboard shortcut CTRL + CMD + T (in Mac). That way, you can use whichever linter makes the most sense for your project at the time. 

 Toggle between linters for maximum flexibility (or if you're just indecisive).

Toggle between linters for maximum flexibility (or if you're just indecisive).

Happy linting!

My first full-stack app: Forget Me Not

Last week at Hack Reactor, we each had to build an MVP (Minimum Viable Product), from scratch, and have it ready to present the next day. Up until this point, we had been working on structured projects in pairs, so this was the first time that we were all on our own. 

The Idea

I approached this project with a mix of trepidation and morbid curiosity of just what, exactly, I could hack together in 2 days. I thought of an app idea while at the gym, came back and sketched out the user flow and features on a piece of paper, and then just went from there.

My app is a simple memory helper for teachers who have trouble remembering their students' names. You can read about it in this mock press release.


The Process

I (once again) was grateful that I'd taken Javascript Design Patterns, which taught me how to approach building the app structure from the very beginning. After I had my sketches done, I set up my file structure and read up on MEAN stacks, which I decided would be a good fit for this project and just cool to try out. 

MEAN stands for Mongo, Express, Angular and Node, which together comprise an end-to-end Javascript tech stack. 

After 12 hours of solid hacking, I had the views running, and one of my two features working. The app would accept a user's guess, and return the appropriate response. I also set up my server routes, and tested my POST, GET and PUT requests to ensure they all did what they should. Huzzah!  

On day 2, I tackled the task of saving and storing a user's hint. I also hooked up the app to Mongo. Up until this point, I'd been using hard-coded data. I wasn't able to refactor the app by mid-day, so decided that I would just use the hard-coded data for my presentation. I talked with a Hacker in Residence (analogous to a TA), and they said that would be perfectly acceptable, given the "minimum viable" nature of the project. 


The App

Here's how it turned out! You can check out the repo here, with the understanding that the code works, but is far from final. 

 Home screen. Styling courtesy of the ubiquitous Twitter Bootstrap 

Home screen. Styling courtesy of the ubiquitous Twitter Bootstrap 

 Student photo shown with a simple prompt

Student photo shown with a simple prompt

 If the guess is incorrect, the user can write and save a hint about that student to connect their name with their face.

If the guess is incorrect, the user can write and save a hint about that student to connect their name with their face.

 If the user gets the name right, a "correct" response is shown, and they are encouraged to keep playing.

If the user gets the name right, a "correct" response is shown, and they are encouraged to keep playing.


Lessons Learned

First, and most important, I learned that I'm capable of hacking something together in a constrained period of time that isn't a total disaster. And that I can learn the technologies I'm going to apply while I'm trying to apply them. That was pretty cool. The project also reinforced the value of just getting your hands dirty and building stuff as the best way to understand the technology you're using. 

More technically, I learned that how you manage your data is very, very important! Next time, I would spend a little more time on deciding how best to handle the data for my app, and plan that out first. I think it would have made all the other decisions I had to make more self-evident. 

I also saw firsthand the value of time-boxing, and being able to manage yourself competently. I have a lot of practice managing myself and others while building user-facing products, and that experience served me well for this sprint. Staying focused on the user persona I had created (a teacher who has trouble remembering students' names) was essential to keeping the project scope manageable, and ultimately ensured that I'd have a product with a clear story to deliver.

 

 

Day 28 of Hack Reactor: Backing the Back-End

Somehow, 4 weeks have sailed by since my cohort started, and I can't even begin to process the amount of learning that's happened during that time.

Last week, we focused on back-end architecture and server-side techniques, specifically building a custom back-end in Node, implementing an ORM, understanding promises, and building databases. Next week, we move on to authentication and Angular.

I've enjoyed this back-end stuff more than I expected. I think partly because there are so many intellectual challenges associated with designing and configuring a back-end, and fewer of the semantic challenges that tend to accompany front-end work.

Interested in learning more? Here are some resources I've found helpful (free, unless noted):

Learning HTML/CSS with Dash

If you recall, I've harbored a general dislike for HTML/CSS for a while now, but I think I'm coming around to something like... lukewarm acceptance. Yeah! Let's go with that. 

I finally checked out General Assembly's Dash, and it is really, really well done. It's project oriented and has a slick interface. Like many beginner courses, it can be a little too "hand-holdy" at times, but it's still a very worthwhile use of an hour or two if your HTML/CSS is rusty. Besides, it's HTML/CSS. You might like it just fine, but you're probably not going to spend hours and hours trying to look into its soul. That's what JavaScript is for!

Animations, Transitions and Keeping CSS Kosher

Wrapping up Code School's excellent (and free!) Try jQuery course, and concluded with animations for making an element on the page move up when you click on it. 

There are two ways they show you how to do this. One is by using jQuery's animate() method in your app code (let's call it your app.js file):

$(this).animate({'top': '-10px'}, 'fast');

And the other is to separate out all the styling and store it in your app.css file, and refer to it in your app.js file.  This is what I call "keeping CSS kosher."

// app.js
$('div').on('click', '.someElement', function() {
  $(this).toggleClass('highlight');
});

// app.css 
.someElement {
  transition: top 0.2s; // assumes browser supports CSS transitions
}
.highlight {
  top: -10px;
}

Keeping CSS kosher requires a lot more code, and also assumes browser compatibility. According to CanIUse, about 7 percent of browser usage globally does not support CSS transitions, and half of that comes from Opera Mini, which Jacques (hi, Jacques!) says it's OK to ignore. So that leaves us with 3 percent global usage, or 5.6 percent U.S. (IE 8 and 9 users) unsupported.

So why keep CSS kosher if: 1) It requires more code, and; 2) It leaves out a small but actual percentage of users on unsupported browsers? 

First, it makes it easier to maintain your code if you keep all styling separate. This I know to be true from experience... painful experience.

Second, Jacques says it is way more performant to keep CSS kosher because then your computer will offload transitions to the GPU, which is built to handle tasks like that. 

So, when it comes down to it, your decision tree would be:

  • Do I have to support IE 8 and/or IE 9 users?
    • Yes: Use jQuery methods in your app.js file. Maybe eat a ham sandwich, and wash it down with milk while you're at it. 
    • No: Keep CSS kosher. Create classes in your app.css file, and refer to them in your app.js file.

Popping and Pushing (more memory tricks)

Definition

The push() and pop() methods add elements to and remove elements from the back of an array.

var arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [ 1, 2, 3, 4 ]
var poppedValue = arr.pop();
console.log(poppedValue); // 4
console.log(arr); // [ 1, 2, 3 ]

Memory Tricks

  • To associate these methods with each other, remember that push-pops are delicious. (I think of them as ice cream treats*, but in my research for this blog post, I discovered that they're actually those weird/gross candy sucker things. Whatever. To me, push-pops = frozen novelties === DELICIOUS)
  • Both of these methods do something to the back of an array, so I like to think of push and pop as a kind of dance method involving your butt. (Like, "Salt-Salt-Salt-N-Pepa's here! ... Want you to push it back!" (and then they do something with their butts) You know that song, right?** #Imightnotbeyoung)
  • I have used push so often that I know it changes the length of an array, but sometimes forget that pop also changes the array -- keeping them associated together will help me remember this.

Keeping these methods straight is pretty intuitive for me, you push something on, and you pop something off. So I don't need a memory trick for that part at least.

* As it turns out, the ice cream treats I'm thinking of are actually called Push-Ups, which sounds like a horribly unpleasant activity to do at all, let alone while eating ice cream.

** Did you know Salt-N-Pepa's "Push It" came out in 1986?!! Also, did you know that video is the best BEST not-actually-a-music-video music video in the history of EVER? I love both Salt and Pepa. I even love the awkwardly capitalized 'N' in between them. Man. If I could, I'd just stop coding right now and watch old Salt-N-Pepa videos ALL DAY.

Arrays! And memory tricks for keeping shift and unshift straight

I just spent about an hour studying arrays. I thought I had a good handle on them, and I'm sure at one point I did, but there was PLENTY of material that I needed to re-study as a refresher. Studying the basics as part of my Hack Reactor precoursework has been very humbling, and I'm really happy that they make us do this!

One thing that I often get confused about is shift() and unshift(). Both of these methods do different things to an array and return non-obvious elements. How to keep them straight? I'll get into that in a moment.

Definitions

The shift() method removes the first element of an array and returns it. It changes the length of the array. If the array has a length of 0, then array.shift() returns undefined .

The unshift() method adds one or more elements to the beginning of an array, and returns the new length of the array. Like shift , it changes the length of the array.

var arr = [1, 2, 3];
console.log(arr.shift()); // 1 
console.log(arr); // [ 2, 3 ]
console.log(arr.unshift(0)); // 3 <- new length of arr
console.log(arr); // [ 0, 2, 3 ]

Memory tricks

Warning: These are silly! But they work for me.

  • Lots of F's: shiFt and unshiFt = the Front of an array.
  • Think of shift like a worker getting off their shift, using a first in [index 0], first out approach. So whoever is at the start of the line [index 0] gets off their shift, and is returned to you. The array actually changes as a result: You have one fewer worker, and all remaining workers are moved up towards the front of the line by one position.
  • Think of the Unshift Family as an annoying family obsessed with how many people they have (like those people who are really into geneology, and keeping ancestry.com in business), so they're going to return the size of their family.
  • Unshift is a fatter word than shift, so of course you're going to end up with a "fatter" array.

I love mnemonic devices (basically attaching a "sticky" mental association to new words so you remember their meanings better - I'm pretty sure that's NOT the scientific definition, btw). I've picked up multiple languages -- from Arabic to Albanian -- using mnemonic devices. The key is not to be embarrassed by the weird turns and graspings that your mind will take in order to attach meaning to a new word or concept. You only need the device while you're learning.

At some point, your reliance on the device falls away and you'll just know that shift() returns the first element of an array, or that "Faleminderit" means "thanks" in Albanian, and you'll evven forget the mnemonic you used to get you there! Brains are awesome like that.

My Random Number Generator now handles weird decimal edge cases

Alright. I think I maybe got this silly thing working as it should. I looked up isNumber and it seems like it basically does an upgraded version of what the conditional in my first while loop does. The thing is, I actually understand what my conditional does (filters out all falsey values except for 0) because I wrote it, and I'm fine with it for now. I might upgrade later once I fully understand isNumber. (As a rule, I don't like writing code that I don't 100 percent understand.)

Anyway, I then tackled the edge cases that have been irking me. Specifically, what if a user inputs something like (3.1, 3.9) as their values? In my previous version, the RNG returns 3 because it applies Math.floor to the max and min, which in this case amounts to (3, 3). But 3.0 is not within the user-defined parameter of (3.1, 3.9). So fooey.

In my newest iteration, I added a new while loop that tests if Math.floor of the min and max are equivalent, and demands a new WHOLE number while this condition is true. I then stored this new value into one of the original nums, and reassigned max and min based on the new value pair.

Finally, I generate a random number, and added new bits of code to the variable that is returned to the user. I rounded-up the min and rounded-down the max to ensure that whatever integer is returned falls within a safe range. OK, this is too many words now. Here is my code.

// collect num1 from user
do {
    // Use parseFloat bc parseInt evaluates non-zero values under 1 as NaN 
    var num1 = parseFloat(prompt("Give me a number!"));
}
while (num1 !== 0 && !num1); // do not accept falsy values except for 0 

// collect num2 from user
do {
    var num2 = parseFloat(prompt("Give me a different number!"));
}
while (num2 !== 0 && !num2); 

// do not accept num2 if it is equal to num1
while (num2 === num1){
    num2 = parseInt(prompt("Give me a DIFFERENT number!")); 
}

// find and store the min and max
var min = Math.min(num1, num2);
var max = Math.max(num1, num2);

// if the Math.floor values are the same, ask for a diff whole number
// accounts for edge cases where user inputs something like (5.4, 5.3) and gets 5 [5.0 falls outside 5.3 - 5.4]
while (Math.floor(min) === Math.floor(max)) {
    // reassign num2 (could also reassign num1), and set new min and max
    num2 = parseInt(prompt("Give me a different WHOLE number!"));
    min = Math.min(num1, num2);
    max = Math.max(num1, num2);
}

// store random whole number in variable to return to user
// round up the min value and round down the max value, so you can return inclusive min/max integers
var randomNum = Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + Math.ceil(min);

alert("Your random whole number is " + randomNum);
document.write();

Goals for this week

This week I will:

  1. Make time to learn: I have dedicated 6:30am-8:00am on Monday-Thursday for learning. 
  2. Finish the Treehouse How to Make a Website course -- I'm almost halfway done, and have created a spectacularly ugly website! Right now, I'm learning about CSS and styling. Did you know that RGB stands for "Red," "Green," "Blue," and that the 6-character hexadecimal value is just a pairing of the red, blue and green amounts in a color? I did not know this. I also didn't realize that hexadecimal refers to a base-16 numbering system, where the letters A-F stand in for numbers 10-15. That allows you to use a digit of value 0-15 per character, vs just 0-9. All of a sudden, a lot of stuff makes more sense!  
  3. Account for weird decimal edge cases in my Random Number Generator -- Thanks to a tip from fnenu, I will try using the isNumber property.  

I think that's a reasonable amount of stuff for this week. Let's see how I do! 

Getting out of the "Code Sinkhole": A less crazy random number generator

Chatted with fnenu this morning about the state of my poor random number generator. I really built a monster from what was supposed to be a simple exercise. Welcome to programming, I suppose. Anyway, it FINALLY occurred to me that there was no need to calculate the difference between the max and min values, since the min value is subtracted from the max before being multiplied by Math.random().

And then I figured I should just use Math.max() and Math.min() to identify the upper and lower (inclusive) bounds for the set of possible numbers returned to the user. It feels a little weird applying them to a set of 2 numbers, but the code certainly does not suffer from the omission of extraneous if statements that I had in my previous version.

I think what this illustrates is, even "simple" coding problems can quickly take on a life of their own, and before you know it you're passing in conditionals and callbacks left and right. I think of this as falling into the "code sinkhole." If you sense yourself getting stuck down there, it might be a good time to get a snack or take a walk. Because you don't want to be in the code sinkhole for too long.

// TODO: deal with non-number inputs

// collect num1 from user
var num1 = parseInt(prompt("Give me a number!"));

// collect num2 from user
var num2 = parseInt(prompt("Give me a different number!"));

// do not accept num2 if it is equal to num1
while (num2 === num1){
  num2 = parseInt(prompt("Give me a DIFFERENT number!")); 
}

// find and store the min and max
var min = Math.min(num1, num2);
var max = Math.max(num1, num2);

// use Math methods to generate random num 
// store in variable to return to user
// need to start from the min (inclusive), rather than start from 0
var randomNum = Math.floor(Math.random() * (max - min + 1)) + min;

// alert the randomNum to user
alert("Your number is " + randomNum);
document.write();

Code review and changes for my Random Number Generator

If you recall, last week, I made a random number generator as part of the Treehouse JS Basics course. Well, after fnenu did code review, I realized I had some weird stuff going on there!  

The easiest way to explain the mistakes I made is to see the diff.  

This seems like a lot more code, and I'm sure there are ways to slim it down. (Pull requests welcome!) 

NaN !== NaN (aka JavaScript==='CRAZY')

Working on re-implementing lodash, and discovered this expression in their comparator function:

var valIsReflexive = value === value; 
// um.. WTH is THAT ^^^^^^^^ 

Not understanding why there were two separate "equals" statements (the first as an assignment, and the second as a strict equality operator), I asked my friend Lindsey for help. She explained that the '===' is making a comparison, and the value of the comparison, value === value (true or false), is then stored in the variable, valIsReflexive.

Which then begs the question, when would value === value ever evalute to false?

So back to Stack Overflow I went, and eventally landed here.

And that's where I learned that NaN is, like, totally crazypants. I ran a few tests in my code, to confirm this; results below.

console.log(NaN===NaN);
// false
console.log(3/0===4/0);
// true

And then, I was like, "WAT." (You should totally watch that, btw. Gary Bernhardt === GOLD.) But then fnenu asked, "What if you set those values to variables, does it still evaluate to false?" This is an excellent question, so I ran another test:

var wat = NaN;
var waat = NaN;
console.log(wat===waat);
// false
console.log(wat===wat);
// false   <-- I KNOW, RIGHT?! 

GAH. Mind, bent.

Code conventions for JavaScript

Praise be to Stack Overflow for leading me to this gem by JS guru Douglas Crockford. 

I'm studying the lodash documentation (more on this later) and wondered what the ALLUPPERCASE named variables were supposed to be, so I searched for it and stumbled upon a great resource that I hadn't been expecting, but am so totally ready to consume. Behold, Internet!