CFD
62% Complete
Star

Chapter 4
Coding &
Concept

So far we've broken down some barriers around coding and computers in general. We've learned about coding structure, style, and behavior too. Additionally, we've introduced programming relative to visual design's elements, principles, and constructs. Though there is always more to learn, your confidence should be magnitudes higher than when we started. Additionally, a mental model should be forming. Let's strengthen it.

To do so, we will visit one more set of concepts before getting into JavaScript itself. Virtually all of these concepts are language agnostic. Hell yea.

In this section, we will visit the most important programming concepts that will help shape your future programming efforts. We will talk about the three main and distinct timeframes when code exists. These are authoring time, compile time, and execution time. This knowledge will help you understand the transition from authoring code to interactive creations people can use. Following this, we will visit the frame rate and event loop concepts in detail so we have a fine-tuned grasp of what actually happens during execution time.

Next we will explore the differences between sync (happens now) and async (happens later) behavior. This exploration will naturally tie into visiting interfacing and the client-server model. As a result, we will learn how code talks to other code while also learning the specific benefits of having multiple computers communicate and/or do dedicated and unique work.

Second to last, we will look at the anatomy of HTML (.html), CSS (.css), and JavaScript (.js). This will allow us to reference real code against various concepts covered thus far. Lastly, we will cover the work. right. better. mantra to help you improve your code authoring over time. All coders live by this, myself included.

Upon completion of this section, your mental model will be primed for programming in JavaScript. Let's get going.

Authoring, Compiling, and Executing

As mentioned previously there are three distinct timeframes when code exists. In order, these are:

  1. Authoring time
  2. Compile time
  3. Execution time

These distinct timeframes are useful for understanding how the static code we author in a text file enables a dynamic and interactive creation to exist in real-time. We will also touch on why this transformation even needs to occur.

Authoring time is pretty self-explanatory right? It is the time when we are authoring code. That's it. We have a text editor program of some kind open and we are typing or pasting into it. Simple as that. Some programs even exist, like Unity for example, that enable a more visual programming approach. This simply means that the program has some amount of UI interaction that enables you as the author to generate code in a non-text based way. Admittedly, this is often more fun than text-based programming... but there is a catch.

Inevitably, these visual tools are limiting as they do not allow you to pull off exactly what you want. This is why we're concentrating on authoring custom code in a text editor. We get ultimate control as to how something works because we get to write the code.

After we have authored the code, we need to "run" or "execute" it. Executing it helps us confirm that it actually does what we want in real-time. Before we can do this however, a step needs to be taken that transforms our static authored code into code that can be executed. Welcome to compile time.

Compile time is how we get from our authored static code to dynamic code that manifests as an interactive application or game. We won't go into the details of this step as it is complex. All you need to know is that this step exists so we can use words we understand instead of coding in binary, the only thing computers fundamentally understand. A prime example is how we use English words (and English abbreviations) within the programming language JavaScript.

In essence, some smart and nerdy authors write compiler programs that compile and convert a high-level programming language like JavaScript (easier for us humans to use) to lower-level languages (easier for super-nerdy humans to use) to binary (easier for super-super-nerdy humans and computers to use).

Author > Compile > Run

Author > Compile > Execute

The output of this compilation process results in code that the computer executes in real-time. This process often manifests as an interactive user interface in an application or an interactive environment in a game.

With Unity, the process is:

  1. Author code in a text editor and/or with Unity's built-in UI that generates code
  2. Click the "Build" button to compile the authored code into an executable package
  3. Execute this file's code on the target operating system in real-time
    • Remember file extensions?
    • Remember decoding?

With JavaScript in a web browser, the process is:

  1. Author code in a text editor and/or a tool that helps generate code
  2. View a web page that hosts your authored JavaScript code, the browser compiles it on the fly
  3. This compiled code is then automatically executed in real-time

To recap, we write in a high-level language using English words and abbreviations. This is author time. Then a compiler program converts the code we humans can understand into code the computer understands. This is compile time. Finally, if the conversion process has no errors, the result is an application or game that is interactive. This is execution time.

How is execution time actually interactive though? One or more users could take any number of actions within our application or game at any given moment. We can't possibly handle all these potential scenarios in our code can we? Thankfully the answer is yes we can. We just need to understand the frame rate and the event loop.

Frame Rate

We know computers are dumb and fast. Some computers are faster than others however. How do we ensure the code we author will execute well on any given computer? To do so, we need to author our code with a target frame rate in mind.

A frame rate is simply the amount of frames that are shown in a second. A frame is a single rendered image. Frames shown back to back over time create the illusion of motion. Common target frame rates are:

As you likely guessed, a high frame rate results in the illusion of smooth motion. A slow frame rate results in an illusion of less smooth motion. The human eye typically needs 24fps or more for a smooth perception of motion to be recognized. Within an interactive medium like applications or games, 60fps is a common target.

It is worth noting that if your application or game does not change often and/or lacks animation, you will likely be able to get away with 10fps or 5fps. The more motion and animation you have however, the more likely you'll want to target 60fps. Generally, the richer and more fluid the experience, the greater the frame rate.

An application or game that targets 60fps must render a new image every 16.6 milliseconds. Damn, that's fast.

1 second = 1000 milliseconds so 1000ms/60fps = 16.6ms per frame

1 second = 1000 milliseconds so 1000ms/60fps = 16.6ms per frame

Milliseconds might be intimidating at first, but you'll get used to them quickly. In fact, you likely already have an intuitive understanding of milliseconds. Do you ever feel an animation within an application or game is too slow or too fast? The milliseconds chosen as the animation time is the culprit.

You usually don't have to worry about the 16.6ms window however. I present it here simply for you to keep it in the back of your mind.

