Lesson Tuesday

Now that we've explored behavior-driven development, let's walk through creating an application using the behavior-driven development process together. Taking time to learn how to identify and code individual behaviors now, while our projects are still relatively small, will make tackling larger, more complex projects in the future much easier.

Separation of Logic

A brief reminder: As discussed previously, new programmers often mistakenly combine business (back-end) and user interface (front-end) logics . User interface logic includes code that handles event listening, user input, and DOM manipulation. Business (back-end) logic evaluates and manages data. Business logic may be called by user interface (front-end) logic but they should otherwise be two very separate areas of our code.

As our projects continually grow in size and complexity, continue writing clean, professional code by keeping these two logics separated. If necessary, review the Business and User Interface Logic lesson from last week.

Application Overview

In the next two lessons we will write a program that takes a year and returns whether that year was (or will be) a leap year. Let's briefly go over what this application will look like:

Business Logic

The business logic (back-end) will evaluate whether the value provided is a leap year and will return true or false accordingly. Remember, business logic does not care how it is used and can operate independently of any user interaction. It happens in the 'back-end' or 'behind the scenes'.

User Interface Logic

The user interface (front-end) logic will collect input from the user, call our business logic function, and display the results from the business logic on the web page. Remember, the user interface logic does not care how the business logic works. All the user interface logic must know is that there is a leapYear() function it may call.

Behavior Driven Development Process

Now, let's walk through how we would code this application using the principles of behavior-driven development:

Identifying Behaviors (also known as "Specifications")

The first step in behavior-driven development is to identify small, individual behaviors the program should demonstrate. You don't have to think of all of them at the beginning. It's entirely alright to add to your list of behaviors/specs/specifications as you think of additional behaviours.

Also, always begin with the simplest possible behavior. In the previous lesson we created a table of specs, or behavior examples, including input and output examples that demonstrate what each behavior should look like in action:

Leap Year Input-Output Grid

Note: Know that your own specs aren't required to be in a table. In the Intro to Programming class here at Epicodus, we will place specs in our project's README.md file. A simple list of behaviors with an input/output example for each is just fine.

Writing Tests

The next step in BDD is to translate your first "plain English" spec into a coded spec, using tools specifically designed for this purpose. Here at Epicodus you will learn how to code automated tests in your level 2 course. Until then we will test our applications manually by inserting our example input into the application and double-checking that we receive the correct output.

To test manually, we'll first need to build a basic front-end that includes a form to submit values. Later on when we have the ability to write codedtests, we will not build the user interface until the business logic is complete and passes all tests.

Writing Code

Let's create a project directory called leap-year and initialize a git repository within it to track our changes. We'll add a README with details about our project, and our list of plain English specs. We'll also add js and css folders.

HTML

First, we'll construct a basic web page where we may enter sample input into our program.

Our HTML page needs a link to the jQuery library, a link to our scripts.js file, a form to collect input, and a div to display the program's output. We'll also include some Bootstrap:

leap-year.html
<!DOCTYPE html>
<html>
  <head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.12.0.js"></script>
    <script src="js/scripts.js"></script>
    <title>Leap year detector</title>
  </head>
  <body>
    <div class="container">
      <h1>Leap year detector</h1>

      <form id="leap-year">
        <div class="form-group">
          <label for="year">Enter a year and find out if it's a leap year:</label>
          <input id="year" type="text">
        </div>

        <button type="submit" class="btn">Find out!</button>
      </form>

      <div id="result">

      </div>
    </div>
  </body>
</html>

User Interface Logic

Next, we'll need jQuery user interface logic to retrieve input from the form, and call our business logic's leapYear() function (which we will write momentarily). It will also be responsible for displaying results our business logic returns:

js/scripts.js
$(document).ready(function() {
  $("form#leap-year").submit(function(event) {
    event.preventDefault();
    var year = parseInt($("input#year").val());
    var result = leapYear(year);
    $("#result").text(result);
  });
});

