Referring to non-widget objects in Dojo without "polluting" global namespace - javascript

What's a clean best practice for keeping track of and referring to general JavaScript objects - most likely Dojo-declared - that may have been declared in one area (read module) of an application but that need to be used in another area? We're assuming AMD here.
As mentioned by the "Non-Widgets" section of Dojo's "Using Declarative Syntax" reference guide:
... regular objects don't have a registry like Dijit based widgets do, therefore in order to be able to reference them after you instantiate them, you have to create a reference to them in the global scope.
Global scope? Rrraaughh?! One of the biggest things about "Modern Dojo" is the frowning upon willy-nilly usage of the global namespace:
One of the core concepts of "modern" Dojo is that things in the global namespace are bad. There are numerous reasons for this, but in a complex web application, the global namespace can easily become polluted with all manner of code [...]. This means in "modern" Dojo, if you are about to access something in the global namespace STOP because you are doing something wrong.
Also, from that guide:
Again, repeat after me "the global namespace is bad, the global namespace is bad, I will not use the global namespace, I will not use the global namespace".
In light of that, have there been any other popular ideas expressed about maybe having a general-purpose object registry that exists in the application's context? Is it feasible or perhaps obvious to just Dojo-define a module whose sole purpose is to be a mixed bag of references to objects that get used throughout the application?

Related

Is it a good idea to mutate Node's global object?

Is it a good idea to add properties to Node's global object? Searches for this lead me to a discussion of global variables in Node, and frankly I can't find much about the global object for some reason.
From my understanding, global in Node is analogous to the window object that's used in the conventional JS environment, and mutating that is generally frowned upon.
I ask because I'm using Electron whose docs list all sorts of examples that use global, and they even provide an API that lets us set/get global properties from other processes.
From a recent code review, my team was asked to replace the use of global with our own Node module so to avoid overwriting important global attributes set by Node/Electron/3rd party resources.
This seems like a good idea, but why then does Electron recommend the use of global? Why is that the paradigm?
Taking a closer look at the examples, it looks like they recommend only adding one property to the global (sharedObject), so this isn't as bad as I thought, but is this good enough, or should I really take the time to create a separate Node module?
Perhaps this is an opinion-based question.

JS: Best practice on global "window" object

Following a rapid-prototyping approach, I am developing an application in Marionette.js/backbone.js and heavily used the window-object to bind collections and views to the global stack (e.g. window.app.data, window.app.views).
Of course, it is always better (smoother!) to encapsulate objects in a single class and pass them as parameters where needed. However, this has some limitations when an app and its potential use-cases become really big. And as the data I deal with comes from an API and therefore would be anyway accessible to anybody interested, does that justify storing data in the window-object? Or are there other best-practices in ES6 (or especially Marionette.js) to achieve the same results, but in a more private manner?!
I already go into details about a simple namespacing pattern in JavaScript in another answer. You seem to be already close to this with window.app.data etc.
But it looks like you have a lot of misconceptions about how JavaScript works.
a namespace-based solution that integrates nicely with Browserify/AMD-modules
Then why not use RequireJS? Browserify? or Webpack? There's nothing that a global ridden spaghetti code can do that a modular approach can't do better.
such would be read-only
No. While not impossible to set an object property to read-only, you must explicitly do it with something like Object.seal or Object.freeze.
I do not want to attach objects to the namespace, but actual instances
JavaScript do not have "namespaces" as part of the language, it's just a pattern to scope all your code within literal objects (key-value).
You can put whatever you'd like.
const MyNamespace = {
MyType: Backbone.Model.extend({ /*...*/ }),
instance: new Backbone.Model(),
anyValue: "some important string",
};
Ideally, you would define the namespace within an IIFE to avoid leaking any variable to the global scope.
const app = app || {};
app.MyModel = (function(app){
return Backbone.Model.extend({
// ...
});
})(app);
[...] data I deal with comes from an API and therefore would be anyway accessible to anybody interested
Even if the data is contained within a module that do not leak to the global scope, anybody can access the data. That's how JavaScript works, it's in the user's browser, he can do whatever he wants with the code and the data.
does that justify storing data in the window-object?
No.
Or are there other best-practices in ES6
ES6 has nothing to do with the architecture and patterns you take for your app.
but in a more private manner?!
Like I said earlier, privacy in JavaScript can't be expected.
[encapsulate objects in a single class and pass them as parameters where needed] has some limitations when an app and its potential use-cases become really big.
That's just incorrect. It's the other way around. Software patterns exist solely to help alleviate any limitations that arise as a project grows in scope.
There are multiple patterns you can use that will help deal with the complexity of a bigger app, like:
Modular approach with components
Dependency injection
Service containers
Factories
Events
etc.
I didn't read specifically this book, but JavaScript Design Patterns seems to be a good way to learn more and it demonstrates specific implementations of software patterns in JS.

