Category Archives: In A Nutshell Series

CLEAN CODE IN A NUTSHELL

What is clean code?  How do you write clean code?  I will attempt to address these questions in this “In a Nutshell” series blog post.

Clean Code In a Nutshell:

  • The crux of it is: Clean code is code that is written in a way that is easily understandable, readable and maintainable by other Humans.
  • Key aspects of clean code:
  1. It is DRY (does not repeat unnecessarily)
  2. Concise (but not too concise!)
  3. Tells a story to the reader in a logical sequence about what is happening in the code
  4. Incorporates the SRP principle and Separation of Concerns
  5. Is easily maintainable (modular) and does not make the person who is reading and working on it want to pull their hair out

That’s basically what it means to write clean code.  For further explanation and examples, continue reading…

Definitions:

  • Code Smell: This refers to code that is not clean and “smells”.  There is something about the code that is unnecessarily confusing, unclear or something that could be improved upon to make it cleaner.
  • DRY: The “Don’t Repeat Yourself” principle.  The goal is to eliminate as much repetition of code as possible and re-use as much code as possible, which keeps things less cluttered and clean.
  • SRP: The “Single Responsibility” principle.  A method, object or class should do one thing and do it very well.  This makes things easier to maintain and keeps things de-coupled.
  • Separation Of Concerns: Code should be logically grouped based on what operations it is performing or data it is related to.  Methods in classes and objects should be closely related to each other and separated.
  • Spaghetti Code: This is code that is not separated logically and is not modular.  It is very difficult to maintain and understand and is usually heavily coupled (the code is connected to and affects many other parts and operations in the application) so that changing one line may have unforeseen side effects on all sorts of other parts of the code base.  It is a nightmare to deal with and the opposite of clean code.

METHODS FOR WRITING CLEAN CODE (and what to avoid doing):

 

NAMING VARIABLES:

  • Names for variables should not be ambiguous, but be descriptive and meaningful.
  • Magic Numbers and Magic Strings: Strings or Numbers usually used as variable names which do not indicate to the reader of the code what their purpose, origin or use is related to.  Don’t do this.  Always make variable names descriptive and meaningful so it’s clear to the reader what they are for and doing.
  • Make naming formats consistent.  If related variables are in camel case, then make sure all of them are in camel case, or if there is a word that is appended or prepended to related variables, make sure you keep using that format.
  • Follow naming conventions in whatever language or framework you are using.  For example, in C# the names of classes, it’s properties and methods use Pascal Case while private fields, method parameters(arguments) and local variables use Camel Case.  In React, all component names and classes should have the first letter capitalized.
  • Try not to use names that are too long or hard to read.  Keep them short (but not too short).

Examples:

// Avoid: Ambiguous variable names:
const x = "Please log in.";
// Cleaner:
const loginMessage = "Please log in.";

// Avoid: Magic Numbers and Strings:
if (userStatus === 1) {
  return true;
}
// Cleaner:
const loggedIn = 1; 
if (userStatus === loggedIn) {
  return true;
}

// Avoid: inconsistent naming:
const username = "Brent";
const user_profile = false;
// Cleaner:
const userName = "Brent";
const userProfile = false;

// Avoid: really long and hard to read names:
const loginUserAndFetchDataFromDatabaseAndUpdateTheReduxStore =  () => { ...code );
};
// Cleaner: use the SRP and Separation of Concerns principles: 
const loginUser = () => { ...code };
const fetchUserData = () => { ...code };
const updateStore = () => { ...code };

METHODS, OBJECTS, CLASSES (SRP and Separation of Concerns):

  • Keep methods short and have them do only one thing!  Methods should do one thing and do it very well (have a single responsibility).  There are differing opinions on how long methods should be, but the goal is to make them as short and as contained as possible.  Some say they should not be more than 10 lines of code.   Just try to make them as short as possible without making the code hard to understand.
  • If methods get too long, look for ways to extract parts of the code to a separate object or function that you use inside the method.
  • Cohesion Principle: All code that is related closely should be together and code that is not should be separated.  Objects and classes should contain data and methods that relate to each other and only have to do with the data or operation that the object/class is concerned with (Separation of Concerns).
  • The Information Expert Principle (or similarly the Encapsulation principle) states that a method should be attached to the class or object that has the related data which it uses (similar to the Cohesion Principle).
  • The number of parameters should not exceed three.   You can extract parameters and batch them in objects or encapsulate them to reduce the number of arguments.  If possible, also avoid using booleans as parameters.
  • Variables should be declared as close as possible to where they are being used so the reader does not have to search around to find where they are defined.

Examples:

// Avoid: long methods and functions with too many parameters and doing more than one thing...
function fetchUserDataAndLoginUser(loggedIn, userId, db, userProfile, userPassword) {
  let userData = {};
  if (!user.loggedIn) {
     ... 
     lots of code to login user on the back end
     ...
     ...
     ...
     userData = db.find({ user: user.id });
     ... 
     lots of code to load userData into a profile view
     ...
     ...
  } else {
 window.location.replace("https://site.com/dashboard"
);
  }
}

// Cleaner (separate the operations into separate functions to use and combine the arguments into a single encapsulated object):

const user = {
   userId,
   userProfile,
   userPassword,
   loggedIn 
};

function authenticateUser(user) {
  ...code for checking passwords and authenticating the user.
}

function fetchUserData(userId, db) {
  ...code for fetching authenticated user data from the database
}

function renderUserData(userData) {
  ...code to render the userData on the view.
}

authenticateUser(user, db)
  .then(user => {
    fetchUserData(user.id, db);
  })
  .then(userData => {
    renderUserData(userData);
  });

