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. 

Hack Reactor Mail Bag!

Hello, reader! 

I've gotten a variety of questions about Hack Reactor, and am batching them here since they are often repeat questions. My goal is to help prospective students without undermining Hack Reactor's admissions or assessment processes (I'm not going to repeat what questions were asked, and how I answered them, for example). 

Keep in mind that Hack Reactor updates their processes regularly, so my experience may not be relevant to whatever is in place by the time you are reading this. 

With all caveats declared, on to the questions! 

About that Hiring Day Assessment...

Question: In "Day 41 of Hack Reactor: Hiring Assessment and Solo Week", you mentioned the repercussions of not passing the assessment. If you don't pass it, is there an opportunity to take it again? Does anything else happen if you don't pass? Have you heard if you have passed yet and do you know the pass rate?

Answer

If you don't pass, there is not a second chance to take the exam. The point of the assessment is to do just that -- assess where you are, at that point in time -- not to pass the exam, itself. What matters is that you and the teaching team at Hack Reactor have a solid understanding of where you are, relative to the bar they set for hirable engineers, and if you aren't where you need to be, then you have a good basis for planning how to get there. 

I cleared the bar, but I found that the assessment was a legitimate challenge. I don't feel comfortable disclosing the pass rate because it's going to vary per cohort, and cohorts are relatively small (40 students in mine), so even one person not passing will have a non-trivial impact (on an absolute scale) on the pass rate. I can say a very small number of students did not pass the assessment. If you don't pass, then Hack Reactor cannot recommend you to their network of companies, BUT they will still help you strengthen all the skills you need in order to get a job as an engineer (technical skills, professional skills, interview prep, etc). 

Just to be clear, passing or not passing the Hiring Assessment (or ANY test), says nothing about your potential. It says nothing about how hard you've worked, or how hard you will continue to work to reach your goals. It says nothing about you as a person. All it reveals is where you are, on some pre-set scale, at some arbitrary moment in time.

Had I not passed, I would continue to make the most of every opportunity to learn and grow, which is what I've done my whole life, and what has gotten me so far in the first place. I would continue to have the same, positive attitude about learning and finding solutions to novel problems, and I'd continue to seek out help and feedback in areas where I need to improve.

Most importantly, I would be just as proud of how far I've come, whether I had passed the test or not. No test could ever change that.  

Admissions: If you get asked to submit a project...

Question: How did you decide on what project to create? More specifically, how did you decide on something that might show the growth you've had since your last interview, without picking something too ambitious? 

Answer

I took the Udacity Javascript basics course (all content/projects free) and did the resume project. I also made a TODO list after taking a Treehouse course (paid). I submitted both, and am not sure if one or the other was more responsible for getting me a second interview.

If I had to do it again, I would pick ONE project that involves taking a user action (i.e. a click), and having that action render something to the DOM (i.e. display a photo) on the screen. I would not focus on style, just on pure functionality.

The "Cat Clicker" project in JS Design Patterns (free) is a fantastic model.

Don't feel like you need to rush to complete the project just so you can say that you did it. What's important is that you actually understand what is going on in your program, so you could explain it to someone if asked.

You should be able to explain your app logic, for example: What happens when a user clicks on the button? What is communicated to your program? How does your program handle the click action, and what does it do as a result? 

If you take the time to build and fully understand a project like the Cat Clicker (or anything else that involves a user interacting with the DOM, and something happening to the DOM as a result), you will be in a really, really good place entering Hack Reactor, and should have no problem with the interview because you'll learn so much through building the project. 

The callback struggle...

Question: I am having the same issues with understanding callbacks as it look like you were when applying. I applied to MakerSquare and got the same " you're so close" email as you and am supposed to interview again in two weeks. Would you be willing to or know someone who could talk to me about callbacks at some point? I'd really appreciate it!!!

Answer

If you are struggling with callbacks, you are not alone. This is one of the most common questions I get. I recommend looking for JavaScript meetups (Google "javascript meetups") in your area to find other developers who you can talk to. Keep looking until you find just at least one actual, living, breathing human being who has an interest in teaching (or just likes helping aspiring engineers). Buy that person food and/or coffee and ask for an hour of their time. 

If you live in the middle of nowhere and/or are not physically able to go to events like this, then it's going to be harder for you unless you're willing to commit to self-directed learning and don't give up easily. If you aren't getting anywhere after a few weeks and you've done the related section in Eloquent JavaScript and JavaScriptisSexy, then you could try hiring an online tutor through a service like eLance.

And if you can't hire anybody, my best advice is to get to know the Google Developer Tools console because it is every JS developer's BFF. Practice writing and calling simple callback functions, and track what happens at every step of the program using Dev Tools. I find that making callbacks explicit (i.e. actually seeing what value is getting passed to what function at what time) can really help demystify the concepts. And, bonus, Google Dev Tools is something you will use throughout your time at Hack Reactor (and as an engineer), so your time familiarizing yourself with it is going to pay off no matter what. 

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.

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 41 of Hack Reactor: Hiring Assessment and Solo Week

The last 6 weeks have flown by like... um... a fly. Or a bee! Or other such creature that flies by really fast. 

As of tomorrow, we are in Solo Week, which is the week in between the "Junior" and "Senior" parts of the program. This is very exciting because it means we're working on our group projects from here on out, and it feels very rewarding to be able to build real full stack apps from scratch.

Hack Reactor has a big exam called the Hiring Day Assessment that we took yesterday. It's a comprehensive set of tasks that you have to complete in order to show mastery of the subject material from weeks 1-6. If you don't pass, then you don't get to participate in Hiring Day at the end of the program, and you also don't get to call yourself a "graduate" of Hack Reactor (and therefore don't have alumni status afterwards). So yeah. It was kind of stressful.

For me, the test was useful because it helped reveal where I feel comfortable vs. where I need to improve. Some of the tasks felt very natural -- almost automatic -- to me, which was unfathomable 6 weeks ago. I guess programming for 12-16 hours a day for 41 days straight will do that to you.

Other tasks felt like a slog, though I never felt hopeless at any point (this is a profound attitudinal change from where I was even a month ago). I didn't have time to get everything working, but I was able to form a plan and describe my logic, so later on I can revisit those tasks and find solutions.

I'm not sure if I passed or not (we find out next week). If I don't pass, it won't be because I didn't work hard enough over the last 6 weeks, which to me constitutes a success no matter what happens. It also won't be because any task was "too hard" for me, just that I couldn't complete a working solution in the time allotted. There's a huge difference between those two states. 

Anyway, I'm just excited to focus on learning more and building cool things in the next 7 weeks! 

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):

Stuff I'm Bad At: The Art of Abstraction

"Learning is any change in a system that produces a more or less permanent change in its capacity for adapting to its environment."

-- Herbert Simon 

 

Usually, I write about things that I'm comfortable with, and maybe even reasonably good at doing. Because a blog called "Stuff I'm Bad At" would be full of parallel parking, deciding how much food to order, and writing thank you notes on time. Who wants to read that? 

But today, I'm going to talk about an immense learning challenge I have, and it's going to be way more interesting than anything else I could write about. My problem lies in the task of abstraction. Specifically, I have trouble abstracting away from the internals of the "black box" of what a program is doing without mixing it in with the interface (what the user or, in our case, programmer, sees). This applies both to understanding and writing code, and it is the biggest hurdle I face on my path towards becoming a software engineer.


"Wonderful, but not incomprehensible."

 

What I love about programming is that it can explain and generate wonder, all at the same time. As Herbert Simon writes in The Sciences of the Artificial:

For when we have explained the wonderful, unmasked the hidden pattern, a new wonder arises at how complexity was woven out of simplicity.

The idea of unmasking simplicity is very much connected with the concept of abstraction, which I refer to in the context of programming as the practice of concealing unnecessary or irrelevant details of a program, and surfacing only its essential features. A programmer who is able to abstract her way around a seemingly complex system and grab ahold of only the relevant details of that system to apply to her particular task has potentially endless power. For me, learning how to do this is akin to discovering a new natural law. 

Programmers rely on abstraction to build clean and intuitive interfaces that allow others to interact with their programs. An interface, broadly speaking, is the meeting point between an inner and outer environment.

For example, imagine you have a mug (hopefully you don't have to imagine too hard because mugs are pretty awesome). Your mug is made of a solid material, has a capacity of 16 fluid ounces, and has a handle -- these qualities serve as affordances that guide you to the mug's proper use: to hold liquid and physically maneuver that liquid with one hand. The mug is your interface to drinking coffee, tea or other beverage. In order to understand the mug's intended task, you don't need to know how the mug was constructed, or whether it's ceramic or porcelain or glass. You just need to know that it's a mug. 

Applying this model to a code example, consider Underscore's function signature for the array method _.indexOf:

_.indexOf(array, value, [isSorted]) Returns the index at which value can be found in the array, or -1 if value is not present in the array.

  _.indexOf([1, 2, 3], 2);
  => 1
  

Just like how anyone can pick up a mug and know what it's for, a programmer should be able to read the _.indexOf function signature (the interface) and quickly grasp the essential features of the function it represents, without needing to "go to the mug factory" by diving into the code that comprises the function line by line.

And just like how a mug is designed to present its most obvious use to the external world (the outer environment), so too must a programmer take care to design an interface with clarity and precision; by naming functions and inputs appropriately, for example. This helps account for weirdos like you and me who otherwise might try to use their program in some way it was never designed for.

So, what happens when we breach the mug factory and go "under the hood" of _.indexOf?

From the Underscore documentation:

_.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);

That doesn't look so bad, right? As it turns out, _.indexOf is simply an invocation of a generator function, createIndexFinder, which takes in 3 parameters. Let's find that helper function...

function createIndexFinder(dir, predicateFind, sortedIndex) {
  return function(array, item, idx) {
    var i = 0, length = getLength(array);
    if (typeof idx == 'number') {
      if (dir > 0) {
          i = idx >= 0 ? idx : Math.max(idx + length, i);
      } else {
          length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
      }
    } else if (sortedIndex && idx && length) {
      idx = sortedIndex(array, item);
      return array[idx] === item ? idx : -1;
    }
    if (item !== item) {
      idx = predicateFind(slice.call(array, i, length), _.isNaN);
      return idx >= 0 ? idx + i : -1;
    }
    for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
      if (array[idx] === item) return idx;
    }
    return -1;
  };      
}