Why using $rootScope with functions is not recommended?

While am looking into the FEQs of Angularjs I've seen below article:
$rootScope exists, but it can be used for evil
Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope. Since the scopes inherit from the root scope, these values will be available to the expressions attached to directives like ng-show just like values on your local $scope.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language. In particular, don't use it for code, only data. If you're tempted to put a function on $rootScope, it's almost always better to put it in a service that can be injected where it's needed, and more easily tested.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
— AngularJS FAQ - $rootScope exists, but it can be used for evil
So My doubt is why $rootScope is not recommended for functions as a global function? Is there any performance issue?
I've answered this in the past, but it's good that you're asking these questions.
$rootScope exists, but it can be used for evil Scopes in Angular form a hierarchy, prototypally inheriting from a root scope at the top of the tree. Usually this can be ignored, since most views have a controller, and therefore a scope, of their own.
Non-isolated scopes are hierarchical, but most developers should be using directives that have isolated scopes. The very hierarchical nature of AngularJS's scope is the source of many bugs in angular apps. It's a problem I like to call scope bleeding where a scope property is modified magically somewhere in the DOM tree and you don't know why.
Angular's default behavior is to inherent scopes and this makes it tempting for one controller to update something managed by another controller, so on, and so on. This is how spaghetti connections between source code is created. Making it very difficult to maintain that code.
Occasionally there are pieces of data that you want to make global to the whole app. For these, you can inject $rootScope and set values on it like any other scope.
No that's not correct. AngularJS allows you to define things like constants, values, and services. These are things that can be injected into routes, controllers and directives. That is how you make things accessible globally to your app, and this how you do it if you want to make your controllers or directives testable. A unit test writer doesn't know what properties should be in the $rootScope that a directive or controller depends upon. They have to assume that the $rootScope has not mutated to provide a service or data.
Of course, global state sucks and you should use $rootScope sparingly, like you would (hopefully) use with global variables in any language.
The problem isn't $rootScope but what people are doing with it. Many apps add the current user, the auth tokens, and the session data into the rootScope. This ends up getting used heavily in templates (shows X if user logged in otherwise show Y). The problem is that the HTML doesn't communicate scope hierarchy. So when you see {{user.firstname + ' ' + user.lastname}} you have no idea where the variable user came from. The second problem is child scopes can shadow root properties. As in the previous example if a directive does this scope.user = 'bla bla bla'. It hasn't replaced the value on the rootScope. It's hidden it. Now you get some strange unexpected things in the templates, and you don't know why the variable user has changed.
Conversely, don't create a service whose only purpose in life is to store and return bits of data.
Angular's $cacheFactory and $templateCache are examples of services that exist only too store data. I think the author was trying to encourage the use of constants and values in Angular's modules, but that's not a good description to do that.
So My doubt is why $rootScope is not recommended for functions as a global function? Is there any performance issue?
The $rootScope is the only scope available during angular.config(..). It's during this time that the scope can be modified if this is the only time that you can do it. For example; you may need to inject an API key or Google anayltics variable before the app starts.
Functions on any scope are generally a bad idea. Mainly for the reason that everything in scopes is digested in expressions on the templates. Functions tent to hide heavy operations. It's impossible to tell how heavy a template is by reading the HTML when it calls a function. I've seen scope functions like getHeight() where the function itself performed 3 levels of nested loops. That function has to get called every time angular digests the watchers to see if it's changed. You should try to keep your templates as dry as possible.
Global Variables are Abused
$rootScope is pretty much a global variable and has its place but is definitely abused by most of the people that use it. These are the reasons Globals in general should not be used.
Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.
No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.) By extension, the lack of access control greatly hinders achieving security in situations where you may wish to run untrusted code (such as working with 3rd party plugins).
Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.
Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected). When dynamically linking modules with globals, the composed system might not be thread-safe even if the two independent modules tested in dozens of different contexts were safe.
Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.
Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.
Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. More generally, source that utilizes global services of any sort (e.g. reading and writing files or databases) that aren't explicitly provided to that source is difficult to test for the same reason. For communicating systems, the ability to test system invariants may require running more than one 'copy' of a system simultaneously, which is greatly hindered by any use of shared services - including global memory - that are not provided for sharing as part of the test.
Source: http://c2.com/cgi/wiki?GlobalVariablesAreBad
Sharing data in Angular
When it comes to sharing data across controllers in Angular you should use a service. With your custom service you can create a getter and a setter method. You inject it to the controllers you need it and can use it in your app.
There exist no performance issues. It would actually boost your performance by a fraction of time, because you dont need to dependency-inject a lot of services.
But it's a big concern of design. Consider a large application with dozens and dozens of views, complex components and tied to a number of well known APIs (e.g. Twitter, Flickr, Facebook, OAuth, ...).
You wont develop this application alone. The following issues will arise:
Namespacing
You are working on the Facebook API, someone else is working on the Twitter API. You both think that using $rootScope for functions is a good idea and both write a $rootScope.login function. How would you resolve this when doing git merge? You need namespacing, alas, you need to develop two services myFacebookAPI, myTwitterAPI which then can implement the same interface for loggin in. (login(user,pw)). Note that this gives you the ability to abstract away the actual social network you are dealing with in the controller, when you can do something like:
$scope.callAction = function (action) {
var service;
if ($scope.serviceSelected === 'fb') {
service = myFacebookAPI;
} else {
service = myTwitterAPI;
}
service[action]();
};
Testing
When developing professionally, you write tests. Angular gives you tools to do automated tests for services, etc., but you wont be able to test something you assign to $rootScope in the same comfortable manner.
Other issues will arise too, but i think this should be enough for you to think about it on your own.

What does Crockford mean: "Javascript depends on global variables for linkage"?

In Javascript: The Good Parts Crockford writes that "Javascript depends on the global variable for linkage." I understand that in javascript if you declare a variable outside a function it "is in the global namespace" -- meaning you can access it anywhere in the program. I sort of understand how linkage limits where in a C++ program you can access a variable (regardless of its scope). With that said, what does Crockford mean?
I think what he means is that global variables are how you communicate with libraries. For example jquery uses the global variable $, underscore uses _, etc. You link to the libs through a global name.
Continuing
All the top-level variables of all compilation units are tossed
together in a global namespace called the global object. This is a bad
thing because global variables are evil, and in JavaScript they are
fundamental. Fortunately, as we will see, JavaScript also gives us the
tools to mitigate this problem.
What Crockford is referring to, I think, is the absence of module or namespace-like mechanisms in JS to segregate and modularize chunks of functionality at a macro level, where those chunks are explicit about what they are exposing (export), or what they are using from other chunks (import). However, as he points out, JS does provide the ability, albeit imperfectly, to do this through existing language features, and the world has not come to an end. At the same time, this problem is now being addressed on a number of fronts, notably the ES6 module mechanism.

Nodejs global variables and modules

Are there any security issuses or something with using global variables and assignig modules to global variables in nodejs?
example:
client = new Client();
Without the var statement, so i can use it everywhere?
It's not that it's a security problem, it's considered bad practice though and it can lead to other problems such as trying to override a Node.js global variable.
Try not to pollute the global namespace and if you really really need global variables, just use one with sub-objects.
I don't think there are security issues per se, but you will be polluting the global namespace. As your project grows (especially with more than one programmer) the risk of conflicts gets bigger. And what if you later on add a third party library to your project that has a variable named 'client'?
I've been using Node for a couple of years and I had the same "problem" you have and is frustrating. Nevertheless I can give you the solution I reached and it works for me.
Node doesn't allows global variables in the way you ask since variables defined as global in a module are global only for that module. But exists a GLOBAL object that ban be used for what you need.
Global variables are a bad idea in general (always), but having a global cache of useful functions in it's own namespace is not a crime at all since it will not override anything and lets you use it along your code. So I'll tell you what I do to share functions and objects between modules and keep source organized (that's important for me at least!):
1st Create a resource file where you place all important functions and objects you want to share across your code. I call mine "R.js", R from Resources
2st Define the "R" object that will store all functions and objects and assign it to node's GLOBAL object:
var R = {};
GLOBAL.R = R; // Adds resource module to global
3rd For sake of simplicity and avoid extra requires all arround the code, I do all needed requires inside R.js. After that you only need to use them with R.require_variable.function_or_property
// All needed requires
R.fs = require('fs');
R.net = require('net');
R.http = require('http');
R.dbClient = require('mysql').Client;
...
4th Create the shared functions, variables and objects you like inside the R object
5th Where needed arround your code, require the R.js file and access to it's member by using the R object
R.<property_or_function>
2 warning notes.
Remember to always call shared functions or user shared objects placind "R." in front of it
Althought you can assign new functions, objects and properties to R object anywhere this can lead to the same inconsistencies you would have with global variables if you don't plan it in advance - i.e. you call a shared function before assigning it to R - so as a methodology, create everything in the R.js file instead of doing it all arround your code. This way all shared things will be in R.js and that is the only place to look for shared code.

Categories

Resources