Friday, September 29, 2017

How to Quit (The Right Way) When You Hate Your Job (So Much)

How to Simply Design Your Own Website With WordPress - Quickly

Best Video Background Plugins for WordPress

International Artist Feature: Egypt

How to Use AI In Google Sheets in 60 Seconds

Building a Slack Bot Using Node.js

Building a Slack Bot Using Node.js

Slack is quickly becoming the new industry standard for teams to communicate with. In fact, it is so popular that when I typed slack into Google, as I expected, the first result was the definition of the word from the dictionary. This was followed immediately by Slack's website! 

This is almost unheard of for most common words in the English dictionary. Usually, Google's definition is followed by several links to the top dictionary websites.

What is Slack?

At its most basic, Slack is a messaging system. It allows for direct messages to team members and the creating of channels (private or public) that allow easy real-time team communication and collaboration. For more information on Slack, you can view Slack's Features.

At this point, you might be wondering where Node.js comes in. As I mentioned, at its most basic, Slack is a messaging system; however, it can be infinitely extended and customized. Slack provides an incredibly flexible system to customize your team's integration, including:

  • creating custom welcome messages
  • creating custom emojis
  • installing third-party applications
  • creating your own applications
  • creating custom Slack Bots

In this article, I am going to demonstrate how to create a Slack Bot with Node.js that can be added to your team's Slack configuration.

Slack Bots Defined

A Slack Bot's job is to receive events sent from Slack and handle them. There are a plethora of events that will be sent to your Bot, and this is where Node.js will come in. We must decide not only which events to handle, but how to handle each individual event.

For example, some common events that a Bot would handle are:

  • member_joined_channel
  • member_left_channel
  • message

In this article, I will create a Node.js application and a Slack Bot that can be added to your team project to perform specific actions based on the events it receives.

To begin, I need to create a Bot on Slack. Two types of bots can be created:

  • a custom bot
  • creating an application and adding a bot user

This article will create a custom bot because an application bot user would be more appropriate if you were planning to write and publish an application on Slack. Given that I wish this bot to be private to my team, a custom bot will suffice.

Creating a Custom Slack Bot

A custom bot can be created here: http://ift.tt/2fVYiPf. If you are already logged in to your Slack account, on the left select the Add Configuration button; otherwise, log in to your Slack account before proceeding. If you do not have a Slack account, you can sign up for free.

This will take you to a new page that requires you to provide a username for your bot. Enter your username now, ensuring you follow Slack's naming guidelines. Once you have selected an awesome bot name, press Add bot configuration.

After you have successfully created your bot, Slack redirects you to a page that allows for further customization of your bot. I'll leave that part to your creative self. The only thing needed from this page is the API Token that starts with xoxb-. I would either copy this token to a safe place for later use or simply leave this page open until we need the token for the Node.js application.

Configurations

Before moving on to code, two more Slack configurations are required:

  1. Create or choose an existing channel that your bot will interact with. While I'm testing my new bot, I chose to create a new channel. Be sure to remember the channel name as you will need it within your application shortly.
  2. Add/Invite your bot to the channel so it can interact with it.

Now that I've got my Slack Bot configured, it's time to move on to the Node.js application. If you already have Node.js installed, you can move on to the next step. If you do not have Node.js installed, I suggest you begin by visiting the Node.js Download page and selecting the installer for your system.

For my Slack Bot, I am going to create a new Node.js application by running through the npm init process. With a command prompt that is set to where you wish your application to be installed, you can run the following commands:

If you are unfamiliar with npm init, this launches a utility to help you configure your new project. The first thing it asks is the name. It defaulted mine to slackbot, which I'm comfortable with. If you would like to change your application name, now is the chance; otherwise, press Enter to proceed to the next configuration step. The next options are version and description. I've left both as the default and simply continued by pressing Enter for both of these options.

Entry Points

The next thing that is asked for is the entry point. This defaults to index.js; however, many people like to use app.js. I do not wish to enter this debate, and given my application will not require an intensive project structure, I am going to leave mine as the default of index.js.

After you've recovered from a debate that is probably as strong as tabs vs. spaces, the configuration continues, asking several more questions:

  • test command
  • git repository
  • keywords
  • author
  • license

For the purposes of this article, I've left all options as their default. Finally, once all options have been configured, a confirmation of the package.json file is displayed prior to creating it. Press Enter to complete the configuration.

Enter the SDK

To make interacting with Slack easier, I'm also going to install the Slack Developer Kit package as follows:

Are you finally ready for some code? I sure am. To begin, I'm going to use the example code from the Slack Developer Kit's website that posts a Slack message using the Real-Time Messaging API (RTM) with a few tweaks.

Given that the entry point I chose was index.js, it's time to create this file. The example from the Slack Developer Kit's website is roughly 20 lines of code. I'm going to break it down several lines at a time, only to allow for explanations of what these lines are doing. But please note that all these lines should be contained in your index.js file. 

The code begins by including two modules from the Slack Developer Kit:

The RtmClient, once instantiated, will be our bot object that references the RTM API. The CLIENT_EVENTS are the events that the bot will be listening for.

Once these modules are included, it's time to instantiate and start the bot:

Be sure to replace the API Token that is obfuscated above with your token obtained during the Slack Bot creation.

Calling the start function on my RtmClient will initialize the bot's session. This will attempt to authenticate my bot. When my bot has successfully connected to Slack, events will be sent allowing my application to proceed. These events will be shown momentarily.

With the client instantiated, a channel variable is created to be populated momentarily inside one of the CLIENT_EVENTS events.

The channel variable will be used to perform specific actions, such as sending a message to the channel the bot is connected to.

When the RTM Session is started (rtm.start();) and given a valid API Token for the bot, an RTM.AUTHENTICATED message will be sent. The next several lines listen for this event:

When the RTM.AUTHENTICATED event is received, the preceding code performs a for loop through the list of Slack team channels. In my case, I'm specifically looking for jamiestestchannel and ensuring that my bot is a member of that channel. When that condition is met, the channel ID is stored in the channel variable.

Debugging

To aid in debugging, a console message is logged that displays a message indicating that the bot has successfully authenticated by displaying its name (${rtmStartData.self.name}) and the team name (${rtmStartData.team.name}) it belongs to.

After the bot has authenticated, another event is triggered (RTM.RTM_CONNECTION_OPENED) that signifies the bot is fully connected and can begin interacting with Slack. The next lines of code create the event listener; upon success, a Hello! message is sent to the channel (in my case, jamiestestchannel).

At this point, I can now run my Node application and watch my bot automatically post a new message to my channel:

The results of running this command (when successful) are twofold:

  1. I receive my debug message indicating that my bot has successfully logged in. This originated from the RTM.AUTHENTICATED being triggered after starting the RTM Client.
  2. I receive a Hello! message in my Slack channel. This occurred when the RTM.RTM_CONNECTION_OPENED event message was received and handled by the application.