Welcome to the mug factory! At this point, you've likely forgotten why you're even here. I have, and I'm writing this thing.

My challenge is to avoid taking unnecessary tours of mug factories, while also building my own super awesome mug factories. I'm making good progress on the first part of the task: it takes some discipline, but I've definitely become more sensitive to internal and external flags telling me when I don't need to know the internals of some piece of code, and it's OK to move on. 

What's much, much harder for me is building the mugs and the mug factories, or programming both the interface and the "black box" code that you shouldn't worry about.

It's a super weird sensation to know that you're writing code that a future version of yourself will deliberately ignore, and at the same time having to remain cognizant of how Future You and other programmers will interact with the interface to that code. Coding becomes something of an out-of-body experience.

For me, the real problem is that I've never been particularly good at thinking in abstract terms. My mind jumps into details and keeps digging until every possible nugget is unearthed. This impacts how I reason about a program because I can easily lose sight of what the hell it is I'm supposed to be returning.  

In other news, I've learned that I have far less mathematical intuition than I previously assumed. Apparently being able to do basic math in your head really fast doesn't actually make you a mathematical thinker.


"The best thing that can happen to a human being is to find a problem, fall in love with that problem, and live trying to solve that problem, unless another problem even more lovable appears."

-- Karl Popper 

 