In the code above we attach a submit listener to our form. When the form is submitted, we assign the value from our form input to the variable, year.

Then, we call a leapYear() function (which we will write momentarily), pass it the year variable as an argument, and assign the return value (which will be true or false) to the variable result. Even though we haven't written the leapYear() function yet, we already know from our specs that it must take a number and return true or false. This is yet another benefit to identifying and listing out anticipated behaviors before we begin coding.

Continuing with the code above, we also display the returned boolean value (currently assigned to the variable result) on the web page with the line $("#result").text(result);.

Business Logic

To start coding our business logic using the behavior-driven development process, we'll take our plain English specifications (also known as "specs" or "behavior examples") and implement code that does each of these behaviors. We always want to begin with the simplest possible example that requires the least amount of code to implement, and focus on only one behavior at a time.

Leap Year Input-Output Grid

Hint: Often if we have a number of conditions that will be evaluated, the first behavior is what will ultimately be the else statement when none of the conditions are true. In our leap year application, the first behavior is returning false for a year that is NOT a leap year, which means it is not divisible by 4, 100 or 400.

Now, in our scripts.js file, we will add the least amount of code to implement the first behavior on our list:

js/scripts.js
var leapYear = function(year) {
  return false;
};

// jQuery user interface logic here.

Does the code above seem odd? We haven't even checked to see if the year is a leap year, we simply return false no matter what. But remember, we're only writing just enough code to make our one, singular, most simple behavior pass. If we began checking what the number was divisible by, we'd actually be getting ahead of ourselves!

This may feel like overkill for such a small program, but if you develop good BDD habits that allow you to identify simple, isolated behaviors now, you'll be able to tackle much more complex problems with much more ease and organization in the future. Remember, one behavior at a time, even if that behavior is very, very simple.

Testing our Specs

Now that we've isolated the most simple behavior possible, and written just enough code to make that one single behavior present in our application, let's manually test it out!

Remember, the first specification we are testing is that the application returns false for a year that is not a leap year. Our example input was 1993, and our anticipated output was false. Let's launch our page in the browser and see what happens!

We can enter 1993 into our form and submit....

leap-year-first-spec-passing

And look, our program is returning false, which is the exact behavior we outlined in our first specification. Our first spec passes!

Let's commit. When following the BDD process you should commit after each passing spec.

Repeat!

Now that our first spec passes when tested manually, we simply move onto the next spec and repeat the process!

Our next behavior details that our program should return true for any year divisible by 4, since that makes it a leap year. Although we know that years divisible by 100 and 400 will also need to be considered, we must focus on one spec at a time. Therefore, we are only going to add code to check whether the provided year is divisible by 4. We'll get to the rest later.

Again, we'll add just enough code to make this second specification pass. In this case, we can just add a simple conditional:

js/scripts.js
var leapYear = function(year) {
  if (year % 4 === 0) {
    return true;
  } else {
    return false;
  }
};

// jQuery user interface logic here.

Now, let's manually test this behavior too. Referring back to our list of specs, the example input for this second specification was 2004, and we anticipated the output true.

And look! If we refresh our application and submit the year 2004, we receive 'true':

second-spec-passing

Again, we will commit after this additional passing spec.

Time to tackle our next specification: We decided that our application should return false when the provided year is divisible by 100, because that means it is not a leap year. We'll add the smallest amount of code to create this behavior:

js/scripts.js
var leapYear = function(year) {
  if (year % 100 === 0) {
    return false;
  } else if (year % 4 === 0) {
    return true;
  } else {
    return false;
  }
};

// jQuery user interface logic here.

And, we can refresh the application and manually test this behavior. Our example input was 1900, and we expected to receive the output false.

third-spec-passing

And look, it works! Let's commit again.

Refactoring

As you work through your specs, implementing each individual behavior one-by-one, you may find your code becoming a tiny bit redundant. That's okay! Pausing to refactor along the way is entirely alright in the BDD process. In fact, it's encouraged!