// Note how the code now tells a story in a logical succession to the reader and each method only deals with one thing and part of the process separately.  The user is logged in and authenticated, then their data is fetched from the database, and then the data is rendered to the view.  
// The code is also easier to maintain because if there is a point of failure along the way, the developer can look in the appropriate method dealing with the failing operation and pinpoint and debug quickly and easily which step is failing.

CONDITIONALS (IF/ELSE STATEMENTS):

  • Keep conditional statements as flat and easy to understand as possible by using refactoring techniques and avoiding common pitfalls.
  • A Nested Conditional is an if/else statement contained within another if/else statement.  Avoid them: they are difficult to read, understand and test.
  • There are circumstances in which nested conditionals can be refactored by considering the relationship of the conditional parameters between the statements.  (See examples below).

Examples and ways of refactoring conditionals:

Use a Ternary Operator:

// Not nested, but easily refactored to make the code cleaner and more readable:
  if (user.id) {
    userLoggedIn = true;
  } else {
    userLoggedIn = false;
  }
// Cleaner:
userLoggedIn = user.id ? true : false;

// NOTE: Never combine ternary expressions and only use one - multiple ternary expressions are too difficult to understand and read.

If the statement sets a Boolean to a variable based on the condition, you can simplify it by setting the variable to the condition in a single line eliminating the if/else statement:

// Avoid: Unnecessary if/else statement:
if (userLoggedIn) {
  showProfile = true;
} else {
  showProfile = false;
}
// Cleaner: showProfile is simply dependent on the value in the condition...it can be refactored to:
showProfile = userLoggedIn; 

Watch out for nested if statements that a single block is based on. Use the && operator or early exit technique to refactor:

// Avoid: nested if statement inside a single block:
if (user) {
  if (user.id) {
    ...code
  }
}
// Cleaner: refactor using the && operator to eliminate the nested if statement:
if (user && user.id) { ...code } 

// Or use the early exit technique to return if a or b is not true to eliminate nesting:
function verifyUser(user) {
  if (!user || !user.id) {
    return;
  }
  ...code to run if user and user.id are true
}

Refactor nested if statements that have repeated conditions to combine them with logical operators:

// Avoid: Nested conditionals with identical conditions:
if (userIsGoldMember) {
  if(itemsInCart) {
    applyDiscount = true;
  }
}
if (totalCost > 100) {
  if (itemsInCart) {
    applyDiscount = true;
  }
} 
// Cleaner: combine the identical conditions and variant conditions with logical operators to eliminate the nested conditional:
applyDiscount = (itemsInCart && (totalCost > 100 || userIsGoldMember));

Make conditions more expressive by extracting the condition to return a boolean in a separate function:

// Avoid: conditions that are complicated and not easy to read quickly:
if (Date.now() >= (new Date(2018, 11, 25).getTime() + 24 * 60 * 60 * 1000)) {
  ...code
}

// Cleaner: separate the condition into a function that returns true or false and describes what the condition is clearly:
const dateIsAfterChristmas = () => {
  return (Date.now() >= (new Date(2018, 11, 25).getTime() + 24 * 60 * 60 * 1000))
};

if (dateIsAfterChristmas()) {
  ...code
}

Refactor Triplicate conditionals: A triplicate occurs when one of multiple conditions is required.  Use the || operator instead of if statements:

// Avoid: separate if conditionals for a triplicate:
if (condition1) {
  return true;
}
if (condition2) {
  return true;
}
if (condition3) {
  return true;
}
return false;

// Cleaner: use the || operator:
return condition1 || condition2 || condition3;

COMMENTS:

  • Comments should not be redundant or stating what is obvious in the code – it just makes more clutter in the code base.
  • Ideally, you shouldn’t need comments since the code you are writing tells a story and it is clear and easy to understand what is going on.  There are differing opinions on this and I think it is a good rule of thumb to follow most of the time.  In reality, there may be a situation where comments would be very helpful to the reader (i.e. when the code is written in an unintuitive way that is necessary, and refactoring would cause breaking changes).
  • If you need to write a comment, don’t write comments addressing “whats” (what the code is ‘saying’, so to speak), write comments that address “whys” and “hows” (why this code is the way it is or how it is doing some operation).
  • Minimizing comments is also a good idea because developers may change logic in the code base, but not update the comments which can cause confusion in the future.
  • The exception to leaving out comments is the case of making a `TODO` note;  These are good comments when a problem in the code is found and a note needs to be left for an issue that needs to be fixed and addressed.
  • If you see comments for blocks of code describing operations in a method, that is a sign that it should be refactored and the operations should be extracted into separate methods.

FURTHER READING AND RESOURCES: 

JavaScript Quirks In a Nutshell

When I was first learning JavaScript I would come across posts about how weird (or bad) the language was, and since it was the first programming language I learned and didn’t have anything else to compare it with, I didn’t understand why some people had a negative opinion of the language.

This is an attempt to assemble  a list of those JavaScript quirks that give it a bad wrap, and were confusing to me when I was learning, as well as key concepts that are vital to understand in order to write good (i.e. working) JavaScript code.  My goal is to create a concise list that would be helpful for those learning the language to reference in order to understand some of the “weird” behavior of JavaScript, and how to use the language more effectively while not having to learn these things “the hard way”, or learning them way too late.  The list is meant to be an overview to make the student aware of these things and serve as a launching point for further exploration and research.

