Lesson 35. Managing in production

Your application is finally online, and you want to ensure that it stays there, fully functional. In this lesson, I discuss ways of getting data into your application even before any forms are used. You may want to add some of the course data you used in development so that your application has a fresh start online with data to view. Adding course data to your live application will reduce the time it takes to make the pages of your site presentable. Then I discuss some ways to improve your code quality and make sure that you don’t make mistakes that could cause your application to crash in production. Last, I talk about ways to log, debug, and monitor your application in production to help you investigate when things begin to break.

This lesson covers

  • Loading seed data into your production application
  • Setting up linting for you code
  • Debugging your application
Consider this

Your application is finally online, and it’s a proud moment, except that your client quickly discovers bugs that went undetected in development. What protocol do you follow to fix your code locally and upload to production?

In this lesson, you learn how to maintain your application in production with a few tools.

35.1. Loading seed data

In lesson 34, you got your database set up, but you may be wondering whether there’s a simple way to populate your production application with data. You can upload data into your application on Heroku in a few ways.

Seed data is the database records you feed into your application when you first set it up in a new environment. Other languages and platforms have conventions for loading a file with seed data in different environments. In Node.js, you can create a JavaScript file containing the data you’d like to load. You may want to populate your application with recipe courses before any users even sign up, for example. To do so, you can use an existing seed file or create a new file in your application directory called seed.js. This file defines and creates new records that communicate with your Mongoose plugin. For that reason, you need to require Mongoose and the models you intend to use, as shown in listing 35.1.

To avoid conflict with a preexisting seed file, create courseSeed.js. In this example, you include the necessary modules needed for creating new data objects with Mongoose. Then you create multiple records with values that you’d like to see in your production application. When this file contains the data that you want to use, run the code in this file, using the Heroku command-line interface (CLI).

Listing 35.1. Adding content through seed data in courseSeed.js
const mongoose = require("mongoose"),
  Course = require("./models/course");                 1

mongoose.Promise = global.Promise;
mongoose.connect(
  process.env.MONGODB_URI || "mongodb://localhost:27017/recipe_db",
  { useNewUrlParser: true }
);
Course.remove({})                                      2
  .then(() => {                                        3
    return Course.create({
      title: "Beets sitting at home",
      description: "Seasonal beets from the guy down
the street.",
      zipCode: 12323,
      items: ["beets"]
    });
  })
  .then(course => console.log(course.title))
  .then(() => {
    return Course.create({
      title: "Barley even listening",
      description: "Organic wheats and barleys for bread,
soup, and fun!",
      zipCode: 20325,
      items: ["barley", "rye", "wheat"]
    });
  })
  .then(course => console.log(course.title))
  .then(() => {
    return Course.create({
      title: "Peaching to the choir",
      description: "Get fresh peaches from the local farm.",
      zipCode: 10065,
      items: ["peaches", "plums"]
    });
  })
  .then(course => console.log(course.title))
  .catch(error => console.log(error.message))
  .then(() => {
    console.log("DONE");
    mongoose.connection.close();
});

  • 1 Require models for seeding data.
  • 2 Remove all existing documents.
  • 3 Run code to create new database documents.
Tip

As an alternative, you could use the mLab URL to load seed data directly into your production database. Although this approach is quick, I don’t recommend it because it exposes your production database to security risks.

Two other alternatives are using Heroku CLI tools to launch your production application’s REPL or terminal environment. You may recall that REPL has access to the files and folders in your projects directory, so it’s a great way to insert data from terminal. Launch REPL by running the command heroku run node in your project’s terminal window. With this REPL-like environment for your production application, you can simply copy and paste the contents of courseSeed.js into terminal. The other approach is to run heroku run bash in your project’s terminal window. This command brings up a prompt where you can run node courseSeed to load all the contents directly. First, you’ll need to commit your courseSeed.js file to git and push to heroku.

If you’re successful, you should see the log outputs of each course created, which also appear immediately on the /courses route in your application online (figure 35.1).

Figure 35.1. Display of the populated courses page

Note

To upload new changes to your project, run git add . followed by git commit -m “some commit message” and git push heroku master.

In the next section, I discuss ways to maintain the integrity of your code and ensure that new errors don’t pop up.

Quick check 35.1

Q1:

What happens when you run heroku run node?

QC 35.1 answer

1:

heroku run node opens a new REPL window for you within the context of your production application. From there, you can run JavaScript commands and load application-specific modules as you would locally, with access to your production database.

 

35.2. Linting