I am in love with my problem. I'm positively obsessed with it. Who could wish for a better, more lovable problem? We all should be so lucky to be made aware of any deficiencies impeding us from doing our best work. Otherwise, we would never know to improve!

After sharing my situation with a number of people who I respect and admire, I've put together a few strategies to help address this challenge:  

  1. Draw pictures. I've found that mapping out a problem on paper helps me tremendously, which makes sense since the very act of drawing something to represent something else is a method of abstraction. 
  2. Write your test suite first. As the maybe 3 readers of this blog know, I'm a big fan of test suites. By keeping your eye on the prize, you're less likely to go astray. At the very least, always know what a function or a program is expected to return to the person who calls it. Write it down in a comment at the top of your code if you need to.  
  3. Stay vigilant. I spend a good portion of my day wrestling with myself to stop thinking so much like myself, and imagining what it's like to think in this totally different way. It's a little exhausting. Eventually, it will become less so (I hope). 
  4. Find examples. When I witness a classmate making a cognitive leap, I'll ask how they got from Point A to Point B. I find it super interesting to hear how others visualize and reason about problems, and I hope that I'll eventually get to a similar level of intuitive cognition. 
  5. Have empathy. This particular strategy is fairly easy for me to enforce. It feels very natural for me to imagine how someone else would feel in one situation or another, and this will help me build better interfaces that account for a variety of potential users. 