NOTE: This list is a work in progress and constantly expanding.  It will be updated and is under construction, so if there are other quirks or important concepts that you would like to see included that would help one write more informed and well-written JavaScript code, drop a note in the comments section.  It would be great to have a one stop shop that has as many of the quirks and confusing things about JavaScript in one place for people who are learning to have as a reference.

Table of Contents:

  • …more to come

THE CREATION AND EXECUTION PHASE:

  • When the JavaScript Engine runs in the browser, it runs in two phases – a Creation Phase and an Execution Phase.
  • A Creation Phase and Execution Phase is run every time the JavaScript for the app initially loads to create the Global Execution Context, and also runs for each successive call to any function to create that function’s Execution Context.
Terms:
  • Creation Phase:  All variable names (including the built-in this variable), objects and functions are created and stored in memory for use in the Execution Phase.  For example, on an app initialization (first load), the global window object is created and variable names, as well as functions in the code are created, stored in memory space and attached to the global window object.  A Global Execution Context is created and the this keyword is created and setup.  In addition, an outer reference to the immediately outer Execution Context is set up which allows access to variables and objects in that context (In this case there wouldn’t be an outer context, since the global context is the top most level).
  • Execution Phase:  The JavaScript code is then run and executed, line by line, without stopping or pausing.
  • Execution Context:  The environment that is created during the Creation Phase that the JavaScript code runs inside of during the Execution Phase.  It defines the variables, objects, functions and function arguments which are available and accessible, as well as the scope chain, and the this value.

*A new Execution Context is created for every function that runs in JavaScript which entails running through a Creation and Execution Phase for it, and setting up an outer reference to the immediately surrounding Execution Context which allows access to the outer context’s variables and objects (see Scope Chain below for more details). 

  • Execution Stack:  A model or data structure in the JavaScript engine which keeps track of the order of the execution of code and it’s current Execution Context.  Every time a function is called in the code, a new Execution Context (or Call Stack) is created and placed at the top of the Stack.  JavaScript is a single threaded language (which means it runs one call stack at a time).  When the execution of the function is completed, that Execution Context is “popped” (removed) off the top of the Stack, and the code of the previous Execution Context on the Stack beneath it is run, picking up from where it left off from before the code from the popped Execution Context began running.  (Further resources: see this great Youtube video lecture on the Call Stack and the Event Loop)

HOISTING:

  • Refers to the storing of functions and variables in memory by the JavaScript engine during the Creation Phase (see above) before the code actually runs.   All variables are initially stored and set to a value of ‘undefined’, but all functions are stored complete in memory (including the declaration of their name as an identifier for a space in memory to look, and their value (the body of the function, etc.)).
  • This is why you can define a function in your code AFTER you actually call it, but variables will return undefined if they are referenced before their declaration in the code.

Example:

// Calling the function in the code before it's defined:
hoistedFunction();

hoistedFunction() {
  console.log("The function ran and worked!");   
}

In the above Example, the call to hoistedFunction() will log "The function ran and worked!" even though it is called before it is defined.  This is because during the Creation Phase, all functions defined in the code are “hoisted” into memory and made available before the code actually is run in the Execution Phase.  Note that this is different from variables, which are initially set to undefined and cannot be referenced before they are assigned in the code.


THE SCOPE CHAIN:

  • If a variable is used in a function and a value is not found for it inside that function’s scope or block, then JavaScript will look for it’s value in the function’s outer environment context.  If the value is not found there, then it will search the environment of the next outer context, and keep going all the way to the global environment to look for the value for the variable.
  • It should be noted that looking for an outer scoped variable’s value stops when the first match is found.
  • It’s possible to access a variable directly on the global scope with window.[variable name].
  • Lexical Scope:  Scope that is assigned based on where variable and function declarations are written in the code (i.e. functions written inside other function body blocks, variables declared in the global space outside of any function blocks, or inside a function’s scope because they are declared in the body, etc.).

Example of traversing the scope chain:

// a variable created at the top level execution context (global):
const globalVar = "from top level";
// Execution Context is created for initial function:
const exampleFunction = function() {
  const outerVar = "from outer context.";
   // A new Execution Context is created when this inner function runs, but it has access to the immediate outer context it's created in, and also the outer context of it's outer context up the scope chain to the top global level, etc.:
  (function() {
    console.log(outerVar); 
    console.log(globalVar);   
  })();
}

exampleFunction();
// When called, the function logs "from outer context" and then "from top level" - the JS Engine went up the scope chain to find outerVar and globalVar and look for it's value all the way up to the top level global context since they were not defined and assigned a value in the inner function block.

*NOTE THIS QUIRK:  When not in strict mode (‘use strict’), if a variable is not declared with var/let/const but assigned a value, then a variable of that name will be automatically created and implicitly declared in the global scope.

Example:

undeclared = 5;

// A global variable undeclared is created and assigned the value of 5 automatically by JavaScript.
NOTE: If 'use strict' is implemented, then a ReferenceError will be thrown and automatic declaration will not occur.

eval():

  • Built in function in JavaScript that takes a string as an argument, and treats the contents of the string as code that was authored code at that point in the program, consequently altering the corresponding Lexical Scope.
  • Can be used to execute dynamically created code (that’s not
    hard coded initially).
    In other words, you can dynamically generate code that is not hard coded at author time and eval() will inject it as if it were hard coded at author time – this is a way to cheat Lexical Scope (code that is scoped based on where it was authored), but has performance issues and is bad practice.
  •  If a string of code that eval(..) executes contains variable or function declarations, the existing lexical scope in which the eval(..) resides will be modified.
  • Note from reference book listed below: “The use-cases for dynamically generating code inside your program are incredibly rare, as the performance degradations are almost never worth the capability.”