Before proceeding and further enhancing my application, now is a good time to recap what I have done to get this far:

  1. Created a custom Slack Bot.
  2. Created a custom Slack Channel and invited my bot to it.
  3. Created a new Node.js application called slackbot.
  4. Installed the Slack Developer Kit package to my application.
  5. Created my index.js file that creates an RtmClient using my API Token from my custom bot.
  6. Created an event listener for RTM.AUTHENTICATED that finds the Slack Channel my bot is a member of.
  7. Created an event listener for RTM.RTM_CONNECTION_OPENED that sends a Hello! message to my Slack Channel.
  8. Called the RTM Start Session method to begin the authentication process that is handled by my event listeners.

Building the Bot

Now it's time for the real fun to begin. Slack offers (I didn't count) at least 50 different events that are available for my custom bot to listen and optionally handle. As you can see from the list of Slack Events, some events are custom to the RTM API (which we are using), while other events are custom to the Events API. At the time of writing this article, it is my understanding that the Node.js SDK only supports RTM.

To finish my bot, I will handle the message event; of course, this is probably one of the most complicated events as it supports a large number of sub-types that I will explore in a moment.

Here is an example of what the most basic message event looks like from Slack:

In this basic object, the three most important things I care about are:

  1. The channel. I will want to ensure this message belongs to the channel my bot is a part of.
  2. The user. This will allow me to interact directly with the user or perform a specific action based on who the user is.
  3. The text. This is probably the most important piece as it contains the contents of the message. My bot will want to only respond to certain types of messages.

Some messages are more complicated. They can contain a lot of sub-properties such as:

  • edited: A child object that describes which user edited the message and when it occurred.
  • subtype: A string that defines one of the many different kinds, such as channel_join, channel_leave, etc.
  • is_starred: A boolean indicating if this message has been starred.
  • pinned_to: An array of channels where this message has been pinned.
  • reactions: An array of reaction objects that define what the reaction was (e.g. facepalm), how many times it occurred, and an array of users who reacted this way to the message.

I'm going to extend my previously created index.js to listen for message events. To reduce redundancy of code, the following examples will contain just the portion of code related to the message event enhancements.

The first thing that must be done is to include a new module for the RTM_EVENTS that I will be listening to. I've placed this below my two previous module includes:

The code for handling the message event I will be placing at the bottom of my file. To test that the message event is working correctly, I've created a new event listener that logs the message object to the console as follows:

I can now re-run my Node application (node index.js). When I type a message into my channel, the following is logged to my console:

So far, so good. My bot is successfully receiving messages. The next incremental step to make is to ensure the message belongs to the channel my bot is in:

Now when I run my application, I only see my debug message if the message event was for the channel that my bot is a part of.

I'm now going to extend the application to send a custom message to the channel demonstrating how a user can be tagged in a message:

Now, when anyone types a message in the channel, my bot sends its own message that looks something like: "Stop, everybody listen, @endyourif has something important to say!"

Ok, not extremely useful. Instead, I'm going to finish my bot by enhancing the message event listener to respond to specific commands. This will be accomplished by doing the following:

  1. Split the text portion of a message into an array based on a blank space.
  2. Check if the first index matches my bot's username.
  3. If it does, I will look at the second index (if one exists) and treat that as a command that my bot should perform.

To make it easy to detect if my bot was mentioned, I need to create a new variable that will store my bot user ID. Below is an updated section of code where I previously set the channel variable. It now also stores my bot's user ID in a variable called bot.

With my bot variable set, I've finished my bot by fleshing out the previously created message event listener as follows:

The following code splits the text property of the message object in an array based on a space. I next ensure that I have at least two elements in the array, ideally my bot and the command to perform.

When the first element in the array matches my bot, I perform a switch statement on the second element in the array: the command. The current commands supported are jump and help. When a message is sent to the channel that looks like "@jamiestest jump", my bot will respond with a special message to the originating user. 

If the command is not recognized, it will fall into my default case statement for my switch and respond with a generic command that will look like this: "@endyourif, sorry I do not understand the command "hi". For a list of supported commands, type: @jamiestest help".

Conclusion

At this point, my bot is complete! If you are interested in further enhancing your bot, here's a list of ideas:

  • Handle a new team member joining by listening to the team_join event. When a new team member joins, it would be a great idea to send them a variety of onboarding information and/or documentation welcoming them to your team.
  • Enhance the list of supported commands that I've started.
  • Make the commands interactive by searching a database, Google, YouTube, etc.
  • Create a bot user on an application and create your own custom slash commands.

New Course: Getting to Know the Foundation XY Grid

10 Basic Mistakes in Digital Painting and How to Fix Them

How to Make a Fiery Halloween Pumpkin in Photoshop (With an Action)

Create a Text Reveal Motion Graphic in Blender: Part 2

How to Compress Rock Vocals Like a Pro

Thursday, September 28, 2017

Quick Tip: Create a Visual Asset Library With “Lingo”

How to Draw a Spooky Halloween Background in Adobe Illustrator

How to Make Professional PowerPoint Presentations (With Templates)

Learn Computer Science With JavaScript: Part 3, Loops

Learn Computer Science With JavaScript: Part 3, Loops

Introduction

Suppose you have been given the task to write a program that displays the numbers 1–100. One way you could accomplish this is to write 100 console.log statements. But I’m sure you wouldn’t because you would have become fed up by the 9th or 10th line.  

The only part that changes in each statement is the number, so there should be a way to write only one statement. And there is with loops. Loops let us perform a set of steps in a code block repeatedly.  

Contents

  • While loops
  • Do-while loops
  • For loops
  • Arrays
  • For-in loops
  • For-of loops
  • Review
  • Resources

While Loops

While loops will execute a set of statements repeatedly while some condition is true. When the condition is false, the program will exit the loop. This kind of loop tests the condition before performing an iteration. An iteration is an execution of the loop’s body. The following example will not display anything because our condition is false.

This is the general form of a while loop:

One thing to be careful of when using while loops is creating loops that never end. This happens because the condition never becomes false. If it happens to you, your program will crash. Example:

Task

How many times will the body of this loop be executed:

Do-While Loops

A do-while loop will execute the body of statements first, and then check the condition. This kind of loop is useful when you know you want to run the code at least once. The following example will display “eat” once, even though the condition is false.

This is the general form for a do while-loop:

Task

Write a do-while loop that will display the numbers 1–10.

For Loops

A for-loop will repeat execution of a code block for a specific number of times. The following example displays the numbers 1–10:

This is the general form of a for-loop:

Initial is an expression that sets the value of our variable. Condition is an expression that must be true for the statements to execute. And step is an expression that increments the value of our variable.

One programming pattern is to use a for loop to update the value of a variable with itself and a new value. This example sums the numbers 1–10:

The += is an assignment operator that adds a value back to a variable. This is a list of all the assignment operators:

Operator
Example
Equivalent
+= x += 2
 x = x + 2
-= x -= 2
x = x - 2
*= x *= 2
x = x * 2
/= x /= 2
x = x / 2
%= x %= 2
x = x % 2

Task 