In the future, if your application's animation and motion seems to have hiccups or it looks janky, then you likely have a problem or two. Typically this means your code, or a 3rd-party's code, is:

  1. doing too much work each frame
  2. doing work inefficiently

We'll revisit these two problems later, but just be aware of them.

So a frame rate is vital for percieved motion, that's great. But how do we actually allow interactivity to be reflected in this motion? Event loop time.

Event Loop

An interactive application or game is simply the manifestation of a target sixty rendered images, shown in sequence, per second. The only reason this frame rate is important is so the user's experience is perceptually fluid and responsive. If fluidity and responsiveness were not a perceptual goal, our application or game could leverage 10fps, 5fps, or an even lower target frame rate. More often than not however we desire the interactive content we create to be extremely fluid and responsive. 60fps? Yes please.

A non-interactive animation hitting 60fps undoubtedly looks smooth, but it is just that, non-interactive. How do we account for this desired interactivity?

Thankfully, the program responsible for executing our compiled code helps us out. This program is called the engine. Additionally, the engine gets help from its parent program, the runtime. Together, the runtime and engine provide an interactive system that executes code in real-time. If we were to code the relationship in an HTML-like code, it would look like this:

<runtime>
    <engine></engine>
</runtime>

For us to take advantage of the runtime and engine, we just need to get an idea of how they work together. This allows us to author code that reacts interactively as the engine executes it in real-time.

The JavaScript runtime in a web browser has four core parts and the engine has two:

  1. engine
    • heap
    • stack
  2. runtime APIs
  3. event queue
  4. event loop

We can update our HTML-like example from before:

<runtime>
    <engine>
        <heap></heap>
        <stack></stack>
    </engine>
    <apis></apis>
    <queue></queue>
    <loop></loop>
</runtime>

So what do each of these runtime parts do anyway? Here is a succint breakdown where the use of work implies some amount of code reading and/or executing:

  1. engine - does work
    • heap - memory for work
    • stack - organizes the engine's work
  2. runtime APIs - does special work the engine cannot
  3. event queue - organizes the results of special work as packages of engine work
  4. event loop - gives the engine queued packages of work

Here is a 3D representation of the relationship between the runtime and engine parts:

The Event Loop Machine

The Event Loop Machine

During compile time, just before execution time, the engine quickly does three things with our code:

  1. reads
  2. reorganizes
  3. optimizes

These steps enable the engine to run fast and efficiently during execution time. Execution time is when the runtime and engine work together to achieve two goals:

  1. clear the stack
  2. clear the event queue

Once these two goals are met, the engine can relax. It relaxes until new work is added to its stack. How does it get new work though? Do you remember the input triggers we covered in the Behavior section? Bingo. As a reminder, these input triggers, often called events, are:

  1. user interaction (tap, click, hover, gesture, voice, etc.)
  2. environment (layout resizing, operating system, device sensors, etc.)
  3. time (delays, schedules, etc.)

When an event occurs, the runtime APIs manage the special work required and then update the event queue when finished. Since the event loop has been cycling while the engine was relaxing, it now notices the updated event queue. Consequently, it takes one item from the queue and gives it to the engine. The engine then puts it on the stack. You guessed it, new work for the engine. This process cycles.

Though all of the runtime's parts are vital, the event loop most ensures our interactive creations come to life. Thanks event loop.

Sync and Async

Though we didn't explicitly state it, the nature of how the event loop works gives rise to the notion of sync and async work. Synchronous and asynchronous are the full terms, but we will use the shortcuts sync and async instead.

Sync work is referred to as blocking where async work is non-blocking. Using your new knowledge of the event loop, how would you categorize the engine's stack work? How about the runtime APIs work? I'll give you a clue, they are different. Take a moment before continuing.

Answer time:

TODO - Replace

TODO - Replace
sync blocking stack work
async non-blocking runtime APIs work

The Event Loop Machine 3D visualization from the Event Loop section should be popping into your head. The event loop cannot cycle when work is on the stack. The loop is blocked. The event queue does not prevent the event loop from cycling. The loop is not blocked.

Let's look at code examples of both work types to see this in action. We haven't specifically covered JavaScript outside the brief introduction in the Elements and Elements section, but I am confident you'll get the gist.

Sync work:

function makeBackgroundBlack() {
  document.body.style.backgroundColor = '#000000';
}

makeBackgroundBlack();

There are likely some details you don't understand, but that is to be expected. Let's look at the same code with some added explanations. Take note that the words following the // are plain English, not code. These plain English comments are useful for us humans when we read and share our code for others to read (including our future self). Comments are for humans not computers. The engine essentially ignores them.

// 1. We declare a function statement (stack work) for the engine
// 2. We name the function whatever we want, 'makeBackgroundBlack' in this case
// 3. The engine doesn't do the work yet (code statement between the '{' and '}')
function makeBackgroundBlack() {

  // We set the document's background color to black (remember the Coding Color section?)
  document.body.style.backgroundColor = '#000000';
}

// 1. We tell the engine to do work, the code sequence `()` is the trigger
// 2. Since we named the function, the engine knows the exact work to put on its stack
makeBackgroundBlack();

Without comments, there are naturally a lot less lines for us humans to read. As far as the engine is concerned however, these are the same program. As you gain more experience you will understand when and when not to use comments. When in doubt use them to help other coders, including your future self, understand your original intention.

Admittedly, the code above does not do a whole lot. The work inside of the makeBackgroundBlack function will happen really fast too. The event loop will technically be blocked for less than 1ms, but from a user's perspective the work will happen instantly and then the event loop will become unblocked. If the function instead counted to a million before changing the background color, then the user would percieve the program as slower (and rightly so).

