Skip to main content

Pomodoro, deconstructed

As I said in the last post, I'd like to revisit some of the coding challenges on freeCodeCamp, and specificially, the Pomodoro timer. First, though, there isn't really a clear three-sentence description of the thing, so let's start there.

Wikipedia says:

The Pomodoro Technique is a time management method developed by Francesco Cirillo in the late 1980s.[1] The technique uses a timer to break down work into intervals, traditionally 25 minutes in length, separated by short breaks. These intervals are named pomodoros, the plural in English of the Italian word pomodoro (tomato), after the tomato-shaped kitchen timer that Cirillo used as a university student.

So often, folks addressing these challenges will build a mockup in HTML (often called a wireframe), then simply start wiring the bits together. And doing that works, at least in principle: the first half of the assertion tests that freeCodeCamp uses are checking that given elements, with given ID's, are available. So wireframing works, build the page, then wire the buttons and inputs to do something.

But here's my issue: while it may look right, it is decidedly not. If the purpose of going through an online course is to eventually land a job, then think from that perspective: if a prospective employer were to see the actual code driving that page, would they hire the person who wrote it, or would they throw her out on her ear?

Don't be that coder. Learn elegant coding.

How does that start?

First, step away from the computer. Grab a pad. We have an idea, let's sketch it out. Rather than build a big Pomodoro timer, let's start small. Break it down to parts:

First, we need to have a way to increment/decrement a displayed value, both for sessions and breaks. Rather than write the same code, can we build something that we can re-use for this? You betcha!

Second, maybe a timer. Definitely a timer. Yup. So let's start there!

Timing is everything

Timing, in javascript, happens with setTimeout()/clearTimeout() or setInterval()/clearInterval(). The first pair causes (or stops) something happening after a given interval, the second causes (or stops) something to recur over and over at that same interval. Here's a simple example:

    // First, let's create a variable that will be our countdown
    var countdown = 10,
        // Then we'll create a timer. This is a simple call to setInterval,
        //  which will loop repeatedly, every 1000 ms (one second) until our
        //  if() condition is met.
      myTimer = setInterval(function() {
        // Count down!
        countdown -= 1;
        // Have we hit zero?
        if (countdown > 0) {
          // Nope -- do something.
          console.log(countdown + "...");
        } else {
          // Yep -- stop the timer and do something different!
          clearInterval(myTimer);
          console.info("Hello World!");
        }
      }, 1000);

The above code creates a loop that runs about every second, decrements the value of countDown, and does something at a given point. Simple, easy, does what we tell it. And for the purposes of our Pomodoro, totally useless. BUT...What if we were to create a Timer class, something that would be flexible, something we could interact with? That sounds like a plan, let's do that!

Giving our Timer class

With ES6, it's a simple process to create classes:

class Timer { ... }

That will do it. Just that. Of course, we want to add a constructor in there, so when we call new Timer() something actually happens.


class Timer{
  constructor(){
    this._countdown = 10;
    this._timer = setInterval(function(){... }, 1000);
  }
}
let myTimer = new Timer()

Notice, within the constructor, we can set properties directly on the class using the this keyword. For example, this._countdown creates a property on our new Timer. this._timer does the same thing. But, before things get confusing, we really need to understand this.

When we create variables, they get created within a context. There is a global context, which would be the window for a web page. Everything can mess with global context. Within our Timer, we have a "local" context. All properties and variables created within the timer are available within the timer. Using this, we can limit our property to the local context.

But here's where it gets dicey: within the setInterval(...), we need to create a callback function that gets run every second. Within that function, what is the context of this? It is the setInterval itself, which creates a Timeout object. Not what we want. What to do? As it happens, ES6 gives us the answer: FAT ARROWS!

The fat arrow function looks like this:

() =>  {...}

which reads the same as

function() {...}

But it does things a little differently. Within the fat arrow function, we are still in the original context. What that means for us is , we can access properties of our Timer object without creating weird temporary variables or something. So we can do something like this:


class Timer{
  constructor(){
    this._countdown = 10;
    this._timer =setInterval(()=>{
      console.log(this);
      // Count down!
      this._countdown -= 1;
      // Have we hit zero?
      if (this._countdown > 0) {
        // Nope -- do something.
        console.log(this._countdown + "...");
      } else {
        // Yep -- stop the timer and do something different!
        clearInterval(this._timer);
        console.info("Hello World!");
      }
    }, 1000);
  }
}
let myTimer = new Timer()

Here's the same code, running live:

Comments

Popular posts from this blog

Quantity vs Quality in Javascript

I have been working on a number of the coding challenges over on freeCodeCamp , and they are great -- a good mix of front-end HTML, javascript, libraries, back-end tech. It is good stuff, and very comprehensive. Hundreds of lessons, and challenges in each area, a great support forum, hints if you need... all sorts of fun. And very conducive to questionable coding. I remember when jQuery first appeared on the scene. John had a very clear vision in mind as to its purpose and place: an easier, unified way of communicating and interacting with the DOM. And it was good. But many folks who had never had the opportunity or desire to get into web programming discovered in this an easy way to do a LOT of cool things. Novice or advanced, we were using this great, lightweight, exciting new library to add all kinds of bells and whistles to web pages. Wireframes and prototypes were being cobbled together quickly, because we COULD. There may have been some spaghetti code happening in th...