Reference: You Don’t Know JS: Scope & Closures, Chaper 2.


PRIMITIVE TYPES:

Terms:
  • Type:  A category identifier for a piece of data which can be used by the JavaScript engine to determine how to handle the piece of data and what operations can be performed with it. For example, a Number type is assigned to a piece of data that is represented by an integer.  Since the data has a type of Number, JavaScript knows that it can do things like arithmetic with it and another piece of data of the same type, etc.
  • Primitive Type:  Represents a single value in JavaScript that is not an Object type.  (Everything in JavaScript is either a Primitive or an Object).
  • DYNAMIC TYPING:   JavaScript is a dynamically typed language.  The engine figures out and determines what type of data a variable holds (without having to declare it explicitly) while the code is running.  It’s possible for a variable to hold different types of values while the code is running.  You don’t specify what type of data is in a variable (you just use var/const/let, and JavaScript figures out what it is – a Number, Boolean, String, etc.).

6 Primitive Types:

  • Undefined: lack of existence (don’t use this or set variables to this)
  • Null: lack of existence – use this to set variables to nothing (let the engine use undefined). Null is not coerced by JS to 0 for comparisons, but coerced to 0 in other contexts (i.e. with Number() function).

*What is the difference between NULL and UNDEFINED?

null is read by JavaScript to mean that there is no value, but the developer intends it that way and set it to null explicitly (i.e. let x = null;), whereas undefined may throw an error as being an unintended absence of value from not assigning anything to the variable (i.e. let x;), and then accessing it (i.e. console.log(x); ), or by simply not declaring it at all in the first place.  Setting a value to undefined explicitly is not considered good practice.  If you want a value to be assigned as undefined or empty, then set it to null in the code.

  • Boolean:  A primitive that has a value of true or false.
  • Number:  An Integer or floating point number (decimal), i.e. 5 or 5.23 etc.
  • String:  Sequence of characters inside quotes (single or double).
  • Symbol (used in ES6 ):  May not be supported by some browsers.

THE EVENT LOOP:

Terms:
  • Event Loop:  A constantly running process that checks a Task Queue for any callbacks registered which are associated with asynchronous operations or Event Listeners, and pushes them to the Execution Stack whenever it is empty.
  • Task Queue: A built-in feature of the Event Loop that keeps track of and stores registered callbacks for any asynchronous operatons (network requests for example) or Event Listeners (for a ‘click’ Event when a user clicks a specified button for example) which are ready to be run and awaiting a push to the Call Stack from the Event Loop.
  • Web API:  Features and methods that come built-in from the browser and that are provided and made accessible to the JavaScript Runtime Engine  so you can access them in your JavaScript code.  Examples are multi-threaded operations made available by Web API methods such as setTimeout() or AJAX requests over the wire using the XHR (XmlHttpRequest) Object provided by the browser.  Javascript is a single-threaded language, so these features and methods allow access to additional threads which can be used to perform longer-running operations while not blocking the running of JavaScript code.
  • Thread:  A line (or “thread”) of instructions sent to a processor from an application. The set of instructions can be abandoned and come back to later where the processor left off with them last and then complete them (called context switching).
  • Execution Stack (aka Call Stack, or just Stack):  see Creation and Execution Phase entry above).
  • Callback:  a function that is registered to run when an asynchronous operation completes.  These are collected in the Task Queue, which the Event Loop constantly checks to push them to the Stack to run.
  • Event Listener:  A feature which can be accessed in JavaScript code with [element].addEventListener([event], [callback]) that registers a callback function to be run when a specified event occurs.  The browser throws events that can occur which are associated with HTML elements in the DOM as the user interacts with the application (i.e. a ‘click’ event is thrown by the browser when a user clicks on a button element on the page).  The callback registered is then pushed to the Task Queue when the event occurs and the Event Loop will see it and run the callback.

What the Event Loop does:  It’s job is to look at the Task Qeue and the Execution Stack in the JavaScript Runtime and if the Stack is empty, and there is anything (i.e. any callbacks registered) in the Task Queue, then it pushes that callback function to the Execution Stack for JavaScript to run it.


CLOSURES:

  • A closure is a feature of JavaScript which enables a function that is called outside of the scope it was created in (and after that scope’s execution context is cleared from the Stack) to have access to variables and values that were created in it’s original lexical scope (the function block where it was defined).
  • Basically, it’s an encapsulation of values and variables from a scope where a function was defined, so that when that function is passed as a value and called outside of that scope (i.e. returned and used elsewhere in the code), those variables and values remain accessible to it and their values in tact and defined as they were in the original scope.
  • Closures are a commonly used feature whenever you want to pass functions as values to be called at a later time in the code which maintain references to variables in the scope they were created in, and are also used in creating JavaScript Modules, for example, where you can expose methods on a returned object that have references to private, protected, internally defined and scoped variables by invoking a wrapper function which creates a closure, encapsulating those variable values which the exported object methods can reference.
  • IIFE’s (Immediately Invoked Function Expressions) can be used to create a scope and consequently a closure (this can be useful in a for loop, for example to capture the value of i).

Example Use Case with Asynchronous operation in a for loop using a Closure to capture the value of i:

for (var i = 0; i <= 5; i++) {
   (function(i) {
      fetch(`/page${i}`)
        .then(() => {
           console.log(`fetched page ${i}`);
        });
   })(i);
}
// The value of i will be encapsulated by the IIFE on each loop iteration and a reference maintained to it in the asynchronous callback (otherwise the value of i would always be the terminal value since the async function callback runs after the loop is finished and references the value of i at that time.