Write a for loop that calculates the factorial of a number. The factor of a number n is the product of all the integers from 1 to n. For example, 4! (4 factorial) is 1 x 2 x 3 x 4 which equals 24.

Arrays

An array is an object that holds a list of items, called elements, which are accessed by their index. The index is the position of the element in the array. The first element is at the 0 index. The following are some common array operations.

Create an empty array:

Initialize an array with values:

Get an element from an array:

Update an element in an array:

Loop over an array:

A two-dimensional array is an array whose elements are arrays. Example:

This is how you would loop over the array and display each element:

Task 

What element is displayed when i = 1 and j = 0 in the above for loop?

For-In Loop

This kind of loop lets us loop through the keys in an object. An object is a data structure that has keys mapped to values. Here are some common operations that can be performed on an object.

Create an empty object:

Initialize an object with values:

Get a property from an object:

Update a property in an object:

Loop over the keys of an object:

Task

What does the above for loop display given obj = {foo: "Hello", bar: "World"}?

For-Of Loop

This kind of loop lets us loop over the values of iterable objects. Examples of iterable objects are arrays and strings.

Loop over an array:

Loop over a string:

Task

Using any of the loops, write a program that will display this staircase pattern:

Review

Loops let us reduce duplication in our code. While loops let us repeat an action until a condition is false. A do-while loop will execute at least once. For loops let us repeat an action until will we reach the end of a count. The for-in loop is designed so we can access the keys in an object. The for-of loop is designed so we can get the value of an iterable object. 

Next, in part 4, we will learn about functions.

Resources


How to Use Layers in Traditional Drawing

10 Easy Pieces: Complete Identity Packs for Broadcast News

How to Create a Quick Soft Pastel Text Effect in Adobe Photoshop

Wednesday, September 27, 2017

How to Draw the Minions in Adobe Illustrator

Quick Tip: When to Use Customer Surveys

How to Use Cell Styles in Excel in 60 Seconds

Learn Computer Science With JavaScript: Part 4, Functions

Learn Computer Science With JavaScript: Part 4, Functions

Introduction

Suppose you have a file that is 82 lines long and consists only of a series of statements. (I hope this is isn’t true, but anything is possible.) How would you understand what the program does? How would you modify it or use it? It would be kind of hard to do anything with this code because there is no structure to it.  

To solve this problem, you could use functions. A function is a group of statements that perform a specific task. Functions allow us to break up a program into smaller programs, making our code more readable, reusable, and testable.

Contents

  • Void functions
  • Value returning function
  • Scope
  • Parameters
  • Modules

Void Functions

This kind of function lists steps for the program to perform. Consider we are writing a program to log a user into a website. The program might consist of the following tasks:

  • Get the username
  • Get the password
  • Check if the username and password exist
  • Redirect the user to their dashboard

Each of these steps might be contained inside a login function. This is an example function:

This is the general form of a function:

To execute the function (also known as calling the function, or invoking the function), you write a statement that calls it.

The () is where we pass input to the function. When we are defining the function, the input is called a parameter. When we call the function, the input will be the actual value and is called the argument. Example:

With JavaScript ES6, you can define functions using arrow syntax. Here is our greet function defined using arrow syntax:

A function with one parameter:

A function with more than one parameter:

A function with multiple statements:

Because an arrow function is an anonymous function, we give our function a name by assigning it to a variable. Arrow functions can be useful when your function body only has one statement.

Value Returning Function

This kind of function returns a value. The function must end with a return statement. This example returns the sum of two numbers.

This is the general form defining a value returning function:

The value of expression is what gets output by the function. This kind of function is useful when it is stored in a variable. 

Scope

A variable’s scope is the part of the program where a variable can be accessed. A variable can be local or global. A local variable’s scope is inside the function it was created in. No code outside of the function can access its local variables. 

Also, when you use let or const to declare a variable, they have block scope. A block is a set of statements that belong together as a group. A block could be as simple as wrapping our code in curly braces:

The variable a is local to the block it is in. A block can also be a loop or an if statement. Example:  

Because our console statement is in the same scope as our first variable a, it displays that value, which is 1. It does not have access to the variables inside the if block. Now, consider this example:

Now 2 will be displayed because the scope of variables that our console statement has access to is within the if block. A function’s parameters are also local variables and can only be accessed by code inside the function. Global variables, on the other hand, can be accessed by all the statements in a program’s file. Example:

In this example, a is a global variable, and we have access to it inside the foo function. The first console statement will display 1. After calling foo, the value of a is set to 2, making the second console statement display 2. 

Global variables should be used very little, ideally not at all. Because global variables can be accessed by any part of a program, they run the risk of being changed in unpredictable ways. In a large program with thousands of lines of code, it makes the program harder to understand because you can’t easily see how the variable is being used. It is better to create and use local variables.

However, if you need to use a variable in multiple places in your program, it is OK to use a global constant. Declaring a variable with the const keyword prevents it from being changed, making it safer to use. You only need to worry about updating the value of the constant in the place it was declared.

Parameters

Recall that a parameter is a variable a function uses to accept data. The parameter is assigned the value of a function’s arguments when the function is called. As of ES6, parameters may also be given default values with the format parameterName=value. In this case, you can call a function without arguments, and it will use default values. Example:

The spread/rest operator is new to ES6 and can be used to either expand an array or object into individual values or gather the parameters of a function into an array. This is an example of using a rest parameter:

Modules

Suppose now you have a file that has 1,082 lines. (I have seen this, and you should run if you encounter such a thing.) The file is organized into functions, but it is difficult to see how they relate to each other. 

To group together related behavior, we should put our code in modules. A module in ES6 is a file that contains related functions and variables. Modules let us hide private properties and expose public properties that we want to use in other files. The filename would be the name of the module. Modules also have their own scope. To use variables outside of the module’s scope, they have to be exported. Variables that aren’t exported will be private and can only be accessed within the module.  

Individual properties can be exported like this:

Alternatively, all properties can be exported with one export statement:

To use a module’s variables, you import it into the file. You can specify what you want to import from the module like this:

You can also rename your import:

Or you can import all of the properties of the module:

Review

Functions allow us to divide our programs into smaller programs that we can easily manage. This practice is known as modularizing. There are two kinds of functions: void functions and value returning functions. A void function executes the statements inside of it. A value returning function gives us back a value.  

Scope is the part of the program where a variable can be accessed. Variables declared inside a function, including the function’s parameters, are local. Blocks also have scope, and local variables can be created inside of them. 

Variables not enclosed in a block or module will be global. If you need a global variable, it is acceptable to have a global constant. Otherwise, try to contain your code to modules because modules have their own scope. But even better, modules give your code structure and organization.  

Resources


How to Create a Wood Engraved Logo Mockup in Adobe Photoshop

15 Best Soundtracks for Instructional Videos

New Course: WordPress Security Top Tips

How to Code Natural Language Processing on Android With IBM Watson

Envato Tuts+ Community Challenge: Created by You, September 2017 Edition

How to Make Smooth Drone Video in Adobe After Effects

Tuesday, September 26, 2017

How to Turn Day Into Night in Adobe Photoshop

How to Set Up Grids in Affinity Designer

How to Run Presentations on Google Slides Remotely (With Phone App)

25 Awesome Overlays for Video

Learn Computer Science With JavaScript: Part 2, Conditionals

Learn Computer Science With JavaScript: Part 2, Conditionals

Introduction

In part one of this series, our programs were only written as a sequence of statements. This structure severely limits what we can do. Say you are designing a program that needs to log in users. You may want to direct a user to one page if they give the correct credentials and send them to another if they aren’t registered. 

To do this, you need to use a decision structure like an if statement. This will perform an action only under certain conditions. If the condition does not exist, the action is not performed. In this tutorial, you'll learn all about conditionals.

Contents

  • If statements
  • Relational operators
  • If-else statement
  • Switch statements
  • Logical operators
  • Review
  • Resources

If Statements

A single if statement will perform an action if a condition is true. If the condition is false, the program will execute the next statement that is outside of the if block. In the following example, if the expression isRaining() is true, then we will putOnCoat() and putOnRainboots() then goOutside(). If isRaining() is false, the program will only execute goOutside().

This is the general form for writing an if statement:

The condition is an expression that has the value true or false. An expression that is true or false is called a boolean expression. Boolean expressions are made with relational operators. 

Relational Operators

A relational operator compares two values and determines if the relationship between them is true or false. They can be used to create boolean expressions for our conditions. Here is a list of relational operators with examples:

Operator Meaning Example Meaning
== equality x == y Is x equal to y?
===
strict equality  x === y Is x equal to y in value and type?
!=
inequality
x != y
Is x not equal to y?
!==
strict inequality
x !== y
Is x not equal to y in value and type?
> greater than
x > y
Is x greater than y?
< less than
x < y
Is x less than y?
>= greater than or equal
x >= y
Is x greater than or equal to y?
<= less than or equal
x <= y
Is x less than or equal to y?

It is important to note the difference between the equality operator == and the strict equality operator ===. For example, the expression 2 == "2" is true. But the expression 2 === "2" is false.  In the second example, the two values are different data types, and that is why the expression is false. It is best practice to use === or !==.

The following example will display the message, "You get an A".

Task

What is the value of the expression 5 > 3? 6 != "6"?

If-Else Statements

An if-else statement will execute one block of statements if its condition is true, or another block if its condition is false. The following example will display the message “valid username” because the condition is true.

This is the general form of an if-else statement:

Task

 What will be the output of this program:

It is also possible to check for more than one condition. Example:

This is the general form for writing multiple if-else-if statements:

Switch Statements

A switch statement is also used to conditionally execute some part of your program. The following example implements our roman numeral converter as a switch statement:

This is the general form of a switch statement:

Each case represents a value our expression can take. Only the block of code for the case that is true will execute. We include a break statement at the end of the code block so that the program exits the switch statement and doesn’t execute any other cases. The default case executes when none of the other cases are true.    

Task 

Write a switch statement that displays the day of the week given a number. For example, 1 = Sunday, 2 = Monday, etc.

Logical Operators

The and operator && and the or operator || allow us to connect two boolean expressions. The not operator ! negates an expression. To illustrate how logical operators work, we will look at a truth table. A truth table contains all the combinations of values used with the operators. I use P to represent the left-hand expression and Q for the right-hand expression.  

&& truth table:

P Q P && Q
true true true
true
false
false
false
true
false
false
false false

We read the table going across each row. The first row tells us that when P is true and Q is true, P && Q is true. The following example tests whether 82 is between 60 and 100 inclusive.

  • let x = 82;
  • x >= 60 && x <= 100
  • P: x >= 60 is true
  • Q: x <= 100 is true
  • P && Q: true && true

|| truth table:

P Q P || Q
true
true
true
true
false
true
false
false true
false
false
false

This example tests if 82 is outside the range 60–100:

  • let x = 82;
  • x < 60 || x > 100
  • P: x < 60 is false
  • Q: x > 100 is false
  • P || Q: false || false

! truth table:

P !P
true
false
false
true

Example:

  • x = 82
  • P: x > 0 is true
  • !P: false

Task

Fill in the table with the missing values.

P Q !P !Q !P && !Q
!P || !Q
true
true




true
false

false
true

false
false


Something useful to know about logical operators is that if the expression on the left side of the && operator is false, the expression on the right will not be checked because the entire statement is false. And if the expression on the left-hand side of an || operator is true, the expression on the right will not be checked because the entire statement is true.

Review

A program can execute blocks of code conditionally using boolean expressions. A boolean expression is written using relational operators. Logical operators allow us to combine boolean expressions. 

A single if statement gives the program one alternative path to take if a condition is met. If-else statements provide a second course of action if the condition is false. And if-else-if statements allow us to test multiple conditions. Switch statements can be used as an alternative to an if-else-if statement when you have multiple conditions to test. 

Next, in part 3, we will discuss loops.

Resources


How to Draw a Stack of Books and an E-Book Reader in Adobe Illustrator

Performance Test: The Best Selling WordPress Themes on ThemeForest

Distortion Masterclass for Ableton Suite: Part 1

Concurrency in RxJava 2

Monday, September 25, 2017

Instagram Stories: How to Create a Color Story

How to Create a Leather Stamp Logo Mockup in Adobe Photoshop

6 Things That Make Yarn the Best JavaScript Package Manager

6 Things That Make Yarn the Best JavaScript Package Manager

Yarn is an open-source npm client that was developed at Facebook and improves on many aspects of the standard npm client. In this tutorial, I'll focus on the top six features that make Yarn awesome:

  1. Speed
  2. Robust Installs
  3. License Checks
  4. Compatibility with npm and Bower
  5. Multiple Registries
  6. Emojis

1. Speed

One of Yarn's claims to fame is its speed compared to the standard npm client. But how fast is it? In a recent benchmark, Yarn was two to three times faster than npm. The benchmark timed the installation of React, Angular 2, and Ember. This is a pretty good test for a package manager as each of these frameworks pulls a bunch of dependencies and represents a major share of the dependencies of a real-world web application.  

Let's add another data point and check for ourselves by installing a create-react-app using both yarn and npm. Here is the installation using yarn:

Here is the installation using npm:

Yep. This definitely corroborates other reports about a significant speed advantage to yarn. Yarn installed in 2.59 seconds, while npm took 9.422 seconds. Yarn was 3.63X faster!

2. Robust Installs

Yarn also boasts more robust installs than npm. What makes an install flaky? If subsequent installs fail or produce a different outcome then an install is flaky. There are two main causes:

  1. Transient network issues might cause fetching packages from the registry to fail.
  2. New releases of packages might result in incompatible and breaking changes.

Yarn addresses both concerns. 

Offline Cache

Yarn uses a global offline cache to store packages you've installed once, so new installations use the cached version and avoid flakiness due to intermittent network failures. You can find where your yarn cache is by typing:

Here are the first five packages in my offline cache:

Yarn can go even further and have a full offline mirror that will work across upgrades of the yarn itself.

The yarn.lock File

The yarn.lock file is updated whenever you add or upgrade a version. It essentially pins down the exact version of each package that may be specified in package.json using partial versioning (e.g. just major and minor) and its dependencies. 

Here is the beginning of a typical yarn.lock file. You can see the version as specified in package.json like "abbrev@1" and the pinned version "1.1.0".

But Why?

Yarn also gives you the yarn why command to explain why a particular package is installed in your project:

3. License Checks

Some projects need to abide by certain licensing requirements or just produce a report for internal or external purposes. Yarn makes it really easy with the yarn licenses ls command. It produces a compact report that includes the fully qualified package name, its URL, and the license. Here is an example:

Yarn can even generate a disclaimer for you with yarn licenses generate-disclaimer. The result is some text with a disclaimer message and text for each package in your application. Here is a sample from the disclaimer generated for my test project:

4. Compatibility With npm and Bower

Yarn is fully compatible with npm as it is just a different client that works with npm registries. Very early it supported Bower, but then shortly after a decision was made to drop Bower support. 

The main reason was that the Bower support didn't work very well and emptied the bower_components directory or didn't fetch any bower packages on a fresh project. But another reason is that the Yarn team didn't want to encourage fragmentation in the package management arena and instead preferred for everyone to switch to npm.

If you are invested in Bower and don't want to migrate right now, you can still use Yarn, but add the following snippet to your package.json file:

5. Multiple Registries

Yarn can work with multiple registry types. By default, if you just add a package, it will use its npm registry (which is not the standard npm registry). But it can also add packages from files, remote tarballs, or remote git repositories.

To see the current configured npm registry:

To set a different registry type: yarn config set registry <registry url>

To add packages from different locations, use the following add commands:

6. Emojis FTW!

Some people like emojis, and some people don't. Yarn originally displayed emojis automatically, but only on Mac OS X. It caught fire from both camps: the emoji haters were upset that their console on Mac OS X was cluttered with emojis, and the emoji lovers were upset that they didn't have emojis on Windows and Linux. 

Now, emojis are not displayed on macOS by default, and you can enable emojis with the --emoji flag:

Conclusion

Yarn is the best JavaScript package manager. It is compatible with npm, but much, much faster. It addresses serious problems for large-scale projects with flaky installation, it supports multiple types of registries, and it has emojis to boot. 

JavaScript, though not without its learning curves, has plenty of libraries and frameworks to keep you busy, as you can see. If you’re looking for additional resources to study or to use in your work, check out what we have available in the Envato marketplace.

The JavaScript community is overall very positive, and there is a lot of momentum behind Yarn. It has already addressed some issues such as redundant Bower support and emojis by default. Migrating to Yarn from npm is very easy. I highly recommend that you give a try.


TypeScript for Beginners, Part 1: Getting Started

How to Add PPT Border Designs to Slides in 60 Seconds

Learn Computer Science With JavaScript: Part 1, The Basics

Learn Computer Science With JavaScript: Part 1, The Basics

Introduction

JavaScript is a language that we can use to write programs that run in a browser or on a server using Node. Because of Node, you can use JavaScript to build full web applications like Twitter or games like Agar.io.  

This is the first lesson in a four-part series where I will teach you the programming fundamentals you will need so you can learn to build your own apps. In part 1, I will introduce you to the syntax of JavaScript and ES6. ES6 stands for ECMAScript 6, which is a version of JavaScript.

Contents

  • Installation and setup
  • Designing a program
  • Syntax
  • Variables
  • Data types
  • Review
  • Resources

Installation and Setup

First, we will set up our development environment so that we can run our code on our own computer. Alternatively, you can test code examples on an online editor like repl.it. I prefer you get started writing and running code on your computer so you can feel like a real programmer. Plus, I want you using Node so you can put it on your resume and impress your employer.  

First, you will need a text editor to write your code in. I recommend Sublime Text. Next, download and install Node to your computer. You can get the software on the Node.js website. Confirm the installation worked by typing the command node -v from your terminal. If everything is fine, you will see the version number of your Node installation. 

One of the things you can do with Node is run JavaScript code from within your terminal. This takes place in what is called a REPL. To try it out, enter the command node in your terminal. 

Next, let's print the message “Hello, World”. Type the following into the terminal:

To exit the REPL, press Control-C twice. Using the REPL comes in handy when you want to test simple statements like the example above. This can prove more convenient than saving code to a file—especially if you’re writing throwaway code. 

To execute a program you have written in a file, in your terminal run the command node filename, where filename is replaced with the name of your JavaScript file. You do not have to type the js extension of the filename to run the script. And you must be in the root directory where the file lives.

Let’s try an example. Create a file named hello.js. Inside, we will put the following code:

Run the code from the terminal:

If all is well, you will see the text "Hello, World" output to the terminal. From now on, you can test the code examples from this tutorial either by using the Node REPL or by saving to a file.  

Designing a Program

Before you write any code, you should take the time to understand the problem. What data do you need? What is the outcome? What tests does your program need to pass? 

When you understand the requirements of the program, then you can write the steps to solve it. The steps are your algorithm. Your algorithm is not code. It is plain English (replace English with your native language) instructions for solving the problem. For example, if you want to write an algorithm for cooking top ramen, it might look like this:

  1. Remove top from cup.
  2. Empty seasoning pack into cup.
  3. Fill cup with water.
  4. Microwave on high for 2 minutes.
  5. Cool for 1 minute.

Yes, I was hungry when I thought of this. And no, this is not something you would actually be given as a programming problem. Here is an example of a problem that is more practical. It is an algorithm to calculate the average of a list of numbers.

  1. Calculate the sum all of the numbers.
  2. Get the total number of numbers.
  3. Divide the sum by the total.
  4. Return the result.

Understanding the problem and coming up with an algorithm are the most important steps in programming. When you feel confident in your algorithm, then you should write some test cases. The tests will show how your code should behave. Once you have your tests, then you write code and tweak it until your tests pass. Depending on how complex your problem is, each one of the steps in your algorithm may need to be broken down further.  

Task

Write an algorithm to calculate the factorial of a number. The factorial of a number *n* is the product of all integers from 1 to *n*. For example, 4! (4 factorial) is 1 x 2 x 3 x 4 = 24.  

Syntax

A program is similar to the language we speak with. The only difference is a programming language is meant to communicate with the computer (and other programmers who have to use it). The rules for constructing the program are its syntax. Programs consist of statements. A statement can be thought of as a sentence. In JavaScript, you must put a semicolon at the end of a statement. Example:

Statements consist of expressions. Expressions are like the subject/predicate parts of a sentence. In a programming language, expressions have a value. Expressions consist of keywords like var and for which are the built-in vocabulary of the language; data like a number or string; and operators like + and =. Example:

Here is a list of arithmetic operators:

  • + - Addition
  • - - Subtraction 
  • * - Exponentiation
  • * - Multiplication
  • / - Division
  • % - Remainder
  • ++ - Increment
  • -- - Decrement

The remainder operator returns the remainder after dividing two numbers. For example, 4 % 2 returns 0, and 5 % 3 returns 2. The remainder operator is commonly used to find out if a value is even or odd. Even values will have a remainder 0.  

Task

Find the value of the following expressions. Write down your answers first, and then check them in your REPL.

  • 9 % 3
  • 3 % 9
  • 3 % 6
  • 3 % 4
  • 3 % 3
  • 3 % 2

Variables

A variable is a name that represents a value in the computer’s memory. Any value we would like to store or to use over and over should be placed in a variable. One way of creating variables is with the var keyword. But the preferred way is to use the let or const keywords. Here are some examples of using let to create variables:

Declaring a variable:

Declaring and initializing a variable:

Reassigning a variable:

Constants are variables that cannot change. They can only be assigned once. Constants that have objects or arrays as values can still be modified because they are assigned by reference. The variables do not hold a value; instead, they point to the location of the object. Example:

However, this will give you an error:

Data Types

Data types have rules for how they can be operated on. For example, if we add two numbers, we get their sum. But if we add a number with a string, we get a string. Here is a list of the different data types:

  • Undefined: a variable that has not been assigned a value
  • Null: no value
  • Boolean: an entity that has the value true or false
  • String: a sequence of characters
  • Symbol: a unique, unchanging key
  • Number: integer and decimal values
  • Object: a collection of properties

A string is a data type that consists of characters. A string will be surrounded with single quotes or double quotes. Strings also have methods you can use to perform actions on them. The following are some examples of actions you can perform on strings.

Determine if a string begins with a substring:

Determine if a string ends with a substring:

Determine if a substring is located anywhere in a string:

Repeat a string a specified number of times:

We can turn a string into an array with the spread operator: ...

Template literals are a special kind of string that use backticks: ` `. We can use them to insert variables within a string like this:

We can create multiline strings like this:

Review

We have seen how to set up our development environment using Node. The first step to programming is writing the steps to solve the problem. This is called the algorithm. The actual code will consist of many statements. Statements are the program’s instructions and are made up of expressions. Expressions are useful in our program if we assign them to variables. Variables are created with the let or const keyword. 

In part 2, I will explain conditionals. 

Resources


A Quick Look at Abstract: Version Control for Sketch

Apparel Designer Must Haves: T-Shirt Design Templates, Photoshop Actions, and More

10 Best React Native App Templates of 2017

How to Get the People You Interview Comfortable Talking

15 Top Logo Sting Templates for Apple Motion, for Your Inspiration

Art Therapy: What It Is and How It May Help You

Friday, September 22, 2017

10 Easy Pieces: Logo Reveals and Video Stings for Broadcast

How to Add a Zoom to Your Drone Video in Adobe After Effects

5 Sketch Courses You Need

International Artist Feature: Jamaica

Teach for Us: Design & Illustration Gurus Wanted!

Teach for Us: Design & Illustration Gurus Wanted!

Do you want to share your design knowledge with an eager community of millions? Are you looking for a way to supplement your income? Would you like to establish yourself as an expert in your field? Well, this may be the opportunity for you.

What We're Looking For

Envato Tuts+ has many areas of content, and while we love a variety of avenues, we're specifically looking for instructors to create written content. The topics we're specifically looking for are:

  • Photo manipulation
  • Product mockups
  • Logo design
  • Text effects
  • Photoshop Actions
  • Adobe Photoshop
  • Procreate
  • Affinity Designer
  • Sketch app

Your area of expertise not listed? We never turn a good application down!

You must also be comfortable with the English language. We can proof your content, but we can't rewrite everything for you. To put it simply, if you struggle when deciding whether to write its or it's, this might not be the gig for you.

We're looking for content from quick tips to in-depth tutorials. Most of all, we want instructors who can explain themselves clearly and accurately and produce quality end results. Whether you're an expert in Adobe Illustrator, Adobe InDesign, Inkscape, Adobe Photoshop, Sketch or any other design package, we want to hear from you!

What Do You Get Out of It?

There are many benefits in becoming an Envato Tuts+ Instructor:

  • Getting paid for a subject you're passionate about is always rewarding. Depending on the content type and subject, you could be billing thousands per month! We pay $250 USD for a standard length tutorial.
  • Get your name out into the community. This is especially good if you're just starting your freelance career.
  • Establish yourself as an expert in your given field by writing regularly for a respected educational network.
  • If you provide assets to Envato Market or Envato Elements, then use this opportunity to help promote your items!

Pitch a Tutorial!

While I can tell you which areas we're specifically looking into, it all comes down to which areas are your strongest and what you feel most confident in teaching. If you are interested in becoming an Envato Tuts+ Instructor, why don't you pitch us an idea? We're looking forward to hearing from you.


How to Handle Important Employees That Want to Quit

Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts

Create Interactive Charts Using Plotly.js, Part 5: Pie and Gauge Charts

If you have been following this series from the beginning, you might have noticed that Plotly.js uses the same scatter type for creating both line charts and bubble charts. The only difference is that we had to set the mode to lines while creating line charts and markers when creating bubble charts. 

Similarly, Plotly.js allows you to create pie, donut and gauge charts by using the same value for the type attribute and changing the value of other attributes depending on the chart you want to create.

Creating Pie Charts in Plotly.js

You can create pie charts in Plotly.js by setting the type attribute to pie. There are also other attributes like opacity, visible and name that are common to other chart types as well. The name attribute is used to provide a name for the current pie trace. This name is then shown in the legend for identification. You can show or hide the pie trace in the legend of a chart by setting the showlegend attribute to true or false respectively. You can set a label name for the different sectors of a pie chart by using the labels attribute.

In the case of pie charts, the marker object is used to control the appearance of different sectors of the chart. The color attribute nested inside marker can be used to set the color of each sector of the pie chart. The color for different sectors can be specified as an array value to the color attribute.

You can also set the color and width of all the lines enclosing each sector using the color and width attributes nested inside the line object. You also have the option to sort all the sectors of the pie chart from largest to smallest using the boolean sort attribute. Similarly, the direction of the sectors can be changed to clockwise or counterclockwise with the help of the direction attribute.

The following code creates a basic pie chart that lists the forested area of the top five countries in the world.

As you can see, we are no longer using the x and y attributes to specify the points that we want to plot. This is now done with the help of values and labels. The percentages are determined automatically based on the input values.

By default, the first slice of the pie starts at 12 o'clock. You can change the starting angle of the chart using the rotation attribute, which accepts a value between -360 and 360. The default 12 o'clock value is equal to the angle 0.

If you want a slice in your chart to stand out, you can use the pull attribute, which can accept either a number or an array of numbers with values between 0 and 1. The pull attribute is used to pull the specified sectors out of the pie. The pull distance is equal to a fraction of the larger radius of the pie or donut.

It is very easy to convert a pie chart into a donut chart by specifying a value for the hole attribute. It will cut the given fraction of the radius out from the pie to make a donut chart.

You can control the color of individual sectors in a pie chart using the colors attribute nested inside the marker object. The width and color of the line that encloses each sector can also be changed with the help of the width and color attributes nested inside the line object. The default width of the enclosing line is 0. This means that no line will be drawn around the sectors by default.

There is also a hovertext attribute, which can be used to provide some extra textual information for each individual sector. This information will be visible to viewers when they hover over a sector. One condition for the text to appear is that the hoverinfo attribute should contain a text flag. You can set the color of text lying inside or outside of the pie sectors using the family, size and color attributes nested inside the insidetextfont and outsidetextfont objects respectively.

The following code uses the data from our previous pie chart to create a donut chart that uses the additional attributes we just learned about.

Creating Gauge Charts in Plotly.js

The basic structure of a gauge chart is similar to a donut chart. This means that we can use some cleverly selected values and create simple gauge charts by still keeping the type attribute set to pie. Basically, we will be hiding some sections of the full pie to make it look like a gauge chart.

First, we need to choose some values for the values attribute. To keep things simple, I will be using the top half of the pie as my gauge chart. This means that the values should be divided equally between the part that I want to be visible and the part of the pie chart that I want to hide. The visible section of the chart can further be divided into smaller parts. Here is an example of choosing the values for our gauge chart.

The number 100 in the above line is arbitrary. As you can see, the first five slices together add up to 100, which is also the value set for the hidden area of the pie chart. This divides the whole pie equally between the hidden and visible part.

Here is the complete code that creates our basic gauge chart. You should note that I have set the color attribute of the sector that should be hidden to white. Similarly, the text and labels values for the corresponding sector have also been set to empty strings. The rotation attribute has been set to 90 so that the chart is not drawn from its default 12 o'clock position.

The next part of the code deals with the needle of the gauge chart. The value that you set for the degrees variable will determine the angle at which the needle is drawn. The radius variable determines the length of the needle. The attributes x0 and y0 are used to set the starting point of our line. Similarly, the attributes x1 and y1 are used to set the ending point of our line. 

You can create more complex shapes for your needle with the help of SVG paths. All you have to do is set the type attribute to path and specify the actual path using the path attribute. You can read more about it in the layout shapes section of the reference.

All the code of this section creates the following gauge chart. Right now, the chart is not very fancy, but it can act as a good starting point.

Final Thoughts

In this tutorial, you learned how to create pie and donut charts using the pie trace type in Plotly.js. You also learned how to carefully set the values of a few attributes to convert those pie charts into simple gauge charts. You can read more about pie charts and their different attributes on the reference page.

This was the last tutorial of our interactive Plotly.js charts series. The first introductory tutorial provided you an overview of the library. The second, third and fourth tutorials showed you how to create line charts, bar charts, and bubble charts respectively. I hope you enjoyed this tutorial as well as the whole series. If you have any questions, feel free to let me know in the comments.


How to Choose the Right Foundation Grid

Thursday, September 21, 2017

How to Find People for a Documentary Interview

24 Awesome Facebook Templates

An Introduction to ETS Tables in Elixir

An Introduction to ETS Tables in Elixir

When crafting an Elixir program, you often need to share a state. For example, in one of my previous articles I showed how to code a server to perform various calculations and keep the result in memory (and later we've seen how to make this server bullet-proof with the help of supervisors). There is a problem, however: if you have a single process that takes care of the state and many other processes that access it, the performance may be seriously affected. This is simply because the process can serve only one request at a time. 

However, there are ways to overcome this problem, and today we are going to talk about one of them. Meet Erlang Term Storage tables or simply ETS tables, a fast in-memory storage that can host tuples of arbitrary data. As the name implies, these tables were initially introduced in Erlang but, as with any other Erlang module, we can easily use them in Elixir as well.

In this article you will:

  • Learn how to create ETS tables and options available upon creation.
  • Learn how to perform read, write, delete and some other operations.
  • See ETS tables in action.
  • Learn about disk-based ETS tables and how they differ from in-memory tables.
  • See how to convert ETS and DETS back and forth.

All code examples work with both Elixir 1.4 and 1.5, which was recently released.

Introduction to ETS Tables

As I mentioned earlier, ETS tables are in-memory storage that contain tuples of data (called rows). Multiple processes may access the table by its id or a name represented as an atom and perform read, write, delete and other operations. ETS tables are created by a separate process, so if this process is terminated, the table is destroyed. However, there is no automatic garbage collection mechanism, so the table may hang out in the memory for quite some time.

Data in the ETS table are represented by a tuple {:key, value1, value2, valuen}. You can easily look up the data by its key or insert a new row, but by default there can't be two rows with the same key. Key-based operations are very fast, but if for some reason you need to produce a list from an ETS table and, say, perform complex manipulations of the data, that's possible too.

What's more, there are disk-based ETS tables available that store their contents in a file. Of course, they operate slower, but this way you get a simple file storage without any hassle. On top of that, in-memory ETS can be easily converted to disk-based and vice versa.

So, I think it's time to start our journey and see how the ETS tables are created!

Creating an ETS Table

To create an ETS table, employ the new/2 function. As long as we are using an Erlang module, its name should be written as an atom:

Note that until recently you could only create up to 1,400 tables per BEAM instance, but this is not the case anymore—you are only limited to the amount of available memory.

The first argument passed to the new function is the table's name (alias), whereas the second one contains a list of options. The cool_table variable now contains a number that identifies the table in the system:

You may now use this variable to perform subsequent operations to the table (read and write data, for example).

Available Options

Let's talk about the options that you may specify when creating a table. The first (and somewhat strange) thing to note is that by default you cannot use the table's alias in any way, and basically it has no effect. But still, the alias must be passed upon the table's creation.

To be able to access the table by its alias, you must provide a :named_table option like this:

By the way, if you'd like to rename the table, it can be done using the rename/2 function:

Next, as already mentioned, a table cannot contain multiple rows with the same key, and this is dictated by the type. There are four possible table types:

  • :set—that's the default one. It means that you can't have multiple rows with exactly the same keys. The rows are not being re-ordered in any particular manner.
  • :ordered_set—the same as :set, but the rows are ordered by the terms.
  • :bag—multiple rows may have the same key, but the rows still cannot be fully identical.
  • :duplicate_bag—rows can be fully identical.

There is one thing worth mentioning regarding the :ordered_set tables. As Erlang's documentation says, these tables treat keys as equal when they compare equal, not only when they match. What does that mean?

Two terms in Erlang match only if they have the same value and the same type. So integer 1 matches only another integer 1, but not float 1.0 as they have different types. Two terms are compare equal, however, if either they have the same value and type or if both of them are numerics and extend to the same value. This means that 1 and 1.0 are compare equal.

To provide the table's type, simply add an element to the list of options:

Another interesting option that you can pass is :compressed. It means that the data inside the table (but not the keys) will be—guess what—stored in a compact form. Of course, the operations that are executed upon the table will become slower.

Next up, you can control which element in the tuple should be used as the key. By default, the first element (position 1) is used, but this can be changed easily:

Now the second elements in the tuples will be treated as the keys.

The last but not the least option controls the table's access rights. These rights dictate what processes are able to access the table:

  • :public—any process can perform any operation to the table.
  • :protected—the default value. Only the owner process can write to the table, but all the processes can read.
  • :private—only the owner process can access the table.

So, to make a table private, you would write:

Alright, enough talking about options—let's see some common operations that you can perform to the tables!

Write Operations

In order to read something from the table, you first need to write some data there, so let's start with the latter operation. Use the insert/2 function to put data into the table:

You may also pass a list of tuples like this:

Note that if the table has a type of :set and a new key matches an existing one, the old data will be overwritten. Similarly, if a table has a type of :ordered_set and a new key compares equal to the old one, the data will be overwritten, so pay attention to this.

The insert operation (even with multiple tuples at once) is guaranteed to be atomic and isolated, which means that either everything is stored in the table or nothing at all. Also, other processes won't be able to see the intermediate result of the operation. All in all, this is pretty similar to SQL transactions.

If you are concerned about duplicating keys or do not want to overwrite your data by mistake, use the insert_new/2 function instead. It is similar to insert/2 but will never insert duplicating keys and will instead return false. This is the case for the :bag and :duplicate_bag tables as well:

If you provide a list of tuples, each key will be checked, and the operation will be cancelled even if one of the keys is duplicated.

Read Operations

Great, now we have some data in our table—how do we fetch them? The easiest way is to perform lookup by a key:

Remember that for the :ordered_set table, the key should compare equal to the provided value. For all other table types, it should match. Also, if a table is a :bag or an :ordered_bag, the lookup/2 function may return a list with multiple elements:

Instead of fetching a list, you may grab an element in the desired position using the lookup_element/3 function:

In this code, we are getting the row under the key :number and then taking the element in the second position. It also works perfectly with :bag or :duplicate_bag:

If you would like to simply check if some key is present in the table, use member/2, which returns either true or false:

You may also get the first or the last key in a table by using first/1 and last/1 respectively:

On top of that, it is possible to determine the previous or the next key based on the provided one. If such a key cannot be found, :"$end_of_table" will be returned:

Note, however, that the table traversal using functions like first, next, last or prev is not isolated. It means that a process may remove or add more data to the table while you are iterating over it. One way to overcome this issue is by using safe_fixtable/2, which fixes the table and ensures that each element will be fetched only once. The table remains fixed unless the process releases it:

Lastly, if you'd like to find an element in the table and remove it, employ the take/2 function:

Delete Operations

Okay, so now let's say you no longer need the table and wish to get rid of it. Use delete/1 for that:

Of course, you may delete a row (or multiple rows) by its key as well:

To clear out the entire table, utilize delete_all_objects/1:

And, lastly, to find and remove a specific object, use delete_object/2:

Converting the Table

An ETS table can be converted to a list anytime by using the tab2list/1 function:

Remember, however, that fetching the data from the table by the keys is a very fast operation, and you should stick to it if possible.

You may also dump your table to a file using tab2file/2:

Note that the second argument should be a charlist (a single-quoted string).

There are a handful of other operations available that can be applied to the ETS tables, and of course we are not going to discuss them all. I really recommend skimming through the Erlang documentation on ETS to learn more.

Persisting the State With ETS

To summarize the facts that we have learned so far, let's modify a simple program that I have presented in my article about GenServer. This is a module called CalcServer that allows you to perform various calculations by sending requests to the server or fetching the result:

Currently our server doesn't support all mathematical operations, but you may extend it as needed. Also, my other article explains how to convert this module to an application and take advantage of supervisors to take care of the server crashes.

What I'd like to do now is add another feature: the ability to log all the mathematical operations that were performed along with the passed argument. These operations will be stored in an ETS table so that we will be able to fetch it later.

First of all, modify the init function so that a new named private table with a type of :duplicate_bag is created. We are using :duplicate_bag because two identical operations with the same argument may be performed:

Now tweak the handle_cast callback so that it logs the requested operation, prepares a formula, and then performs the actual computation:

Here is the prepare_and_log private function:

We are logging the operation right away (the corresponding function will be presented in a moment). Then return the appropriate function or nil if we don't know how to handle the operation.

As for the log function, we should either support a tuple (containing both the operation's name and the argument) or an atom (containing only the operation's name, for example, :sqrt):

Next, the calculate function, which either returns a proper result or a stop message:

Finally, let's present a new interface function to fetch all the performed operations by their type:

Handle the call:

And perform the actual lookup:

Now test everything:

The result is correct because we have performed two :add operations with the arguments 1 and 2. Of course, you may further extend this program as you see fit. Still, don't abuse ETS tables, and employ them when it is really going to boost the performance—in many cases, using immutables is a better solution.

Disk ETS

Before wrapping up this article, I wanted to say a couple of words about disk-based ETS tables or simply DETS

DETS are pretty similar to ETS: they use tables to store various data in the form of tuples. The difference, as you've guessed, is that they rely on file storage instead of memory and have fewer features. DETS have functions similar to the ones we discussed above, but some operations are performed a bit differently.

To open a table, you need to use either open_file/1 or open_file/2—there is no new/2 function like in the :ets module. Since we don't have any existing table yet, let's stick to open_file/2, which is going to create a new file for us:

The filename is equal to the table's name by default, but this can be changed. The second argument passed to the open_file is the list of options written in the form of tuples. There are a handful of available options like :access or :auto_save. For instance, to change a filename, use the following option:

Note that there is also a :type option that may have one of the following values:

  • :set
  • :bag
  • :duplicate_bag

These types are the same as for the ETS. Note that DETS cannot have a type of :ordered_set.

There is no :named_table option, so you can always use the table's name to access it.

Another thing worth mentioning is that the DETS tables must be properly closed:

If you don't do this, the table will be repaired the next time it is opened.

You perform read and write operations just like you did with ETS:

Bear in mind, though, that DETS are slower than ETS because Elixir will need to access the disk which, of course, takes more time.

Note that you may convert ETS and DETS tables back and forth with ease. For example, let's use to_ets/2 and copy the contents of our DETS table in-memory:

Copy the ETS's contents to DETS using to_dets/2:

To sum up, disk-based ETS is a simple way to store contents in the file, but this module is slightly less powerful than ETS, and the operations are slower as well.

Conclusion

In this article, we have talked about ETS and disk-based ETS tables that allow us to store arbitrary terms in memory and in files respectively. We have seen how to create such tables, what the available types are, how to perform read and write operations, how to destroy tables, and how to convert them to other types. You may find more information about ETS in the Elixir guide and on the Erlang official page.

Once again, don't overuse ETS tables, and try to stick with immutables if possible. In some cases, however, ETS may be a nice performance boost, so knowing about this solution is helpful in any case. 

Hopefully, you've enjoyed this article. As always, thank you for staying with me, and see you really soon!