Bugs and coding mistakes are part of the development process. What can you do to prevent the inevitable mistakes that halt production? Along with code quality, the process of linting to hold your code to a particular standard is a way to reduce errors. Linting involves running a program to read through your code and notify you of bugs or errors that you may not have caught. You also might miss (and some browsers might ignore) syntax errors during development that could break your application in a different environment. To lint your code, globally install a package called eslint by running npm install -g eslint. ESLint is an open-source tool used in terminal to run static analysis on your code. Through this analysis, you can identify code style and structure problems. Other linting libraries that you can use include JSLint and JSHint. You can learn more about ESLint at https://eslint.org/.

Note

You could also install the package for this project by running npm install eslint --save-dev within your project directory in terminal. The --save-dev flag signifies that this package doesn’t need to be installed in your production environment; it will be marked that way in your application’s package.json. To use eslint after installing it as a development dependency, you need to access it from ./node_modules/.bin/eslint.

As you initialized a new package.json file with npm init, initialize a .eslintrc.js file by running eslint --init in your project’s terminal window. Choose to set up your file by answering the questions in terminal, as shown in listing 35.2. You need to let the linter know to look for ES6 syntax and methods because you use them throughout your application. You also tell the linter to analyze your code on the server and client because you’ve written JavaScript for both.

Listing 35.2. Setting up your .eslintrc.js file in terminal
? How would you like to configure ESLint? Answer questions about
your style                                                     1
? Are you using ECMAScript 6 features? Yes
? Are you using ES6 modules? Yes
? Where will your code run? Browser, Node
? Do you use CommonJS? No
? Do you use JSX? No
? What style of indentation do you use? Tabs
? What quotes do you use for strings? Double
? What line endings do you use? Unix
? Do you require semicolons? Yes
? What format do you want your config file to be in? JavaScript

  • 1 Answers to questions to set up your linter

Take a look at the .eslintrc.js file that’s produced at the end of this prompt in listing 35.3. Notice that you’re formatting the linter’s configurations in JavaScript, not JSON, like your package.json file. As in your other JavaScript modules, these configurations are assigned to module.exports. Most of the configurations that follow are fairly straightforward. Your environments are specified to include node, web browsers, and ES6 syntax. Then there are eslint rules, which define when to warn you of inconsistencies. In this case, you throw a linter error when spaces are used instead of tabs, semicolons are missing at the end of statements, or single quotation marks are used around text. You can change these configurations to suit your preferences.

Listing 35.3. Example .eslintrc.js configuration file
module.exports = {
  "env": {                     1
    "browser": true,
    "es6": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "sourceType": "module"
  },
  "rules": {                   2
    "indent": [
      "error",
      "tab"
    ],
    "linebreak-style": [
      "error",
      "unix"
    ],
    "quotes": [
      "error",
      "double"
    ],
    "semi": [
      "error",
      "always"
    ]
  }
};

  • 1 Specify the environments to analyze.
  • 2 Define eslint rules.

Test your linter on the main.js file by running eslint main.js. I hope that you don’t see any errors up front. Try deleting a semicolon or defining a variable that you don’t use later. Notice how eslint outputs errors with line numbers so that you can correct your code easily. Clean code helps ensure the integrity and readability of your application.

Note

Keep in mind that some linter rules are stricter than others. The rules are intended to maintain consistency in your code. If you see errors referring to spaces versus tabs, those errors don’t mean that your code is bad—only that it could use a cleanup.

The output of errors in your terminal window details which files and line numbers you need to visit to correct your syntax or code structure.

Quick check 35.2

Q1:

What does .eslintrc.js do?

QC 35.2 answer

1:

Like package.json, .eslintrc.js stores the configuration settings for eslint that you set up in the initialization process in terminal. This file contains rules by which the linter determines whether your code needs to be fixed.

 

35.3. Debugging your application

You looked at a few ways to debug your application earlier in the book. You used console.log to print custom messages, error messages, and request/response-specific data in your Express.js middleware functions. Then you used the logs in your terminal window to determine where to fix certain problems. If an error occurred while saving a user to the database, for example, you caught the error in your promise chain and logged it to the console.

Logging is helpful when it’s used correctly. Logs provide a recorded history of transactions and interaction with your application. Even if your application is running smoothly, you want your development logs to tell you more about the application’s performance, and you want your production logs to inform you of suspicious activity.

Locally, you can get more information about the request-response cycle by starting your application in debug mode. In your project’s terminal window, type the command DEBUG=* node main to set the DEBUG environment variable to logging from all elements of your application as it runs.

Note

On Windows machines, first set the environment variable and then run the application by running the command set DEBUG=* & node main.

You’ll notice right away that the number of log lines in your terminal window reflects the operations Express.js performs to register your routes, along with some configurations it makes before your web server launches (listing 35.4). Now when you visit any page in your application locally, the debug logs stream down your terminal window. Conveniently, Express.js also tells you how much time each operation takes in its log messages. During development, this information can help you determine whether some parts of the application aren’t performing well so that you can investigate further.

