Everyone knows the DRY acronym: "don't repeat yourself". But another one I try to keep in mind is KISS: "keep it simple, stupid!"

When I first built my word and character counter, I overcomplicated it. Trying to avoid any form of repetition whatsoever, I created a single function that could count words and characters:

/**
* Count the number of words/characters in a form control
* @param {Object} element The element whose words/characters should be counted
* @param {Boolean} countChars Whether to count words (false) or characters (true)
* @returns {Number} The word/character count
*/

function countWordsOrChars (element, countChars) {

// Bail if the element doesn't exist
if (!element) return;

// If counting charaters, get the count
// Otherwise, trim any whitespace
var count = countChars ? element.value.length : element.value.trim();

// If no words/characters, return zero
if (!count) return 0;

// If counting words, get the count
// (counting words as separated by 1 or more whitespace characters)
if (!countChars) count = count.split(/\s+/).length;

// Return the count
return count;

}

I made the code more complicated than it needed to be.

This reminds me of the quote I shared in Rethinking DRY:

As Harry Roberts says, “DRY is often misinterpreted as the necessity to never repeat the exact same thing twice. This is impractical and usually counterproductive, and can lead to forced abstractions, over-thought and over-engineered code.”

We kicked off a new session of the Vanilla JS Academy last week, so I decided to rethink my approach. I opted for two separate functions this time: one for counting words, and one for counting characters.

/**
* Get the number of words in a text area
* @param {Object} textArea The text area
* @returns {Number} The word count
*/

function getWordCount (textArea) {

// Trim whitespace from the value
var value = textArea.value.trim();

// If it's an empty string, return zero
if (!value) return 0;

// Otherwise, return the word count
return value.split(/\s+/).length;

}

/**
* Get the number of characters in a text area
* @param {Object} textArea The text area
* @returns {Number} The character count
*/

function getCharacterCount (textArea) {
return textArea.value.length;
}

This is so much better! Two separate functions, each with its own job. This is called the single-responsibility principle.

Keep it simple, stupid!