REVEALING MODULE PATTERN Use Case:

function userModule() {
   const username = "Brent";
   const eyeColor = "brown";

  function username() {
   console.log( username );
  }

  function eyeColor() {
    console.log( eyeColor );
  }

  return {
   username: username,
   eyeColor: eyeColor
  };
}
// Invoke the function to create a closure:
const user = userModule();

user.username(); // "Brent"
user.eyeColor(); // "brown"

// The userModule invocation exposes functions in that module that utilize closures to retain references to private protected variables and values which can be accessed when the exposed functions are called outside of the context they were defined in.

‘USE STRICT’:

  • By typing 'use strict;' in your code, this changes JavaScript’s un-opinionated, loose rules and flexible behavior by preventing type coercion and requiring more explicit syntax.
  • Considered good practice to implement in production code in order to catch potential errors.

Examples of behavior with ‘use strict’:

'use strict'; 

a = 1; // throws an error since var, let, const is not used to declare it. 

17 = '17'; // will throw an error since type coercion is turned off and the string '17' will not be converted to a number or vice versa.

// When calling a function the shorthand way (instead of using fn.call()), this is set to undefined in strict mode:

fn("arg"); // this is undefined.

// Normally when not using strict mode, this is set to the window object in a shorthand function call.
// See this article recommended by Dan Abramov:
Understanding Javascript Invocation and "this" by Yehuda Katz

MISC:

  • Everything in JavaScript is an Object or Primitive data type.
  • JavaScript compiles (translates the human readable code to machine code that the computer can understand and execute) just before execution, as opposed to other languages which are compiled well before.

External Resources/Further Reading:

  • You Don’t Know JS: Up & Going by Kyle Simpson – an excellent book series on Javascript to gain a more sophisticated understanding of how the language works – but written in a way that’s not to dense or difficult to digest.  E-book format is free to read online.
  • wtfjs.com – Funny website with many examples of strange JavaScript behavior.
  • Good article on Scope and THIS – from Digital Web Magazine by Mike West.

 

…More Items Coming… This list will continue to be updated.

Items planned for future updates:

  • Type Coercion
  • truthy and falsy concept and rules
  • Logical Operators
  • Comparisons
  • This keyword
  • New keyword
  • Prototypal Inheritance
  • The Prototype Chain
  • ES6 Classes
  • Promises
  • Synchronous vs. Asynchronous execution
  • Web APIs that add features and asynchronous functionality to JavaScript

Regular Expressions in a Nutshell

So, you want to validate an email that a user entered into a form to make sure that it is correctly formatted.  No problem, just use a Regular Expression to do this, like the following:

/^(?("")("".+?""@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-zA-Z])@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,6}))$/
What in the Sam Hill…???

If this was your response (like mine was when first discovering Regular Expressions), then this article is an attempt to demystify and decrypt this mess and explain it in a nutshell, and serve as an introduction to the topic.

Regular Expressions In a Nutshell:

  • In a Quora article about what the most useful and underrated skill in Computer Programming is, Jaime Potter responded that it’s knowing how to use Regular Expressions well.  He posted a picture diagram breaking down the components of a Regular Expression, which I think will best represent them in a nutshell (all credit goes to him as the source of this image diagram):

  • Typically, you would take a Regular Expression (like the one above) and use a matching method (like the preg_match() function in PHP) to see if a specified string matches the search patterns defined in the Regular Expression.  Common use cases  would be validating user submitted form data (for example, an email or address).

Definitions:

  • Regular Expression:  (paraphrased from Wikipedia) A sequence of characters that define a search pattern typically used to find, find and replace, or validate part or all of a string.   (Also referred to as regex or regexp).
  • Delimiter: A character or symbol that identifies a set of data or string of text as complete and separate.  Used to indicate or designate a group of characters or strings in code that are related to each other or an associated task, and to designate a complete statement or group of statements.  In Regular Expressions, the delimiter is the ‘/‘ at the beginning and end which contain it.  Another example would be the ‘;‘ at the end of a statement (i.e. let x = 5;).

REGULAR EXPRESSIONS CHEAT SHEET:

To get started, see this quick reference sheet that I discovered in the User Contributed Notes section of the preg_match() documentation on PHP.net.  This very helpful comment was made by a user named ‘force at md-t dot organd lists out a cheat-sheet for Regular Expression match patterns:

[abc]     A single character: a, b or c
[^abc]     Any single character but a, b, or c
[a-z]     Any single character in the range a-z
[a-zA-Z]     Any single character in the range a-z or A-Z
    Start of line
    End of line
\A     Start of string
\z     End of string
.     Any single character
\s     Any whitespace character
\S     Any non-whitespace character
\d     Any digit
\D     Any non-digit
\w     Any word character (letter, number, underscore)
\W     Any non-word character
\b     Any word boundary character
(...)     Capture everything enclosed
(a|b)     a or b
a?     Zero or one of a
a*     Zero or more of a
a+     One or more of a
a{3}     Exactly 3 of a
a{3,}     3 or more of a
a{3,6}     Between 3 and 6 of a

options: i case insensitive m make dot match newlines x ignore whitespace in regex o perform #{...} substitutions only once

Typical Use Example of Regular Expressions:

  • Validating user submitted form data, such as usernames, emails and addresses, etc. 

For example, to make sure that an email entered is in the correct format (i.e. ‘[email protected]’),  you can use a Regular Expression to define a search pattern that matches the valid email format, and then check to see if the user submitted email matches the pattern (in PHP, you can do this using the preg_match() method which will return 1 if the string matches the pattern defined in the regex).