The takeaway here is that you should try to do small and efficient work in your functions. As you author code over time, you will develop an intuitive understanding of what that really means. For now, put this idea in the back of your mind. Remember, the faster the stack and event queue are cleared, the greater the chance you will hit your target frame rate. 60fps? Yes please.

Let's now look at an async example. We will make it similar to the sync example for comparison. In fact, we will make the program identical except for a single statement and its comments.

Async work:

function makeBackgroundBlack() {
  document.body.style.backgroundColor = '#000000';
}

// 1. We tell the engine to do work, the code sequence `(makeBackgroundBlack, 1000)` is the trigger
// 2. 'setTimeout' is a named built-in function that the 'runtime APIs' provide, thank you runtime
// 3. The 'setTimeout' function expects two argument values
setTimeout(makeBackgroundBlack, 1000);

Before reading on, try to guess what setTimeout does. How do you think it uses the argument values?

This async program is identical to the sync program except for one code statement. If we look up how the setTimeout function uses its arguments to do work, we can learn what work it does. I want to stress again that professional coders, just like beginners, use references to learn and remind themselves what certain functions do. Even the best cannot remember everything.

I will just tell you what arguments, in order, setTimeout expects:

  1. a function
  2. a time in milliseconds

The work setTimout actually does, in English, is:

  1. create a timer
  2. run the timer for the time in milliseconds provided
  3. wait for the timer to complete
  4. upon completion, update the event queue with the function provided

What is cool about many functions, setTimeout included, is that they can be designed with a small amount of flexibility built-in. As you may have guessed, as long as we give setTimeout valid arguments, it will always do the work we want (via the function provided) after a delay (via the time provided). Pretty damn cool. You can design your own functions with flexibility as well.

As a quick example, let's design a new function named changeBackgroundColor.

function changeBackgroundColor(newColor) {
  document.body.style.backgroundColor = newColor;
}

Here are a few examples of how we could use it:

changeBackgroundColor('#FF0000');

or

changeBackgroundColor('Green');

or

changeBackgroundColor('Blue');

You get the idea.

We explored some JavaScript a little bit in this section, but the main takeaway is the difference between sync and async. If you understand how to keep your stack work small and fast, you'll be running 60fps with no problem.

As you learn more about runtime APIs you will discover that the runtime will do a lot of really cool non-blocking work for you. If you haven't already noticed, the runtime APIs provide a simple interface for you as a code author to work with. Let's dig deeper into what that means.

Interfacing

It wasn't important until now to tell you what the aforementioned API of runtime APIs stands for. Now is the time. Welcome to Application Programming Interface. Yea, that is a mouthful. Coders instead just say API (each letter pronounced individually).

An API is just an interface. The doorknob of a door is an interface. The steering wheel of a vehicle is an interface. The keys of a virtual keyboard are too. Interfaces provide a way to interact. The doorknob and steering wheel are physical interfaces designed for humans. A virtual keyboard is a digital interface also designed for humans. An API is a programming interface designed for code. An API allows code to interact with other code, this is the takeaway.

As a code author, you get ease-of-use while the underlying complexity is the code designer's responsibility. Think about it. As a driver of a vehicle, you do not need to know all the details of how the engine works to use it. The designers take that responsibility. Similarly with code, you just use the API provided to gain benefit. This is a pretty solid trade.

In the last section we saw one API in action, the built-in setTimeout function. We wrote our code to interact with that API by giving it two argument values. Behind the scenes, the runtime wired up and provided the functionality we expected. Both you and I don't really care how the work is done as long as it gets done. This is the trade-off an API provides, a simpler way to do work. APIs rock!

Earlier in the Constructs and Components section we covered built-in, 3rd party, and custom components. Naturally, they each provide various APIs. As previously mentioned, we can create useful code for others to use too. Another author using our code APIs doesn't have to care about how the work actually gets done. They get the same trade-off as us, a simpler way to do work.

As you gain coding and programming experience, you'll memorize certain built-in and 3rd party APIs. This translates to improving your authoring speed. Don't worry about being slow when you start out, you'll get better in time.

This might sound weird at first, but some APIs exist on a different computer than the one your program runs on. Whoa. Have you ever wondered how a particular app or game can provide new content without actually updating? Welcome to the client-server model.

Client and Server

Clients and servers are computers that communicate over a network. The internet is one such network that facilitates this communication. Some of these computers are clients and some are servers. Sometimes a computer is both a client and a server. The distinction is simple. A client asks for data and the server provides it. The network between them is the communication channel.

The details of how the internet facilitates this communication is elegant and impressive, but not a focus of this book. I highly recommend Introduction to Networking by Charles Severance if you want to dig deeper, but it is not required reading to move forward. Just know that the internet enables a client computer and a server computer to talk.

Let's look at two example programs that utilize the internet to help solidify your understanding. One program will be a web browser and the other an internet-connected mobile game. Let's just say that each example is running on a smartphone. Both the browser and the game are on the client, the smartphone. Each program leverages distinct APIs to request information from distinct and remote computers, the servers. Pretty simple relationship really.

Client and Server

Client and Server

You already know that a web browser may be used to access a particular website or web app. While the site or web app is running, its code can make additional requests to the server in an effort to get additional data. For example, when a sport statistics app is starting up, or another input trigger occurs, the app could use an API to get the most up-to-date scores and stats. An updated version of the app is not required. Instead, an API interaction provides updated data. This is super useful.

An internet-connected game works exactly the same way. When it starts up, or another input trigger occurs, it could make an API request to get current world-wide player rankings for the game. Additionally, if the designers and code authors designed the game in such a way, they could make different API requests for new worlds, levels, characters, etc. No update required. Pretty damn cool.