If you have other strategies to share, please do so in the comments! 

 

 

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.

Google I/O, Android Nanodegree, and Not Doing Homework on Time

Oh my gosh. You guys. I know. I have been really really bad about blogging of late, but I have a good excuse! Which is, um, just lots of work! I have been a busy little bee.

Google I/O 

We launched the Android Developer Nanodegree at Google I/O on Thursday! Or, more specifically, Sundar Pichai announced it at the Keynote, and I launched it from my kitchen table, in my pajamas and rocking a scrunchie (according to the lady who cuts my hair, I have a lot of breakage, so I've taken to wearing scrunchies to bed).

 Photo:  Techcrunch

Photo: Techcrunch

This was my second I/O, and it was definitely more chaotic than last year. First of all, Udacity and Google had a Developer Training booth this year, where we gave out these phone battery charger thingies in exchange for downloading the Udacity app and signing up for one of our free Google courses. Holy crap. People really wanted those phone charger thingies. They went like hot cakes, if those hot cakes also charged your phone. On Day 2, we ran out and gave away Udacity sunglasses instead. These were markedly less desirable than phone charger thingies. Here is an actual conversation I had with multiple people about the sunglasses:

  • Patron: What are those?
  • Me: Sunglasses. 
  • Patron: OK. But are they 3D? VR? 
  • Me: Um, no, notsomuch. 
  • Patron: (visibly confused) What do they do?
  • Me: Oh! Well! They block 100 percent of UV rays from your eyeball area. Also, there's this nifty Udacity logo on the side... (voice trails off as patron wanders away, distracted by a cardboard box that transports them to outer space) 

I did, at one point, attempt to model the sunglasses. This resulted in one person handing them back to me. Whatever. I am an excellent Booth Human, no matter what people say. 

Also adding to the chaos, the prevailing interior theme of I/O this year seemed to be "low to the ground" because the entire venue was full of bean bag/pouf cushion seats. I think this was supposed to give everything a relaxed, chill vibe. Anyway, it really reminded me of this:

 Lounging on dog beds = the new hotness

Lounging on dog beds = the new hotness

At one point, I legit tripped over Sebastian, Udacity's CEO, while en route to get sour apple gummy rings (they were running low, and I panicked). Sebastian, to his credit, does not care in the slightest about getting tripped over, and we went through the slides for his I/O session on democratizing education, which ended up going very well. 

Android Nanodegree 

So this is what I've spent the last 6 months working on. Our team made a whole slate of world-class educational courses with Google, and all these courses are now available to anyone with an internet connection, for free. The Nanodegree is the credential, and that costs money, but the content, itself, is free (and always will be). Weirdly, there are a lot of MOOC haters out there, and I don't really understand what MOOCs ever did to these people besides have a seriously unfortunate acronym, but even the worst hater can't be opposed to bringing free programming courses online, right? 

Trailer video for the Android Developer Nanodegree (Production Credit: Calvin Hu) 

Not Doing Homework on Time

I cleared the soft deadline for Hack Reactor's Section 1 homework, but did not make Section 2 (it's tonight). The hard deadline is at the end of the week, and I'm feeling good about making that one. It's unnerving how quickly time is flying by. My cohort starts in 4 weeks! 

What I'm working on this week: Learning jQuery, implementing a front end, and re-implementing a few advanced Underscore functions. 

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.

Using Sublime Text for note-taking

We got our pre-course homework from Hack Reactor yesterday! Very exciting. Lots to learn and do. I'm not allowed to share details of the assignments, but can talk generally about my plan to get all of it done.

First, I'm reading up on the documentation they've provided and taking notes. I'm a copious note-taker, and find that it really helps me retain and organize information. I'd like to use Sublime for this, but it's not immediately obvious how to use it for notes in Markdown. 

Enter this blog post, which is tremendously helpful. Less than 15 minutes later, I have Sublime hooked up with Markdown editing and preview, and I'm ready to get started! For my first chunk of work, I have ~300 slides to get through. My goal is to get through 50/day. For me that means I 100 percent understand what's on the slide, and have taken good notes documenting key points, and my thought process for any sample exercises.  