Can we refactor our application's business logic to make it efficient or easy to read? We currently have two different places returning false. Let's refactor our code so that a single evaluation may check whether the year is divisible by 4 or 100. We'll change our 100 condition to use the not operator ! so it also returns true.

js/scripts.js
var leapYear = function(year) {
  if ((year % 4 === 0) && (year % 100 !== 0)) {
    return true;
  } else {
    return false;
  }
};

// jQuery user interface logic here.

Great! We'll commit one more time.

Implementing Additional Behaviors

We have one last spec on our current list. Our program should return true for years divisible by 400, since that means they are a leap year. You guessed it, we'll add just enough code to add this functionality to our application, therefore making this last spec "pass":

js/scripts.js
var leapYear = function(year) {
  if ((year % 4 === 0) && (year % 100 !== 0) || (year % 400 === 0)) {
    return true;
  } else {
    return false;
  }
};

// jQuery user interface logic here.

Our example input for this spec was 2000, and we expected our application to return true, since 2000 was a leap year. Let's test it out:

fourth-spec-passing

Perfect! We've successfully coded all behaviors outlined by our list of specifications. We know each spec passes, because we received our intended outputs for each individual input.

In the next lesson we'll add additional user interface logic to our leap year application.

For an overview of the series of steps in the BDD process, check out the cheat sheet tab of this lesson.

Terminology


  • Business logic: The code responsible for handling the evaluation and manipulation of data; does not require any user interface.

  • User interface logic: The code responsible for the interaction between the user and the application; handles tasks such as event listening, user input forms, DOM manipulation, display and styling.

Behavior-Driven Development Process


1. Identify Specifications/Behaviors

Identify the behaviors your program should exhibit. Include example input and output that would demonstrate this behavior is working.

Make sure each behavior truly is a single behavior. In the leap year example, checking that the number is divisible by 400 and checking if the number is divisible by 4 are two seperate ways to check for a leap year, and are therefore two separate behaviors, even though they both result in the program returning true.

2. Code the Behaviors

Beginning with the simplest possible behavior, add the least amount of code to integrate this behavior into the application.

3. Test

In level 2 courses, you will write automated tests to check your code. In Intro to Programming we will test manually. Enter the example input that corresponds to your first specification. Check to see if you receive the example output.

If not, it's evident that the behavior is not functioning as expected, and you'll need to revisit your code.

4. Commit

If you do receive the correct output, your spec passes! Each time a new test passes, you'll want to commit your work.

5. Repeat!

Repeat this same process for each specification. Begin with the simplest possible spec, and work your way up in complexity.

Refactor

Whenever necessary, refactor between specifications. Just ensure your previously passing specs still pass after refactoring.

Code Samples


leap-year.html
<!DOCTYPE html>
<html>
  <head>
    <link href="css/bootstrap.css" rel="stylesheet" type="text/css">
    <link href="css/styles.css" rel="stylesheet" type="text/css">
    <script src="js/jquery-1.12.0.js"></script>
    <script src="js/scripts.js"></script>
    <title>Leap year detector</title>
  </head>
  <body>
    <div class="container">
      <h1>Leap year detector</h1>

      <form id="leap-year">
        <div class="form-group">
          <label for="year">Enter a year and find out if it's a leap year:</label>
          <input id="year" type="text">
        </div>

        <button type="submit" class="btn">Find out!</button>
      </form>

      <div id="result">

      </div>
    </div>
  </body>
</html>
js/scripts.js
var leapYear = function(year) {
  if ((year % 4 === 0) && (year % 100 !== 0) || (year % 400 === 0)) {
    return true;
  } else {
    return false;
  }
};

$(document).ready(function() {
  $("form#leap-year").submit(function(event) {
    event.preventDefault();
    var year = parseInt($("input#year").val());
    var result = leapYear(year);
    $("#result").text(result);
  });
});