Listing 35.4. Example of log messages through Express.js in terminal
express:router:route new "/new" +0ms            1
express:router:layer new "/new" +0ms
express:router:route get "/new" +0ms
express:router:layer new "/" +0ms
express:router:route new "/create" +0ms
express:router:layer new "/create" +0ms

  • 1 Log Express.js route registration in debug mode.

If you find it helpful to run your application with debug logs, you can add a start script in your package.json file to avoid writing the whole command each time. Add "debug": "DEBUG=* node main" after your start script. Then, whenever you want to see these logs, run the npm run debug command.

These logs can be valuable in production as well, though you don’t want to run your production application in debug mode. Instead, install another package to handle logging the important data that you want to see in production. Install a package called morgan to provide your Node.js application better console log messages.

Install the morgan package by running the command npm i morgan -S. Then, in main.js, require the morgan module by adding const morgan = require("morgan"). Then the process is as simple as telling your Express.js application to use morgan and passing in some formatting options. You can add app.use(morgan(":method :url :status * :response-time ms")) to log the request method, URL, status code, and time taken to process a response, for example.

This output should immediately resemble the logs that Express.js generated in debug mode. Launch your application with npm start, and notice the logs for each request made, as shown in the next listing. I recommend using the morgan("combined") format, in which the combined formatting options provides a lot of the information you’ll need to monitor the request-response cycle in your production application.

Listing 35.5. Example of log messages with morgan
GET / 200 * 20.887 ms                     1
GET /js/jquery.min.js 304 * 2.504 ms
GET /js/bootstrap.min.js 304 * 1.402 ms
GET /js/recipeApp.js 304 * 0.893 ms
GET /css/recipeApp.css 304 * 1.432 ms

  • 1 Log custom messages with morgan.

With logging set up, the best approach to debugging problems is to pause your application where issues occur and analyze the code surrounding those issues. This practice is easier said than done, but tools are available to help you identify the troubled code. Built into Node.js is a debug tool that lets you step through your code one line at a time. After each line of code, you can evaluate the variables and data to determine whether their values are what you expect.

To run the built-in debugger, run the node inspect main.js command in your project’s terminal window. After running this command, you’ll immediately see the first lines of your main.js file display in your terminal window. The tool pauses as soon as your application starts, stating Break on start in main.js:1. You can start evaluating your code by typing n to go to the next line, incrementally jumping over a single line at a time, or typing c to continue running your application. If you type c, your application runs as usual. The debugger becomes particularly useful when you have an idea of where your code isn’t working properly. If you think that your code isn’t finding users correctly on the user’s show page, for example, you may want to pause the code within that controller action. To pause in specific locations, add debugger; at that location in your code, as shown in listing 35.6.

By adding this line, running the debugger again in terminal, and typing c to let your application run, you’re setting the application up to stop for you when it queries the database for a user in the show action before the view is rendered.

Listing 35.6. Debugging the show action in usersController.js
User.findById(userId)
  .then(user => {
    debugger;                         1
    res.render("users/show", {
      user: user
    });
});

  • 1 Add a debugger breakpoint when a user is found in the database.

As soon as you visit a user’s show page in your browser, the page pauses, and your terminal window displays the code where you placed your debugger;. From there, you can investigate the variables within this code by entering the REPL environment. By typing repl in the debugger window in terminal, you can run normal REPL commands within the context of the code that’s being debugged. In this example, you’re checking whether the user being retrieved from the database has a valid email address, so run the following statement: console.log(user.email). If you get undefined or some value other than the user’s email address, you know that the issue has to do with the email, and you can investigate further. When you’re done debugging, type c to continue and press Ctrl-D to exit. For more information about this debugger, visit https://nodejs.org/api/debugger.html.

The built-in debugging tool can be a helpful way to analyze the data in your application as it runs. Fully debugging your code this way involves a few steps, however, so I recommend exploring other debugging tools, such as node-inspector, which lets you use the console in Google Chrome to debug. You can also use Node.js with an integrated development environment like TernJS in Atom, which offers debugging tools while you edit your code.

Quick check 35.3

Q1:

What happens when you add debugger to your application code?

QC 35.3 answer

1:

Adding debugger to your code allows the debugging tool in Node.js to pause at that specific location as your application runs. Outside the debug tool, this addition won’t prevent your application from running normally.

 

Summary

In this lesson, you learned how to add data to your production application through the Heroku console. Then you installed eslint to lint your application for errors or syntactic inconsistencies in your code. Last, I introduced some debugging tips to help you identify production errors and know immediately where to go to fix them.

Try this

Try using the debugger in Node.js to evaluate the values of different variables in your application. Try running your application in debug mode and breaking within the user’s create action to evaluate the incoming request parameters.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset