Translate

Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Tuesday, February 19, 2019

Imperative vs. Declarative JavaScript

In this corner, weighing in at 7 lines of code, we have an imperative JS function, and in this corner, coming in at a lean, mean 2 LoC, declarative! Let's get ready to rumble!

 by Cliff Hall·Feb. 12, 2019
Source: https://dzone.com/articles/imperative-vs-declarative-javascript

I was recently doing a JavaScript code review and came across a chunk of classic imperative code (a big ol' for loop) and thought, here's an opportunity to improve the code by making it more declarative. While I was pleased with the result, I wasn't 100% certain how much (or even if) the code was actually improved. So, I thought I'd take a moment and think through it here.

Imperative and Declarative Styles


To frame the discussion, imperative code is where you explicitly spell out each step of how you want something done, whereas with declarative code you merely say what it is that you want done. In modern JavaScript, that most often boils down to preferring some of the late-model methods of Array and Object over loops with bodies that do a lot of comparison and state-keeping. Even though those newfangled methods may be doing the comparison and state-keeping themselves, it is hidden from view and you are left, generally speaking, with code that declares what it wants rather being imperative about just how to achieve it.

The Imperative Code


Image title

Let's break down the thought process required to figure out what's going on here.

  1. JavaScript isn't typed, so figuring out the return and argument types is the first challenge.
  2. We can surmise from the name of the function and the two return statements that return literal boolean values that the return type is boolean.
  3. The function name suggests that the two arguments may be arrays, and the use of needle.length and haystack.indexOf confirms that.
  4. The loop iterates the needle array and exits the function returning false whenever the currently indexed value of the needle array is not found in the haystack array.
  5. If the loop completes without exiting the function, then we found no mismatches and true is returned.
  6. Thus, if all the values of the needle array (in any order) are found in the haystack array, we get a true return, otherwise false.

The Declarative Code


Image title

Note: Tip o' the propeller beanie to Michael Luder-Rosefield who offered this solution which is much simpler than the previous version which used reduce. 

That took fewer lines, but you still have to break it down to understand what it's doing. Let's see how that process differs.

  1. JavaScript isn't typed, so figuring out the return and argument types is the first challenge.
  2. We can surmise from the name of the function and the returned result of an array's every  method that the return type is boolean.
  3. The function name suggests that the two arguments may be arrays, as do the default values now added to the arguments for safety.
  4. The  needle.every call names its current value  el, and checks if it is present in the haystack array using  haystack.includes.
  5. The  needle.every call returns true or false, telling us, quite literally, whether every element in the needle array is included in the haystack array.

Comparisons


Now, let's weigh the relative merits of each implementation.

Imperative


Pros


  1. The syntax of the venerable for loop is known by all.
  2. The function will return immediately if a mismatch is found.
  3. The for loop is probably faster (although it doesn't matter much at the small array size we're dealing with).

Cons

  1. The code is longer: 7 lines, 173 characters.
  2. Having two exits from a function is generally not great, but to achieve a single exit, it would need to be slightly longer still.
  3. While the loop does iterate the entire length of the needle array, it has to be explicit about it, and we need to visually verify the initializer, condition, and increment inspection. Bugs can creep in there.
  4. Comparing the result of the haystack.indexOf call to -1 feels clunky because the method name gives you no hint about what it will return if the item isn't found (-1 as opposed to null or undefined).

Declarative

Pros

  1. The code is shorter: 2 lines, 102 characters.
  2. The function will return immediately if a mismatch is found.
  3. The result of a single expression is returned, so right away it's obvious what the function is attempting to do.
  4. The use of needle.every feels satisfying, because the method name implies that we'll get a true or false result, AND we don't have to explicitly manage an iteration mechanism.
  5. The use of haystack.includes feels satisfying, because the method name implies that we'll get a true or false result, AND we don't have to compare it to anything.

Cons

  1. The every call is probably slower (although it doesn't matter much at the small array size we're dealing with).

Conclusion

Both of these implementations could probably be improved upon. For one thing, and this has nothing to do with imperative vs declarative, the function name and arguments could be given clearer names. The function name seems to indicate that we want to know if one of the arrays is an element of the other. The argument names actually seem to reinforce that. In fact, we just want to know if the contents of the two arrays match, disregarding order. This unintended misdirection creates mental friction that keeps us from readily understanding either implementation upon first sight.

Aside from naming issues, it looks like the declarative approach has more pros than cons, so on a purely numerical basis, I'm going to declare it the winner.

Implementing declarative code is widely expected to enhance readability. How it affects performance is another question, and one that should certainly be considered, particularly if a lot of data is being processed. If there isn't much performance impact, then a more readable codebase is a more manageable codebase.

If you see other pros or cons I missed for either of these contenders, or take issue with my approximation of their merits, please feel free to leave your comments. And again, thanks to Michael Luder-Rosefield for doing just that on the Medium version of this post.

Saturday, December 29, 2018

Domain-Driven Design in JavaScript


Let DDD bring order to your JavaScript chaos

Credits to: Ewan Valentine
Source: https://dzone.com/articles/domain-driven-design-in-javascript


I wouldn't class myself as a JavaScript developer, I always joke that it's a language I never meant to learn. It's so pervasive now, it just happened. I go through phases of enjoying it and despising it. But through the peaks and troughs of love and not quite hate. One problem persisted: if I'm to be a good JS developer and write functional JavaScript, how then do I write code in a way that implies a proper domain model?

In traditional OO languages, such as Java, C#, and even Go actually, it's easy to write code that's architected around a domain design. You have classes, which are big and do a lot of stuff. Which of course is something you generally avoid like the plague in JavaScript, for fair enough reasons.

However, my code always seemed to end up looking like this:

const { getUser, removeUser } = require('services/user');

const { sendEmail } = require('helpers/email');

const { pushNotification } = require('helpers/notifications');

const { removeFilesByUserId } = require('services/files');

const removeUserHandler = await (userId) => {

  const message = 'Your account has been deleted';

  try {

    const user = await getUser(userId);

    await removeUser(userId);

    await sendEmail(userId, message);

    await pushNotification(userId, message);

  } catch (e) {

    console.error(e);

    sendLogs('removeUserHandler', e);

  };

  return true;

};



This looks okay, right? Sure! No big problems here design-wise. However, when you have a large codebase entirely made up of files such as this, in other words directories full of vaguely grouped 'services,' individually exporting and importing single functions, often vaguely named, and not obviously belonging to a domain when reading through the code, it can very quickly feel as though you're dealing with a big ball of unrelated scripts, rather than a well-architected software application.

I didn't want to return to classes and traditional encapsulation. It felt like a step back after learning 'the functional way™️. But, increasingly, I was finding JavaScript projects difficult to read, 'bitty' and fragmented. I was seeing this everywhere, too! It wasn't just my own hapless downfall. It seemed really common to see JS projects with little to no design or architecture. I was ready to toss JS into the bin for good and resume my position in the Golang ivory tower.

Until one of my engineers slipped a new feature into one of our most noisy codebases, which jolted my attention.

Peering through reams and reams of JavaScript, suddenly something stood out in a PR.

ScheduledJobs.run(jobId);

const job = await ScheduledJobs.get(jobId);



Huh. Is that, a class? Surely not. We don't do that here! No!

const run = (jobId) => {};

const stop = (jobId) => {};

const pause = (jobId) => {};

const get = (jobId) => {};

module.exports = {

 run,

 stop,

 pause,

 get,

};



Praise Dijkstra, they're just functions! Good old-fashioned functions. Suddenly I felt so, so very silly for deliberating, Googling manically for weeks and weeks, and posting lengthy diatribes on Twitter about how JavaScript was done; not fit for public consumption. When all I needed to do was use what JavaScript gave me for this exact purpose: modules! I got so caught up in trying to follow a paradigm that I forgot to be pragmatic.

If I refactored my first arbitrary example to use this pattern, in order to follow a domain design, maybe I'd have something more like this:

const UserModel = require('models/user');

const EmailService = require('services/email');

const NotificationService = require('services/notification');

const FileModel = require('models/file');

const Logger = require('services/logger');

const removeUserHandler = await (userId) => {

  const message = 'Your account has been deleted';

  try {

    const user = await UserModel.getUser(userId);

    await UserModel.removeUser(userId);

    await EmailService.send(userId, message);

    await NotificationService.push(userId, message);

    return true;

  } catch (e) {

    console.error(e);

    Logger.send('removeUserHandler', e);

  };

  return true;

};



This code tells me so much more already!

I began writing my JavaScript in this way, centered around these objects of grouped functions, which can still be used in a functional way. But this pattern communicates purpose much better than dealing in lots of single, un-grouped function calls. I find it made code easier to follow, having that indicator of where this piece of code fits into the bigger picture.

It was so simple in the end, and it was something I already knew, even something I had already used hundreds of times in the past. It all seemed so obvious! But it's easy to neglect concepts such as DDD in languages like JavaScript, especially when you're on the pursuit to functional enlightenment! But there is a happy medium.


Tuesday, November 13, 2018

Top 10 JavaScript errors from 1000+ projects (and how to avoid them)

Source: https://rollbar.com/blog/top-10-javascript-errors
To give back to our community of developers, we looked at our database of thousands of projects and found the top 10 errors in JavaScript. We’re going to show you what causes them and how to prevent them from happening. If you avoid these "gotchas," it'll make you a better developer.

Because data is king, we collected, analyzed, and ranked the top 10 JavaScript errors. Rollbar collects all the errors for each project and summarizes how many times each one occurred. We do this by grouping errors according to their fingerprints. Basically, we group two errors if the second one is just a repeat of the first. This gives users a nice overview instead of an overwhelming big dump like you’d see in a log file.

We focused on the errors most likely to affect you and your users. To do this, we ranked errors by the number of projects experiencing them across different companies. If we looked only at the total number of times each error occurred, then high-volume customers could overwhelm the data set with errors that are not relevant to most readers.

Here are the top 10 JavaScript errors:

Each error has been shortened for easier readability. Let’s dive deeper into each one to determine what can cause it and how you can avoid creating it.

1. Uncaught TypeError: Cannot read property


If you’re a JavaScript developer, you’ve probably seen this error more than you care to admit. This one occurs in Chrome when you read a property or call a method on an undefined object. You can test this very easily in the Chrome Developer Console.






This can occur for many reasons, but a common one is improper initialization of state while rendering the UI components. Let’s look at an example of how this can occur in a real-world app. We’ll pick React, but the same principles of improper initialization also apply to Angular, Vue or any other framework.

class Quiz extends Component {
  componentWillMount() {
    axios.get('/thedata').then(res => {
      this.setState({items: res.data});
    });
  }

  render() {
    return (
      <ul>
        {this.state.items.map(item =>
          <li key={item.id}>{item.name}</li>
        )}
      </ul>
    );
  }
}

There are two important things realize here:

  1. A component’s state (e.g. this.state) begins life as undefined.
  2. When you fetch data asynchronously, the component will render at least once before the data is loaded – regardless of whether it’s fetched in the constructor, componentWillMount or componentDidMount. When Quiz first renders, this.state.items is undefined. This, in turn, means ItemList gets items as undefined, and you get an error – "Uncaught TypeError: Cannot read property ‘map’ of undefined" in the console.

This is easy to fix. The simplest way: Initialize state with reasonable default values in the constructor.

class Quiz extends Component {
  // Added this:
  constructor(props) {
    super(props);

    // Assign state itself, and a default value for items
    this.state = {
      items: []
    };
  }

  componentWillMount() {
    axios.get('/thedata').then(res => {
      this.setState({items: res.data});
    });
  }

  render() {
    return (
      <ul>
        {this.state.items.map(item =>
          <li key={item.id}>{item.name}</li>
        )}
      </ul>
    );
  }
}

The exact code in your app might be different, but we hope we’ve given you enough of a clue to either fix or avoid this problem in your app. If not, keep reading because we’ll cover more examples for related errors below.

2. TypeError: ‘undefined’ is not an object (evaluating


This is an error that occurs in Safari when you read a property or call a method on an undefined object. You can test this very easily in the Safari Developer Console. This is essentially the same as the above error for Chrome, but Safari uses a different error message.




3. TypeError: null is not an object (evaluating


This is an error that occurs in Safari when you read a property or call a method on a null object. You can test this very easily in the Safari Developer Console.




Interestingly, in JavaScript, null and undefined are not the same, which is why we see two different error messages. Undefined is usually a variable that has not been assigned, while null means the value is blank. To verify they are not equal, try using the strict equality operator:

Screenshot of TypeError: null is not an object

One way this error might occur in a real world example is if you try using a DOM element in your JavaScript before the element is loaded. That’s because the DOM API returns null for object references that are blank.

Any JS code that executes and deals with DOM elements should execute after the DOM elements have been created. JS code is interpreted from top to down as laid out in the HTML. So, if there is a tag before the DOM elements, the JS code within script tag will execute as the browser parses the HTML page. You will get this error if the DOM elements have not been created before loading the script.

In this example, we can resolve the issue by adding an event listener that will notify us when the page is ready. Once the addEventListener is fired, the init() method can make use of the DOM elements.

<script>
  function init() {
    var myButton = document.getElementById("myButton");
    var myTextfield = document.getElementById("myTextfield");
    myButton.onclick = function() {
      var userName = myTextfield.value;
    }
  }
  document.addEventListener('readystatechange', function() {
    if (document.readyState === "complete") {
      init();
    }
  });
</script>

<form>
  <input type="text" id="myTextfield" placeholder="Type your name" />
  <input type="button" id="myButton" value="Go" />
</form>

4. (unknown): Script error



The Script error occurs when an uncaught JavaScript error crosses domain boundaries in violation of the cross-origin policy. For example, if you host your JavaScript code on a CDN, any uncaught errors (errors that bubble up to the window.onerror handler, instead of being caught in try-catch) will get reported as simply "Script error" instead of containing useful information. This is a browser security measure intended to prevent passing data across domains that otherwise wouldn’t be allowed to communicate.

To get the real error messages, do the following:

1. Send the Access-Control-Allow-Origin header

Setting the Access-Control-Allow-Origin header to * signifies that the resource can be accessed properly from any domain. You can replace * with your domain if necessary: for example, Access-Control-Allow-Origin: www.example.com. However, handling multiple domains gets tricky, and may not be worth the effort if you’re using a CDN due to caching issues that may arise. See more here.

Here are some examples on how to set this header in various environments:

Apache

In the folders where your JavaScript files will be served from, create an .htaccess file with the following contents:

Header add Access-Control-Allow-Origin "*"

Nginx

Add the add_header directive to the location block that serves your JavaScript files:

location ~ ^/assets/ {
    add_header Access-Control-Allow-Origin *;
}

HAProxy

Add the following to your asset backend where JavaScript files are served from:

rspadd Access-Control-Allow-Origin:\ *

2. Set crossorigin="anonymous" on the script tag

In your HTML source, for each of the scripts that you’ve set the Access-Control-Allow-Origin header for, set crossorigin="anonymous" on the SCRIPT tag. Make sure you verify that the header is being sent for the script file before adding the crossorigin property on the script tag. In Firefox, if the crossorigin attribute is present but the Access-Control-Allow-Origin header is not, the script won’t be executed.

5. TypeError: Object doesn’t support property


This is an error that occurs in IE when you call an undefined method. You can test this in the IE Developer Console.

Screenshot of TypeError: Object doesn’t support property

This is equivalent to the error "TypeError: ‘undefined’ is not a function" in Chrome. Yes, different browsers can have different error messages for the same logical error.

This is a common problem for IE in web applications that employ JavaScript namespacing. When this is the case, the problem 99.9% of the time is IE’s inability to bind methods within the current namespace to the this keyword. For example, if you have the JS namespace Rollbar with the method isAwesome. Normally, if you are within the Rollbar namespace you can invoke the isAwesome method with the following syntax:

this.isAwesome();

Chrome, Firefox and Opera will happily accept this syntax. IE, on the other hand, will not. Thus, the safest bet when using JS namespacing is to always prefix with the actual namespace.

Rollbar.isAwesome();

6. TypeError: ‘undefined’ is not a function


This is an error that occurs in Chrome when you call an undefined function. You can test this in the Chrome Developer Console and Mozilla Firefox Developer Console.

Screenshot of undefined is not a function

As JavaScript coding techniques and design patterns have become increasingly sophisticated over the years, there’s been a corresponding increase in the proliferation of self-referencing scopes within callbacks and closures, which are a fairly common source of this/that confusion.

Consider this example code snippet:

function clearBoard(){
  alert("Cleared");
}

document.addEventListener("click", function(){
  this.clearBoard(); // what is “this” ?
});

If you execute the above code and then click on the page, it results in the following error "Uncaught TypeError: this.clearBoard is not a function". The reason is that the anonymous function being executed is in the context of the document, whereas clearBoard is defined on the window.

A traditional, old-browser-compliant solution is to simply save your reference to this in a variable that can then be inherited by the closure. For example:

var self=this;  // save reference to 'this', while it's still this!
document.addEventListener("click", function(){
  self.clearBoard();
});

Alternatively, in the newer browsers, you can use the bind() method to pass the proper reference:

document.addEventListener("click",this.clearBoard.bind(this));

7. Uncaught RangeError


This is an error that occurs in Chrome under a couple of circumstances. One is when you call a recursive function that does not terminate. You can test this in the Chrome Developer Console.

Screenshot of Uncaught RangeError: Maximum call stack

It may also happen if you pass a value to a function that is out of range. Many functions accept only a specific range of numbers for their input values. For example, Number.toExponential(digits) and Number.toFixed(digits) accept digits from 0 to 100, and Number.toPrecision(digits) accepts digits from 1 to 100.

var a = new Array(4294967295);  //OK
var b = new Array(-1); //range error

var num = 2.555555;
document.writeln(num.toExponential(4));  //OK
document.writeln(num.toExponential(-2)); //range error!

num = 2.9999;
document.writeln(num.toFixed(2));   //OK
document.writeln(num.toFixed(105));  //range error!

num = 2.3456;
document.writeln(num.toPrecision(1));   //OK
document.writeln(num.toPrecision(0));  //range error!

8. TypeError: Cannot read property ‘length’


This is an error that occurs in Chrome because of reading length property for an undefined variable. You can test this in the Chrome Developer Console.

Screenshot of TypeError: Cannot read property ‘length’

You normally find length defined on an array, but you might run into this error if the array is not initialized or if the variable name is hidden in another context. Let’s understand this error with the following example.

var testArray= ["Test"];

function testFunction(testArray) {
    for (var i = 0; i < testArray.length; i++) {
      console.log(testArray[i]);
    }
}

testFunction();

When you declare a function with parameters, these parameters become local ones. This means that even if you have variables with names testArray, parameters with the same names within a function will still be treated as local.

You have two ways to resolve your issue:

  1. Remove parameters in the function declaration statement (it turns out you want to access those variables that are declared outside of the function, so you don’t need parameters for your function):
    var testArray = ["Test"];
    
    /* Precondition: defined testArray outside of a function */
    function testFunction(/* No params */) {
       for (var i = 0; i < testArray.length; i++) {
         console.log(testArray[i]);
       }
    }
    
    testFunction();
    
  2. Invoke the function passing it the array that we declared:
    var testArray = ["Test"];
    
    function testFunction(testArray) {
      for (var i = 0; i < testArray.length; i++) {
         console.log(testArray[i]);
       }
    }
    
    testFunction(testArray);
    

9. Uncaught TypeError: Cannot set property


When we try to access an undefined variable it always returns undefined and we cannot get or set any property of undefined. In that case, an application will throw “Uncaught TypeError cannot set property of undefined.”

For example, in the Chrome browser:

Screenshot of Uncaught TypeError: Cannot set property

If the test object does not exist, error will throw “Uncaught TypeError cannot set property of undefined.”

10. ReferenceError: event is not defined


This error is thrown when you try to access a variable that is undefined or is outside the current scope. You can test it very easily in Chrome browser.

Screenshot of ReferenceError: event is not defined

If you’re getting this error when using the event handling system, make sure you use the event object passed in as a parameter. Older browsers like IE offer a global variable event, and Chrome automatically attaches the event variable to the handler. Firefox will not automatically add it. Libraries like jQuery attempt to normalize this behavior. Nevertheless, it’s best practice to use the one passed into your event handler function.

document.addEventListener("mousemove", function (event) {
  console.log(event);
})

Conclusion


It turns out a lot of these are null or undefined errors. A good static type checking system like Typescript could help you avoid them if you use the strict compiler option. It can warn you if a type is expected but has not been defined. Even without Typescript, it helps to use guard clauses to check whether objects are undefined before using them.

We hope you learned something new and can avoid errors in the future, or that this guide helped you solve a head scratcher. Nevertheless, even with the best practices, unexpected errors do pop up in production. It's important to have visibility into errors that affect your users, and to have good tools to solve them quickly.

Friday, October 5, 2018

React Native App Development, Part 1: A Guide to React Native Architecture




In this post, we briefly discuss the architecture behind the React Native framework, giving a high-level overview of what makes it go.

Source: https://dzone.com/articles/react-native-app-development-part-1-a-beginners-gu
Let’s take a look at one screen from an app that is purely React Native and ask ourselves what is the UI that we see here.
react native mobile app
Is this HTML? Is this a webview like other implementations in PhoneGap or Cordova?
The answer is, without a doubt, no. The views in React Native are purely native views so, from our app, the navigation controller that you see here at the top bar is the UINavigationController. Now, if you are an iOS developer, you would see these are the same UI views that you use in your native apps.
react native FunctionIf I had shown you the same screen on Android, you would see that the implementation is completely different. It renders to the native views. If the UI is completely native with React Native, where is the JavaScript?  

Where Is the JavaScript?

JavaScript is what running under the hood. Where you as a developer specify the business logic and which components you want, and then the framework renders it for you. To understand this better, let's dive into React Native a little deeper and see the architecture from the inside.

Understanding React Native Architecture

Consider that there are two realms running side-by-side in your app. You have the JavaScript realm and you have the native realm.

JavaScript Realm

The JavaScript realm is where you program in JavaScript, naturally. The code there is running on a JavaScript engine. Specifically, React Native uses jscore, an open source JavaScript engine for WebKit. You are probably familiar with other engines like V8. They do the same things and this engine is running inside your app on one of the threads. Your app is a process that has several threads in it. JavaScript is just one of them.

Native Realm

In the native realm, you still develop in Objective-C and/or Swift if you are on iOS or with Java if you are on Android. You use the native, platform-specific languages that you used before and you have the main UI thread as usual. In all platforms, you can usually change the UI only from the main UI thread and you can create as many background threads as you want.

The Bridge

These two realms are different and connecting these two realms is the bridge. React Native is a very important construct in this entire setup. Did you ever try to debug a React Native application using Chrome, for example? So, when you debug a React Native application using Chrome, then you have the two realms actually running on different computers. You can run the JavaScript role entirely inside Chrome itself. You can debug it inside the Chrome debugger and you have the native realm still running on your phone. Then, instead of going inside your app, you would go through a WebSocket. The bridge, which is just a communication protocol, can travel over WebSocket as well.