The king is dead. Long live the king!

The combination of React’s meteoric rise and utter dominance within the frontend framework wars marks a new era. Gone are the days of triggering bubble events to ensure consistent state between view and controller. Gone are the days where one must limit the number of scoped items in the digest cycle to manage performance. And gone are the days programming by way of side effect, the bane of all state management.

The brainchild of Facebook, React allows for the modern-day engineer to write code declaratively. The addition of Redux gives rise to a practical form of functional programming, where state flows from (1) dispatched action, (2) to reducer, and finally (3) to the store. Components connected to redux finally react to changes in state. And instead of segregation by language (HTML, CSS, JavaScript), logic and presentation are colocated in components, the building blocks of React-based UI.

“We know no king, but the King in the North whose name is [functional, unidirectional data flow and component-segregated logic]” – Lady of Bear Island

Screen Shot 2018-05-14 at 4.48.01 PM
React in all it’s glory

The Iron Throne

When looking at the plethora of existing programming languages, one cannot help but notice the raw dominance of JavaScript. It’s interesting to note that JavaScript is also becoming more and more popular over time, especially in the current day.

The combination of JavaScript being so closely tied with modern browsers, the ability to rapidly develop applications (both mobile or otherwise), the rise of new technologies such as Node, Google Chrome’s V8 engine, React, and NPM, its quick learning curve, popularity of JSON, as well as the most recent developments in ECMA standards (ES6 at the moment) all have helped to make JavaScript to become as dominant as it is.

Perhaps I’m biased, but I see JavaScript as quickly becoming the king of software development. Either by way of the iron price or other means.

screen-shot-2016-11-29-at-6-10-25-am

 

ECMAScript 2015

A variety of new syntax and features were added during the ES6 update, much of which I still haven’t gotten around to using. There are certain updates that I really like, such as arrow functions and the introduction of formal classes. Arrow functions help are quite simple to understand and remove a lot of the need for the binding this to the correct context, while classes provide a much-needed standardized approach to object-oriented programming in JavaScript.

Below, I’ve written an example of a few functions in ES6 style.

screen-shot-2016-10-13-at-10-52-07-pm

 

Promising Promises

For anyone who has decided the brave the world of web development, they will have inevitably come across the concept of asynchronous programming. Asynchronous programming refers to the idea that we should allow for some function or piece of code to finish running before firing off another piece of code. In other words, one forces synchronicity for some system that naturally occurs in an asynchronous manner. One such manner of achieving this goal is by using callback functions, as shown below.

Screen Shot 2015-12-29 at 6.28.45 PM

However, using callbacks comes at the cost of readability and potentially lends to a problem known as callback hell, wherein callback functions are stacked back to back. One method of avoiding this issue is by making use of promises. Promises are defined by their distinct ‘.then()’ clause and allow for the writing of more easily understood code at the cost of slight decreases to performance speed. Shown below is one such example of the elegant promise.

Promise Example

Gestalt

The great challenge of the engineer lies not in his or her technical craft but in being able to successfully navigate the social sphere. Pragmatism demands that the team be prioritized over the individual. To that end, raw technical ability is a poor substitute for collaboration and communication.

Prior to my attending Hack Reactor, I thought of programming as existing within a social vacuum. Experience has told me otherwise; a close examination of the topic at hand would reveal that most problems as faced by engineers are primarily social, as opposed to being technical, in nature. As such, the most valuable toolsets an engineer may possess is his or her affability and social adroitness.

Hidden in Plain Sight

Functions carry the ability to retain and access memory within their respective scopes. This legality, in combination with the capacity to return functions, allow for rather interesting code implementations. In the code snippet below, after instance has been called, every function call thereafter results in a return of “after.” Note that due to the lexical nature of JavaScript, the returned function retains access to the scope of the returnOnce function (and therefore the alreadyCalled variable).

Scoping Example

Once this concept of scoping is understood, we may craft considerably more clever functions. In the example below, we take in some unspecified number of functions as arguments. These functions are then saved and set to be applied to the variable parameter at some unspecified time in the future.

Advanced Scoping Example

Droidspeak

A long time ago in a galaxy far, far away… programs were once built and maintained via assembly. This is not the case today; assembler as a language has been reduced (more or less) to a state of obsolescence.

Assembler

 

In the Star Wars universe, Luke Skywalker is able to communicate with his personal astromech droid, R2D2. How Skywalker is able to understand the beeps and whines that R2D2 emits is something of a mystery; the respective manners in which both R2D2 and Skywalker communicate is analogous to the ways in which lower and higher level languages are designed. R2D2 speaks via whirrs and beeps whereas Skywalker exhibits general fluency in Galactic Basic.

By improving upon the level of abstraction, program complexity is more easily concealed. Thus, the modern progression of the programming language is expected to tend toward greater readability.

Javascript High-Level

Inductive Deduction

To the human brain, operations that involve computation and calculation extremely expensive. Thus, the optimal approach (from the perspective of the human) is to attempt to reduce the complexity of the problem at hand. In effect, it is of no surprise that the mathematician tends toward recursion over iteration.

To this end, the programmer is wise to produce algorithms and solutions via mathematical induction. As a general heuristic, it is not necessary to map out every possible event within a recursive call (or set of iterations). In the case of recursion, it is only necessary to understand the base case(s) and the general pattern.

Although quite inefficient in the context of time complexity, the code snippet shown below demonstrates the power of mathematical induction quite well. Thinking through every single combination in the array is largely unnecessary; the intuitive aspect of the algorithm lies with the nested if-statements at the center of the for loops.

Largest Product of Three

Back to the Future

The natural procedure to general problem solving often follows the style set forth by the imperative paradigm: the iterative approach. Then, there is the more elegant (and somewhat more magical) recursive style. It is important to note that while recursion and iteration may be considered to be mathematically equivalent, they are not computationally equivalent.

Recursive Pattern Example

Shown above is a depthFirstSearch function that is designed to move throughout a tree-like structure and to return an array of node values that correctly pass some arbitrary filterFunction. The exact functionality of depthFirstSearch is not particularly relevant; it is the ability to keep track of the node level that interests us. Note the pattern of incrementing and decrementing around the recursive call: this allows us to keep track of how far down we are within the tree. Indeed, as we jump in and out of the explore inner-function, we are thus able to maintain our sense of time and place.

If you are still confused and want to learn more about recursion, click here.

Trading Time and Space

Every program is constrained both by limitations in memory and speed. These constraints work diametrically against one another; improving upon the speed of a program normally comes at the cost of memory (or vice versa). In modern times, it is important to note that memory has become relatively inexpensive in terms of cost. As such, modern concepts of optimization revolve around reducing general time complexity.

Fibonacci Non-Memoize

One example through which the importance of computational speed may be demonstrated is the Fibonacci algorithm. As shown above, the naive implementation of nthFibonacci rapidly decrements in algorithmic speed as its variable n increases. Only for a small numerical parameter would nthFibonacci be useful; larger parameters would take far too long to compute.

Indeed, there is another refactor of nthFibonacci that does not run into the aforementioned problems. In the algorithm listed below, we choose to store our computed values into memory so as to reduce the overall amount of computations taking place. This technique, aptly referred to as memoization, is incredibly useful when making large-scale computations and calculations (one ubiquitous example being Google Maps).

Fibonacci Memoize