A server, if you didn't guess already, is also responsible for providing a client web browser the initial HTML, CSS, and JavaScript for a website or web app. If too many people try to access the same data at the same time however, the server can crash. It is worth noting that each client is actually getting a copy of the data to reconstruct in its browser. Typically a crash occurs because the server software can't properly provide the various clients the copies fast enough. I mention this simply because many people don't grasp the fact that the client reconstructs what the server provides.

Having talked about HTML, CSS, and JavaScript at solely a high level thus far, now is a great time to venture deeper. We'll do so next by exploring the anatomy of the three file types .html, .css, and .js.

Anatomy of HTML, CSS, and JavaScript

This section will be the first where we really start digging into the existing languages of HTML, CSS, and JavaScript. We have covered quite a bit in an effort to get to this point. Specifically, we learned about the powerful concepts of binary and states in addition to encoding and decoding in the Breaking Barriers chapter. We learned in Structure, Style, and Behavior how each concept plays a valuable and distinct role in an interactive creation. In Coding and Visual Design we mapped familiar design-specific concepts to programming concepts to help establish a knowledge bridge. More recently, we explored programming-specific concepts to help shape your understanding of how code lives and communicates in real-time.

We know code is a system for converting meaning between forms where HTML, CSS, and JavaScript are just specific forms. HTML is a markup language used to define structure. CSS is a style language used to define style. JavaScript is a scripting language used to define behavior. The web browser knows how to decode HTML into divisions of content and render them. It also knows how to decode CSS property-value pairs to adorn the HTML elements with style and functionality. Lastly, we know a browser's runtime and engine understand how to decode and execute JavaScript which enables an interactive creation to exist.

We will now start to dig into HTML, CSS, and JavaScript since we have a greater understanding of how the various concepts we have covered play-off each other. Your mental model should be primed.

Let's squash a myth real quick. Designers and other non-coders new to coding think they need to learn an entire new language including all its words, syntax, and idiosyncrasies. In the context of the web, that would mean three sets of words, syntax, and idiosyncrasies need to be learned. There is a better way to spend time and energy learning however. What really needs to be learned is:

  1. Distinction between structure, style, and behavior
  2. Syntax of structure, style, and behavior language
  3. Subset of code words for each implementation (80/20 rule)

For 2D and the web, that means we need to know the difference between HTML structure, CSS styling, and JavaScript behavior. We have this distinction covered already. Bonus. Let's dig into number two and three. Learning these two facets for each language may not be easy, but it can be simple. Regardless, there is no substitue for practice.

HTML

In keeping with the structure, style, and behavior order, let's look at the anatomy of each starting with HTML. We will title our file index.html to align with a best practice naming convention. Technically you can name it anything your OS allows, but make it easier on yourself and follow this best practice.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Coding for Designers</title>
  </head>
  <body>Content goes here.</body>
</html>

This is the most structurally simple, complete, and valid HTML a browser uses. Let's walk through each tag using comments to clarify each tag's purpose. We saw earlier that JavaScript uses the // character sequence for comments. HTML uses the <!----> sequence where the actual comment rests in the middle of the dashes. Just take note that each language may have a uniqe approach to comments, but the purpose is the same. Yes, it would be ideal if all languages used the same character sequence for denoting comments. It's not a perfect world. Sad face.

<!-- Tell the browser the document type - we only care about html -->
<!DOCTYPE html>

<!-- Tell the browser where we've defined our html - additional data exists outside it -->
<html>

  <!-- Define the page metadata - useful data for the browser, other programs, and search engines -->
  <head>

    <!-- Define the character encoding - inform the browser how to reliably decode this document -->
    <meta charset="utf-8">

    <!-- Define the page title - useful for the browser, other programs, and search engines -->
    <title>Coding for Designers</title>

  <!-- Define the page metadata end -->
  </head>

  <!-- Define the page content - what gets rendered for viewing and user interaction -->
  <body>Content goes here.</body>

<!-- Define the html end -->
</html>

There are many types of element tags that can be added in both the <head> and <body> element tags. As mentioned earlier, we will not go over them here as you, just like other coders, can use other resources to look up what tags are available. We will reveal the most common ones for the <body> however to fulfill the common subset bullet above. Instead of comments I will use English inline with the tags to show how the elements wrap content. Content is visible to the user where the tags that wrap the content are not. The tags simply tell the browser your structure, the building block parent-child relationships. The spacing between elements is not important as the browser understands the structure regardless. Spacing between content is what matters.

Spacing, tabs, and new lines do typically exist between elements however. This is solely to improve human readability. Imagine if the below HTML elements were all on a single line. The browser wouldn't care as the defined structure would remain the same, but we would have a much tougher time reading and easily seeing the parent-child relationships when authoring.

<body>
  <div>
    <h1>This is the Primary Title of the Page</h1>
    <p>This is a paragraph. It is followed by an image and a button.</p>
    <img>
    <button>Toggle Image Opacity</button>
  </div>
  <div>
    <h2>This is a Secondary Title</h2>
    <p>This is another paragraph. It has a <a>hyperlink</a>.</p>
  </div>
</body>

The first thing you will notice about six of the seven tags is that they are abbreviations, they are shortcuts. This admitedly sucks for beginners, but it is great for when you know the small subset by heart. You will learn it quickly, but it still is lame from a beginner perspective. Here's a breakdown to help:

HTML Tags Subset Map

HTML Tags Subset Map
div division
h1 heading one
p paragraph
img image
button button
h2 heading two
a hyperlink