Example:

$email = $_POST['user_submitted_email'];

$regexp = '/^[^0-9][_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/';

if (preg_match($regexp, $email)) {
    // process user submitted email;
} else { 
    // Error: email is not in a valid format;
}

Further Reading:

See this one page tutorial on Regular Expressions.  This is from a great site that could be considered a one stop shop for all things Regular Expression related at https://www.regular-expressions.info.  The site breaks down how to use Regular Expressions in a thorough and comprehensive, but digestible manner.

BONUS TIP:

Event Bubbling in a Nutshell

When reading through Stack Overflow posts having to do with Javascript, I sometimes came across the term Event Bubbling and never knew what it was really.  I decided to sit down and spend some time learning about it so I wouldn’t be puzzled anymore by it.  My main learning resources were two excellent Youtube tutorial videos:  Javascript Event Capture, Propogation and Bubbling by Wes Bos and Event Bubbling by The Net Ninja.   This is an excellent article as well on the topic.  I recommend you at least watch the Youtube tutorials, but I am going to attempt to boil the subject down into a single post here.

Event Bubbling In a Nutshell:

  • Events (such as ‘click’ events, for example) are registered not only by the target element where they originate, but by all of that element’s parents all the way up to the global element (i.e. the Window/Browser).
  • An Event occurs (a ‘click’, for example) and the click event is registered (this means recorded or noted and recognized by the browser).  The registered click event then goes from the Window Object down through the child elements and is registered on each during a ‘Capture Phase’ (<html> –> <body> –> <div> –> <form> –> <button>, for example) to find the Target Element (where the click event originated from, i.e. what element was clicked).  Once the click event has registered on the Target (‘Target Phase’), it then bubbles back up the DOM Tree (‘Event Bubbling Phase’) and is registered on all parent elements up through the Window Object triggering any Event Listeners or Handlers in the process.

Why it’s important to understand: 

  • To avoid unintentional Event Handle triggering on parent elements of the target, or to intentionally incorporate handling the event on a parent element. 
  • If there are any identical Event Listeners on the parent elements of the Event Target, then their respective Event Handlers will be triggered.  A click event on element A will trigger element A’s Event Handler as well as Element A’s parents’ Event Handlers for a click event.  

For more information and examples, keep reading:

Definitions:

  • Window Object: My non-technical understanding is to just think of it as the browser or the window you have open in the browser.  It contains all of the elements on the page.
  • Event Target:  The element that the Event originated from (i.e. the element that was clicked, for example).
  • Event Capture: The process of recording events that occur starting at the top of the DOM (the Window Object) and down through the parent elements related to the Event Target.
  • Event Propagation: To propagate, literally means to spread and promote widely.  The event is ‘spread widely’ and registered throughout the DOM tree from the top (Window Object) down to the event target, and back up to the top again.
  • Event Bubbling: The process in which the Event is registered on each successive parent element of the Event Target element all the way up to the Window Object.
  • Event Target Phase: This occurs in between the Capture and Bubbling Phase during Event Propagation.  During this phase, any listeners on the Event Target for the Event and their respective functions will be triggered and invoked.

The Process:

Event Bubbling happens in the course of what’s called Event Propagation, which has three main parts:

  • The Capture Phase: The event is recorded from the top of the DOM and down to find the event target.
  • The Target Phase: The Event is registered on the Target (the element it originated from) and any Listeners or Handlers are fired.
  • The Event Bubbling Phase:  After the Capture and Event Target Phase, the event is registered on each parent element of the Event Target, in order, up through the DOM Tree to the Window Object.

Important Note: Branch paths in the DOM for Events during Event Bubbling are static:  If the DOM tree is modified after the Event Listeners have been assigned, the modified DOM tree or added elements will not be used or included in the Event Bubbling process.

For example, if the handling of the Event involves creating/appending/inserting an additional parent element of the Event Target, then the inserted parent element will not register the Event as it bubbles up the DOM tree on future click events originating from the Event Target.  The Event will bubble only up through parent elements present in the DOM Tree when the Event Listener for that target was assigned (for instance, at the loading up of the page).

Additionally, an Event Listener that is assigned to a class of elements will not be applied to any elements of that class that are later added to the DOM Tree.

Scenarios Where Understanding Event Bubbling Can Help:

Example (consider the following HTML which contains a list of items with buttons that give the user the option to remove the item from the list, or add an item to the list):

<div>
  <ul id='theList'>
     <li id='item_copy'>List Item
       <button class='btn_remove'>Remove</button>
     </li>
     <li>List Item
        <button class='btn_remove'>Remove</button>
     </li>
  </ul>
  <button id='btn_add'>Add Item</button>
</div>

Now, the Javascript to assign Event Listeners and Handlers:

// Add a list item to the list when Add Item clicked:
<script>
const parent_el = document.getElementById('theList');
const li_content = document.getElementById('item_copy').innerHTML;
const add_btn = document.getElementById('btn_add');

add_btn.addEventListener('click', () => { 
    let created_li = document.createElement('li'); 
    created_li.innerHTML = li_content;
    parent_el.appendChild(created_li); 
});
// Assigns click event listener and handler for the remove buttons currently on the page: 
const remove_btns = document.getElementsByClassName('btn_remove');

// A click on .btn_remove removes item from the list: 
 Array.from(remove_btns).forEach(function(btn) {
     btn.addEventListener('click', (e) => {
     let target_btn = e.target;
     let li_to_remove = target_btn.parentElement;
     li_to_remove.remove();
     });
 });
</script>