Goals for this week

Last week, my goals were to finish this Treehouse course and to wrap up my Random Number Generator. I managed to do both of these things, but still have some final tasks to complete before I'm satisfied. 

For my RBN, I need to input a conditional so that users can't submit invalid inputs after they submit the same integer values twice. I'll get to this when I'm ready. It shouldn't take too long, but I finally understand why engineers lose so much steam when context switching! 

For the Treehouse course, I finished my project, but need a lot more practice building websites before I feel like I'm making coherent choices. 

This week, my goal is to build a new website. Any website. I'm planning for a light week because this is my last week of study before I get my Hack Reactor homework, and I'd like to knock out some major work projects as well. 

First ever mailbag post!

Big milestone, you guys. I got TWO questions since setting up my contact page last week. This necessitates (drumroll) a mailbag post! 

Question from a reader on learning callbacks:

Thanks so much for detailing your thoughts and preparation!

How did you further practice callback functions? I have my interview with HR in a week and I feel I still need some practice with them.

Thanks!

My response:

I found that the most useful references for callbacks were the Udacity course that Marcus (cofounder of HR) teaches (he does a good job explaining how the compiler runs through code), and this book.

The best way to practice is to find someone (if you are at university, this should definitely be doable) who can sit down with you while you code, and give you guidance and feedback. At least, that's what worked best for me.

I sat down with a friend and worked through writing the reduce function, using the each function as a callback. That is when I finally understood what I was doing.

For studying the underscore functions (reduce, each, map, etc) in particular, I found that lodash (a superset of underscore) has a more intuitive way of writing the code. You can see how they implemented collection functions like each and reduce by browsing their documentation, or just by opening up the console while on the lodash site and running console.log(_.reduce);

Good luck and don't give up. If this is something you really want to do, you will be able to make it happen.

Best, JK

Question on finding a mentor online:

I was wondering about how would one go about finding a good mentor if they don't live in a city where tech is a big deal. Since I doubt any senior person in the Baton Rouge, LA area is hugely into the web(python especially) I know I would have to find a mentor online, but how?

My response:

It is very hard to find a mentorship from scratch, I agree. Instead, I would look for meetups (meetup.com) in your area, or, if you're able to travel a bit, in the nearest major city.

Then go for a smaller goal of just finding a study buddy who is more of a peer vs. a senior dev.

Ultimately, I think a study buddy is more useful than a mentor when you're starting out in programming (if that is indeed the case for you). You can learn from people you admire online by following their blogs, tweets, LinkedIn articles, and Github activity. But when you're starting out, nothing beats having someone to slog through problems together, and to help keep you accountable.

If you are looking for more structure, Udacity has a Nanodegree program that you might be interested in. It is $$ though ($200/mo). They do provide Coaches and a private community forum for support, so it kind of gives you that mentorship feeling. They also give you code review and feedback on projects, and that can be really helpful when you're learning. [Full disclosure: I work for Udacity, but I do not benefit financially from new sign-ups or anything like that.]

Best, JK


Where has this week gone?!

How is it Thursday already? Here's what I've been up to:

  • Trying to get a dev environment set up on my machine for work. This sucked up many many many hours of time! Eventually I gave up, BUT I did practice a lot of command line in the process. So not a total loss. 
  • Redoing the random number generator to handle edge cases like when a user inputs 5.4, and 6, and the generator returns 5, which was not in their set range. What I want to happen is for the generator to accept 5.4 from the user, and then round it up to 6 when it sets the min and max values. This would set both the min and max values to 6, so the generator would only return 6. For a pairing like (5.4, 7), the generator would return 6 or 7. 
  • Building regular expressions. I've been testing on regexr
  • Putting out various work-related fires! 

Basically, it's been a very hectic week, and I expect the frenetic pace to continue up until Google I/O. I'm not sure if I'm going this year, but it's a big event for us and we're doing lots of cool stuff to prepare for it. 

At this rate, I'm a tiny bit concerned about how I'm going to keep up with Hack Reactor's pre-coursework, which they're releasing to our cohort later this month. If you don't complete it, you get kicked out of the program. So... I'm going to have to find time wherever/however I can.