A <div> tag simpy denotes a division of content where the aesthetic and layout (position and dimension) of each division is dependent on style. This will likely become your most used element tag. Combining it with the virtually infinite variations of CSS styling enables you to create the same visual effect of virtually every other tag. If not for the specific attributes and semantics of certain tags that browsers, operating systems, and search engines use, we could almost get away with solely using <div>s with custom styles. This idea it so illustrate the notion that a lot can be achieved with little.

Moving on, the <h1>, <p>, <button>, and <h2> tags are explained and covered with the examples above. The <img> and <a> tags are not however. This is because they are each lacking attributes. We'll use the shortcut attrs moving forward. All elements can leverage attrs, but these latter two elements require them to function as designed.

Think of attrs as APIs. Attrs enable the coder to achieve functionality based on a shared understanding of designed use. They are also where we start to transition toward CSS via the class attr. First we will update the <img> and <a> tags with each of their most useful attrs.

So <img> becomes <img src='assets/img/cover-coding-for-designers.jpg'> where the src attr is set with = to the value assets/img/cover-coding-for-designers.jpg between quotes. Quotes define the start and end of the attr value. The browser knows how the image tag is designed to work so its runtime APIs automatically download the image provided by the src attr, which is the path to the asset. Upon completion of the download, the tag embodies the downloaded image. This same functionality can be achieved using JavaScript only, but we'd have to write more code. Remember, APIs provide a tradeoff and a simpler way to do work.

Additionally, <a>hyperlink</a> becomes <a href='http://www.codingfordesignersbook.com'>hyperlink</a> where the href attr is set with = to the value http://www.codingfordesignersbook.com between quotes. The browser knows that the anchor tag, when hit, should change the web page to the value provided. This same functionality can be achieved using JavaScript only, but we'd have to write more code. Again, the goal is a simpler way to do work.

The takeaway is that the browser provides useful runtime API hooks via element attrs. Now that we've covered the basic implementation of HTML structure, let's dig into style. Welcome to the class attr.

CSS

The class attr gives you the creative power to style content. We will start by giving each <div> the same style. So <div> becomes <div class='dark-background'> where the class attr is set with = to the value dark-background between quotes. The dark-background name could be virtually anything we want, but there are rules for valid names. Make it easier on yourself and stick with:

Now that we have set a dark-background value for the class attr, how do we actually define the style for the browser to render it? Remember when I mentioned that other tags can be added to the <head>? Welcome to the <link> tag. It allows us to link another file to our web page. Perfect. Our updated <head> is below and it now has a <link> tag. The attrs of it tell the browser to download and use a CSS file where our defined dark-background style resides.

<head>
  <meta charset="utf-8">

  <!-- 'rel' defines the href relationship type - 'href' defines the hyperlink reference -->
  <link rel="stylesheet" href="assets/css/style.css">

  <title>Coding for Designers</title>
</head>

The folder structure on the server computer that is providing these files to client computers is below. Take note that a lacking file extension means the item is a folder. The relative paths of the <link>'s href attr value and the <img>'s src attr value rely on the structure below. These relative paths, relative to the index.html that is, tell the browser exactly where to find the file to use.

index.html
assets
  css
    style.css
  img
    cover-coding-for-designers.jpg

Now is the time to look at the anatomy of a .css file which, for our purpose, consists of one class definition. Typically the file would have more than one, but currently we only need one. Take note that CSS uses comments via /**/ where the comment itself resides in the middle. I too wish HTML, CSS, JS shared the same comment syntax, but I digress. Our style.css file is simply:

.dark-background {

  /* This is a CSS comment - the below property-value pair sets an element's background color to black */
  background-color: #000000;

}

Each class definition is denoted by a preceding . so our dark-background class becomes .dark-background within our .css file. Then, similar to the JavaScript scope concept we visited earlier, the property-value pairs are defined between the { and } characters. The { and } define the scope, the space and enclosure, where one or more property-value pairs are associated with a particular class.

Each property-value pair consists of a property name that uses the same rules for class naming suggested above, followed by a : and then an actual value. For ease of learning, I wish the : was = instead, but I digress. With a class and its valid property-value pair(s) defined, any element that has a class by the same name will get the styles applied. Pretty damn cool and very reusable.

If it isn't already obvious, each browser sets default styles for elements to provide some baseline style. More often than not, you'll want to set your own styles to override the defaults. This is why we created style.css.

Since browsers typically default the color of text to black, our applied dark-background class makes our text blend with the dark background. We want to see the text too so we can fix this by updating our class definition to use another common property named color. Again, we won't go over all the valid properties that are possible as you, like other coders and designers, can reference resources. The takeaway is the relationship of property-value pairs within class definitions. Here is one approach to update our style.css file:

.dark-background {
  background-color: #000000;
  color: #ffffff;  
}

Another approach could be:

.dark-background {
  background-color: #000000;
}

.light-text {
  color: #ffffff;
}

Our <div>s would need to be updated for the second solution. Take note that spaces are used between class names to enable more than one class style to be applied to a single element. This is a very powerful aspect of CSS, one which you will grasp more intuitively in time. Updated HTML using the second solution is below:

<div class='dark-background light-text'>

With either solution, both our <div>s will have dark backgrounds and the text within them will be light. You might wonder how the text of the child elements can be light without explicitly setting styles on them. This is where the cascading part of cascading style sheets comes in. Think of cascading as style inheritence. Long story short, a majority of property-value styles can be inherited regardless of nested element depth. Cascading is extremely powerful and you will learn its nuances in time.

As a creation evolves, feel free to change the names of classes if it makes sense to. A class name may make less sense as new property-value pairs are added or removed. Over time you will leverage established naming practices and/or develop your own to gain an intuitive feel of when to update a name. Additionally, you'll develop a sense of how best to group certain property-value pairs for reuse by different elements. Just know that it is extremely common to change names as a creation evolves.