In the above example, the remove buttons will not work on list items that are added by the user with the Add Item button.  The reason is because when the Event Listeners were assigned to the Remove buttons, the DOM  Tree did not include the added list items created when the user clicks Add Item.  So the Event Listeners and click handlers don’t exist on the newly created list items.

This is where Event Bubbling can come in to save the day.  You use this process to your advantage to solve this problem by assigning the Event Listener and Handler for the click to the parent element of the user added list items (this would be the <ul> with the id of “theList”).

This way when the user clicks on the remove button on the newly created list item, the click event will bubble up through the parent elements and the Event Listener on <ul> “theList” will be ready and waiting for it.  Once the click on the newly added remove button registers on <ul>, it’s target can be found and the remove element function fired.

Example:

 // Grab the pre-existing parent element (<ul>): 
 const the_List = document.getElementById('theList');
 // Add the listener to #theList and pass in the 
    event:
 the_List.addEventListener('click', (e) => {

 // Check to see what the Event Target of the caught    
    click was.
 // If it was the remove btn, then remove the list
    item:
 if (e.target.className == 'btn_remove') {
     let list_item = e.target.parentElement;
     list_item.remove();
     }
 });

Now, the list items added by the user after the page loads will be removed when the user clicks the remove button.  The <ul> ‘theList’ catches the click event as it bubbles up the DOM tree and handles it by finding the Event Target (the remove button clicked) and removing the parent element of it (the list item).

Hopefully, this summary on Event Bubbling will prove to be helpful to those wanting to get their feet wet in the subject and start to understand what it is and how understanding it can help solve problems like this that come up in your code.

OBJECT ORIENTED PROGRAMMING IN A NUTSHELL

This post is a brief overview of the fundamentals and principles of Object Oriented Prgramming (OOP).  It is a summary of my notes from an online course in PHP (see end of article for reference), so most of the examples are in PHP, but the principles are universal to OOP.

OOP In a Nutshell:

  • OOP (Object Oriented Programming) refers to a method of programming that works with data which is  grouped into a set called an ‘Object’.   
  • The Object can have properties (stored data) and/or methods (functions that the object can run and call).
  • The Object can be based on a blueprint or parent which defines properties and methods it inherits and has access to and can use (further abstracted and managed by an Interface in some cases).  An example of a blueprint or parent that Objects inherit from would be Classes.

That’s just the tip of the tip of the iceberg.  If your interested in the rest of the tip of the iceberg, then here is some more information:

Definitions:

  • Object: A set of data grouped together by a common theme.  An object could be stored in a variable, function or data structure.  Objects consist of key/value pairs (the key is a placeholder(or representative name) for data, and the value is the actual data stored and associated with the key).
  • Class: Describes the properties and methods of an object (it is like a blueprint or definition of an object). Properties can be variables, arrays, or data;  Methods are functions that create/define behaviors of the object.
  • Property: A key/value pair in an Object that stores descriptive data (for example, an Object holding data about a person could have a property key of ‘name’, which would hold the person’s name as the value).
  • Method: A key/value pair in an Object that stores behavioral data (i.e. a function that does something – for example, modifies some property data, or gets additional data and uses it somehow).  The term ‘Method‘ and ‘Function‘ mean basically the same thing.  When talking about Objects, a ‘Method‘ is basically a function that is stored inside of and can be called from an Object.
  • Instantiation: calling the class with the new keyword to make the properties and methods accessible to an object that is created (by assigning a variable to it).  Example:  $obj = new Class_name();
  • Instance: an object (represented by a variable, for example) that has access to and references  the properties and methods of a parent class.  The instance is created through the process of instantiation (using the new keyword; see above).  In other words, an object is an instance of a class.

Benefits of using OOP (Object Oriented Programming):

  • Enables modular functionality in code.  Complex functionality can be accomplished while simplifying the code and making it cleaner (easier to read and understand).
  • Updating the code or modifying and adding features and functionality is also made easier by using OOP.

CLASSES:

  • To create a Class use the class keyword, then make a name:

Note: The first letter of the name of the class must be CAPITALIZED!

Example (A Class named Car is created and a property and method are assigned to it):

class Car {
//Methods and properties go here;
//Example property:
     var $doors = 4;
//Example method:
     function moveWheels(){
         echo "Wheels are moving!";
     }
}
Other things to note in class creation:
  • When creating a class, create the properties before creating the
    methods.
  • Use the keyword var to create properties (you can assign values or not).
  • You can use method_exists(“methodName”); for debugging if trying to find methods in a lot of code.
Creating properties in the class:
  • Use the keyword var to create properties (you can assign values or not):

Example (the class Car is created with properties and methods defined.  The -> is an access operator that is similar to the . in Javascript):

class Car {
    //(properties created with var)
    var $wheels = 4; 
    var $hood = 1;
    var $engine = 1;
    var $doors = 4;

//Methods(functions) in the class:
//To modify or assign values to properties, use $this variable (refers to the object/class that it is in):

    function changeWheels() {
        $this->wheels = 10; 
        //changes the wheels property value.         
        //Note: you don't use the $ when
        //referencing the properties in this
        //function method to set them.
     }

    function moveWheels(){
        echo "Wheels are moving!";
    }
}

OBJECTS:

To use the properties and methods of a class in an object:

  • Create an instance of the class: use the keyword new followed by class_Name(); i.e. new Car(); <—this creates an ‘instance’ of the class.
  • Assign the instance of the class to a variable – the variable now
    stores the instance of the class and is an object that has access to
    properties and methods of the assigned class.

Example:

$hondaFit = new Car(); 
//this creates an instance of the Car class assigned to $hondaFit (which can be called an object).
To access methods/properties:
  • To access a property/method use the -> operator and the name of the property/method (without the $ included) in PHP.  In Javascript, use the . operator (objectName.property):
Example:
  $hondaFit->wheels;  //returns the value.   
//or 
  echo $hondaFit->wheels; //<--this echoes '4'.

//Example (method access): 
  $hondaFit->moveWheels();

//Modify or assign a value to the object property:
  $hondaFit->wheels = 10; 
//reassigns the value of $wheels to 10.

INHERITANCE:

  • A class can inherit and access the properties and methods of other classes by using the extends keyword:

Example:

class Class_A extends Class_B {

//Class_A now has access to props and methods of      //Class_B.

//Props and methods can be added which Class_A will have in addition to those of Class_B.

//you can override the parent (Class_A) property by using var and assigning a new value to it:
var $propNameFromClass_A = newValue;
}

CONSTRUCTORS:

  • Constructor functions execute every time a new instance is created of the parent class they’re created in (with the new keyword).

Examples of practical use:

  • Create default values when a user is created or some default values of a new object that are automatically created when the object is instantiated.
  •  Automatic validations and site maintenance when new objects are created.

Create a constructor in PHP using function, two
underscores, and construct :

Example:

class Class_A {
    function __construct(){
       //code goes here; this runs every time a new
       //instance of Class_A occurs.
    }
}

DATA ACCESSORS:

Three Types:
  • Public — available to the whole program – scope is global.
  • Protected — only available to the parent class or sub-classes
    (extended) that inherit from the parent.
  •  Private — only available to the parent class (not accessible by
    extended classes).

You can use accessors on methods and properties, as well as classes.

Syntax: put the access type (public protected or private) before the class keyword or variable/property name:

Example:

public class Class_A {
    private $prop1 = value; 
    //only accessible inside the class
}

Uses:
-can be used to hide as much of the inner workings of an object as possible. That way it is less likely to break. 
-If you make everything public, then another programmer might alter a variable which you don't want changed by anything other than the inner workings of your object.

STATIC MODIFIERS:

  • This makes a method or property only accessible by the class and not by an instance or object.
  • It allows the use of a property or method of a class without having to
    make an instance of it.
  • Static properties can be referenced in methods inside the class by
    using ClassName::$property

Use the static keyword in place of var:

class Class_A {
    static $property = value; 
//the property is attached to the class and
//not the instance of it.
    function funcName {
    Class_A::$property = newValue; 
    //use :: syntax to access static properties.
    }
}

Note: when accessing static data in the Class, use the $ in the variable name if present (as opposed to omitting it when working with an instance).

To access the static property or method:

Insert :: after the class name to access static data: 

Example: 

echo Class_A::$property;

or

Class_A::funcName(); 
//executes the method using the static property.

S.O.L.I.D. DESIGN PRINCIPLES IN OOP:

  • Fundamental OOP design patterns and concepts to make your code easier to maintain, debug and read.

S.O.L.I.D. stands for:

  • Single Responsibility Principle (SRP): Classes should have one and only one job, or should have one and only one reason to change.
  • Open/Closed Principle (OCP):  Classes/objects should be open for extension, but closed for modification. Easily extend a class without modifying it, make functionality in the class as abstract and broad as possible and leave more specific tasks and computation in the sub-classes that extend it.
  • Liskov Substitution Principle:  Every subclass should be substitutable for their base/parent class. The functionality and methods/properties of a subclass should not remove or significantly differ from the functionality/logic of it’s base/parent class it extends, so that uses of it as a type of the parent class will not break or not work as expected.
  • Interface Segregation Principle (ISP):  No client should be forced to depend on methods it does not use.  Interfaces belong to their clients and not to the implementations. Thus, we should always design them in a way to best suite our clients. we should break our interfaces in many smaller ones, so they better satisfy the exact needs of our clients. Interfaces are just plain function name definitions. There is no implementation of any kind of logic in them.. great advantage of clients depending only and only on what they actually need and use.
    *** ISP recommends that you should use many specialized interfaces instead one big interface. Interfaces belong to their clients and should represent what the clients need. This helps reducing dependencies on methods the client is not using.
  • Dependency Inversion Principle (DIP):  High-level modules should not depend on low-level modules.  Both should depend on abstractions.  Abstractions should not depend upon details. Details should depend upon abstractions.  Common solution is to implement Interfaces which are objects that specify what methods are available to classes or objects that implement them.

DESIGN PATTERNS IN OOP:

  • Singleton:  An object of which there is one and always only one copy or instance.  The object is not instantiated with copies that inherit from it or duplicated anywhere else in the application code.  The purpose of using a singleton could include conserving memory space and provide a single instance of an object that serves as a central and global resource that you need to manage throughout the application (i.e. a log).   The pattern is criticized because since it can expose your object to the global namespace, but if used carefully and depending on the use case, it can be an appropriate solution and pattern to implement.

FURTHER READING AND RESOURCES: 


Helpful Bonus Tips:

  • To check if a Class exists use class_exists("class_Name");  returns a boolean.  Can be used for debugging.
  • You can also use method_exists("method_Name"); to check for a method.  Can be used for debugging if trying to find methods in a lot of code.

This blog post is a summary of my notes taken from an online course on Udemy by Edwin Diaz called PHP for Beginners – Become a PHP Master – CMS Project.  There is a section on Object Oriented Programming in the course that was excellent and explained the fundamental concepts clearly and efficiently.   I’ve tried to boil the concepts down into a quick read as an introductory crash course to get started.