JavaScript

Thus far we've covered the anatomy of HTML and CSS, so now it is time for JavaScript. In a way we already looked at the anatomy of JavaScript in the Elements and Elements section. That breakdown was a bit more granular though and we'll revisit the specifics in the next chapter Coding and JavaScript. For now we will look at the high level anatomy of a JavaScript program. We will focus on shape, space, and form or more precisely function, scope, and object.

As you already know, a function is like a shape because it encloses scope just as a shape encloses space. An enclosure helps prevent clashing of what exists between different scopes or spaces. No clashing please. Objects, like forms, are a higher level enclosure. More often than not, they each embody one or more functions or shapes respectively. JavaScript, like the majority of programming languages, has specific types of objects. JavaScript is fairly unique however in that a function is also an object.

Long story short, a JavaScript program is essentially a nested tree of functions. As a byproduct of functions each enclosing a scope, a JavaScript program can also be thought of as a nested tree of scopes. So when the JavaScript engine evaluates an expression that has a reference (shortcut name for a value), it works like this in an effort to get the bound value:

  1. Look in the target scope for the reference
  2. If not found, look in that scope's parent scope
  3. Repeat until the reference is found or the root parent scope is hit

When the reference is found in one of the scopes, the engine uses the value that is bound to the reference and continues to do work. This is what we want. If the root scope is hit and the value does not exist, then we have a problem. We will go into detail later regarding this scenario, so just be aware of it.

Now that we know the anatomy of a JavaScript program is simply a nested tree of scopes, let's add a simple example based on this section's HTML and CSS examples. As you might imagine, HTML has a tag that allows us to add JavaScript just as easily as we added CSS. Welcome to the <script> tag. You can add a <script> tag to the <head> or the <body>, but the latter is best practice for non-blocking reasons. Specifically, <script> tags should reside just before the closing body, the </body>. Here is an updated excerpt from our index.html file.

    <!-- The previous HTML code from our index.html file is excluded for brevity -->
    <script src='assets/js/main.js'></script>
</body>

Naturally, the server folder structure needs the path to our main.js so our updated structure becomes:

index.html
assets
  css
    style.css
  img
    cover-coding-for-designers.jpg
  js
    main.js

The browser understands the script tag and its src attr and then, you guessed it, the browser automatically downloads it. When completely downloaded, the runtime and engine take over with compilation and execution of its contents. Before we look at the contents of our main.js file, let's update our <img> and <button> HTML to more easily use each with JavaScript.

The updated <img> becomes:

<img id='image-to-toggle' src='assets/img/cover-coding-for-designers.jpg'></img>

The updated <button> becomes:

<button onclick='toggleImageOpacity()'>Toggle Image Opacity</button>

The id attr is how we identify an element in our HTML as unique to our document. An id means we intend there to be only one element with a specific name. A unique id enables us to gain a reference to the element's corresponding object for use in JavaScript. With this JavaScript reference we can use its API to do all sorts of cool things.

The result of clicking the button above during execution time results in the function named toggleImageOpacity to be called via (). This results in the function's contents being executed by the engine. Behind the scenes, the runtime APIs transform the hardware input (mouse, trackpad, stylus, touch, etc.) to event queue work. The event loop then picks up the resulting package and it gets placed on the stack. This all happens in milliseconds or even microseconds when the event loop is not blocked. Lastly, the engine actually executes the function contents. Now is a great time to look at the contents residing in our main.js file.

function toggleImageOpacity() {

  // Reference work
  var imageToToggle = document.getElementById('image-to-toggle');
  var currentOpacity = window.getComputedStyle(imageToToggle).opacity;

  // Core work
  if(currentOpacity == 1) {
    imageToToggle.style.opacity = .5;
  } else {
    imageToToggle.style.opacity = 1;
  }

}

Do not worry if you cannot understand everything in the above function as we'll cover it in great detail in the next section. You should however be able to grasp what is happening each time the toggleImageOpacity function executes. The image's opacity style is simply toggled between .5 (50%) and 1 (100%). Take note that the function is structured in two parts:

  1. Reference work
  2. Core work

A function is not always structed this way by a coder, but JavaScript compilation essentially enforces it. We don't go into the details of compilation as previously mentioned, but look into JavaScript hoisting if you want to dig deeper. Just save yourself some pain and declare your identifiers (vars first and functions second) at the top of their parent function prior to use.

Admittedly, this program is tiny as it is comprised of only one small function. Take note however that programs of all sizes leverage this structure since they are just functions nested in functions. And consequently scopes nested in scopes. We will consider larger programs later in the Coding and JavaScript chapter to see this in action.

Before advancing to the next chapter though, we'll dive really deep into the toggleImageOpacity function. The function works, but we can improve it.

Work. Right. Better.

In programming there is the axiom "make it right before you make it faster". This exact quote is found in The Elements of Programming Style by Brian W. Kernighan and P.J. Plauger and it is heavily respected by the programming community. Put another way, when authoring code you should make it:

  1. Work
  2. Right
  3. Better

In this section we will explore the notion of right and better in reference to the working toggleImageOpacity function that we recently looked at. This effort will introduce reusable code improvement tactics and the thought process behind them. The three step process will become second nature in time.

First and foremost you need the code to work. No shit. Making it right is less obvious though. Typically the goal is to achieve the same functionality with less and/or more efficient code. Making it better is much more subjective.

Is the code better for beginner and junior coders? Is it better for advanced and senior coders? Is it better for the computer? Sometimes the solution is ideal for all, but this is not always the case. For example an advantageous language feature may be common sense to an advanced coder, but confusing to a beginner coder. The code is better for one group and less so for the other. Similarly, when program performance is a bottleneck, better may mean sacrificing human readability. This should be avoided, but it is sometimes necessary. This latter example translates to an advantage during compilation time and/or execution time, but a disadvantage to authoring time.

Below is the toggleImageOpacity function from the previous section with added comments. Each comment is numbered for reference as we will soon be investigating the code line-by-line. After we understand each line of code, we will entertain improvement ideas.

// 1. function declaration using toggleImageOpacity identifier
function toggleImageOpacity() {

  // 2. variable declaration and assignment using imageToToggle identifier
  var imageToToggle = document.getElementById('image-to-toggle');

  // 3. variable declaration and assignment using currentOpacity identifier
  var currentOpacity = window.getComputedStyle(imageToToggle).opacity;

  // 4. 'if' portion of an if/else conditional statement
  if(currentOpacity == 1) {

    // 5. property assignment using imageToToggle reference
    imageToToggle.style.opacity = .5;

  // 6. end of 'if'
  }

  // 7. 'else' portion of an if/else conditional statement
  else {

    // 8. property assignment using imageToToggle reference
    imageToToggle.style.opacity = 1;

  // 9. end of 'else' 
  }

// 10. end of toggleImageOpacity function
}

Now that the numbered comments provide a bit more context to each associated line of code, let's take a step deeper into each snippet. I do not expect you to understand everything we cover in the rest of this section however. Do not be discouraged if some words or ideas make no sense yet as this is expected. The intention of this section is to plant seeds in your mind regarding the vocabulary, concepts, and considerations of advanced coders. Extract what you can.

In snippet one there are four parts comprising the line of code:

// 1. function declaration using toggleImageOpacity identifier
function toggleImageOpacity() {
  1. function - keyword reserved by JavaScript denoting a function
  2. toggleImageOpacity - custom identifier for referencing the function by name
  3. () - function signature input defining how to call the function to do work
  4. { - opening curly brace for declaring the beginning of the function body
    • } - a closing curly brace is expected after the function body for declaring its end
    • the { and } define the scope boundary of a function

The above four parts make up the anatomy of a function. First, the function keyword tells the JavaScript engine your intent to define a function. Second, a custom identifier is set to enable other code to properly reference and call the function by name. Third, the function's signature input defines what arguments the function expects to use when doing its work. No arguments are expected for toggleImageOpacity currently. Lastly, the { and } define the bounds of the function body. All functions return a value prior to closing the function body too, but this function signature output will be covered in the next chapter.

With respect to making snippet one right there is nothing we can do. A case could be made for making it better by renaming toggleImageOpacity to a single character alternative. This change is better for computers because there is less information to read which also translates to a smaller payload to send over a network. We won't make this change as we want to keep the code better for us humans. Research the minification process to learn about attaining the best of both worlds.

In snippet two there are five parts comprising the line of code:

// 2. variable declaration and assignment using imageToToggle identifier
var imageToToggle = document.getElementById('image-to-toggle');
  1. var - keyword reserved by JavaScript denoting a variable
  2. imageToToggle - custom identifier for referencing a value by name
  3. = - assignment operator that assigns the value on its right to the identifer on its left
  4. document.getElementById('image-to-toggle') - browser API for referencing a specific HTML element's corresponding JavaScript object
  5. ; - character reserved by JavaScript denoting the explicit end of a code statement

The above five parts make up the anatomy of a declaration and assignment statement. The parts work together to assign the resulting value from the document.getElementById() browser API call to the declared imageToToggle identifier. In subsequent code, the identifier can be used as a shortcut to reference the actual element object and then use its API. It is worth noting that every use of imageToToggle could be replaced with document.getElementById('image-to-toggle'). This approach would work, but it would be less right because we'd be doing the same work more times than needed.

Assigning an executed function's result to a variable identifier is an example of caching. Caching is a great approach for decreasing code volume and increasing execution time performance. The more expensive and time consuming the function call (blocking stack work), the more valuable caching is. Preventing repetitive work is the win with caching.

With respect to making snippet two more right, there is one other thing we could do. We could cache the imageToToggle lookup and assignment outside of the toggleImageOpacity function. In doing so, we would prevent the repetitive work that occurs each time toggleImageOpacity executes. This approach would require the identifier to never be reassigned to continue to work.

Additionally, an even more right approach could be made if imageToToggle's value would be useful to other code within our program. If this was the case then the variable wouldn't exist in the scope just outside the toggleImageOpacity's scope, but could instead exist in a higher level scope via the singleton design pattern. We mentioned this approach in the Principles and Patterns section, but the details are outside the scope of this book. Again, we're just planting seeds here so do not concern yourself with the details. We'll leave the snippet as is for simplicity and because there isn't anything better we can do.

In snippet three there are five parts comprising the line of code:

  // 3. variable declaration and assignment using currentOpacity identifier
  var currentOpacity = window.getComputedStyle(imageToToggle).opacity;

Each part reflects the same general description as snippet two with the exception of window.getComputedStyle(imageToToggle).opacity. This part accesses the nested and specific opacity style object property of the cached imageToToggle element. The opacity property doesn't exist on the imageToToggle object itself and that is why we need the help of the API.

The previous snippet's suggestion to cache the identifier outside the toggleImageOpacity function is problematic in this snippet though. The difference is that currentOpacity is something we want to lookup each time the function executes. This is a requirement if we want an up-to-date opacity value. A change like this would result in a less right and ultimately broken set of code. Caching the style object returned from the getComputedStyle(imageToToggle) call outside the function scope could be considered more right however. Nothing better is possible.

In snippet four there are seven parts comprising the line of code:

// 4. 'if' portion of an if/else conditional statement
if(currentOpacity == 1) {
  1. if - keyword reserved by JavaScript denoting conditional code execution
  2. ( - opening paren for declaring the if condition beginning
  3. currentOpacity - custom identifier for referencing a value by name
  4. == - loose equality that coercively compares values on each side and produces a true or false value
  5. 1 - a literal number value
  6. ) - closing paren for declaring the if condition end
  7. { - opening curly brace for declaring the beginning of the if-condition code block
    • } - a closing curly brace is expected to declare its end

The above seven parts make up the anatomy of an if statement. First, the if keyword tells the JavaScript engine your intent to define a condition to control execution flow. When the condition is true, the code between its { and } will execute. If the condition is false, then the code block is skipped. The beginning ( and ending ) parens define the space where the condition in question resides. This condition is the comparison between the value in the currentOpacity identifier and the number value 1. We will cover this again later, but = is used to assign where == is used to compare.

With respect to making snippet four right and better, we enter subjective changes. This subjectivity sources from a deeper understanding of JavaScript:

  1. Implicit coercion
  2. Optional braces

Implicit coercion is a nuanced sub-system of JavaScript. Coercion is a fancy word for interpreting a value in one form as another form. We'll leave the details to the next chapter, but just know that loose equality == allows coercion where strict equality === does not. Put another way, loose equality allows interpretation where strict equality does not.

Optional braces are an authoring time convenience for more succinct code writing. The snippet will remain as-is for now as many sub-systems and their caveats do not need to be learned to make code work.

In snippet five there are four parts comprising the line of code:

// 5. property assignment using imageToToggle reference
imageToToggle.style.opacity = .5;
  1. imageToToggle.style.opacity - nested identifier
  2. = - assignment operator that assigns the value on its right to the identifer on its left
  3. .5 - a literal number value
  4. ; - character reserved by JavaScript denoting the explicit end of a code statement

The above four parts make up the anatomy of an assignment statement. This snippet has one small difference compared to snippet two. Where snippet two has a declaration and an assignment, this snippet only has the latter. The assumption made is that the nested identifiers style and opacity already exist. As a result, a simple assignment using = can be made.

Regarding right and better, we could cache the imageToToggle.style lookup. Technically speaking, each time the imageToToggle.style.opacity portion executes there is repetitive lookup work the engine has to do. We will not make this change as the performance benefit is negligible. This will be learned in time, but changes to increase performance should only be considered when the target frame rate or user experience suffers. Put another way, "premature optimization is the root of all evil". This exact quote is from Donald Knuth, a heavilty respected and influential coder. We will take his advice.

In snippet six there is only one part comprising the line of code:

// 6. end of 'if'
}
  1. } - closing curly brace for declaring the end of the if-condition code block

This closing curly brace simply defines the end of the if statement's code block. Nothing right or better is possible.

In snippet seven there are two parts comprising the line of code:

// 7. 'else' portion of an if/else conditional statement
else {
  1. else - keyword reserved by JavaScript denoting conditional code execution
  2. { - opening curly brace for declaring the beginning of the else-condition code block
    • } - a closing curly brace is expected to declare its end

The above two parts make up the anatomy of an else statement. The else is an optional execution flow that follows an if or else if statement. When the corresponding if or else if condition is false, the code between the else's { and } code block will execute. The if/else allows a program to branch, to have conditional execution flow at execution time. Specifically in our toggleImageOpacity function, we use this tactic to ping-pong, or toggle, an image's opacity between the values 1 and .5. Put another way, the program toggles the image's opacity between fully opaque (100%) and half transparent (50%). There is nothing right or better to do with this snippet.

In snippet eight there are four parts comprising the line of code:

// 8. property assignment using imageToToggle reference
imageToToggle.style.opacity = 1;
  1. imageToToggle.style.opacity - nested identifier
  2. = - assignment operator that assigns the value on its right to the identifer on its left
  3. 1 - a literal number value
  4. ; - character reserved by JavaScript denoting the explicit end of a code statement

Everything covered in snippet five can be said of this snippet. The only difference is the use of the literal value 1 in place of .5.

In snippet nine there is one part comprising the line of code:

// 9. end of 'else' 
}
  1. } - closing curly brace for declaring the end of the else-condition code block

This closing curly brace simply defines the end of the else statement's code block. There are no right or better improvements that are possible with this particular snippet. There is a better change possible when considering the entire if/else as a whole however. Snippets four through nine can be encapsulated more succintly using the ternary operator. The ternary operator does the same work as an if/else, but does so more succinctly (often in a single line of code):

// Ternary operator alternative to an if/else that encapsulates snippets four through nine
imageToToggle.style.opacity = currentOpacity == 1 ? .5 : 1;

This is admittedly an advanced code statement, but it is functionally identical to the if/else. We won't go into its anatomy, but you could probably guess how it works. It is better for advanced JavaScript coders and less so for beginner coders. Subjectivity is at play.

In snippet ten there is one part comprising the line of code:

// 10. end of toggleImageOpacity function
}
  1. } - closing curly brace for declaring the end of the function body
    • { - an opening curly brace is expected before the function body for declaring its beginning
    • the { and } define the scope boundary of a function

This closing curly brace simply defines the end of the toggleImageOpacity function. There are no right or better improvement possibilities.

In this section we introduced some of the vocabulary, concepts, and considerations of advanced coders. Overwhelming I know. Hopefully a few things made sense though. Regardless, seeds should be planted that will bear fruit later in your learn-to-code journey.

In the next chapter Coding and JavaScript we will bypass much of this advanced material in favor of a simplified approach. As you progress as a coder you can begin to make code right and better. Until then, the goal is to make code that works. Let's do this.