Disclaimer: I’m a Node.js newbie.
There’s a number of class-based languages in which you can/must use namespaces to organize your code, for example: Java, PHP, ActionScript 3… For a number of those languages, if you choose/have to use namespaces, there’s generally a set of common practices and conventions that govern project organization then:
Classes form the basic code units, and responsibilities are spread across multiple classes.
The class file hierarchy reside in a single top-level directory (most of the time: src/ or lib/).
Each source file contains a single class definition and nothing else.
Each class resides at a specific level of a namespace (or package) hierarchy, which mirrors the filesystem; for example:
in Java: class com.badlogic.gdx.Application would be found in the src/com/badlogic/gdx/Application.java file
in PHP (with PSR-0): class Symfony\Component\HttpKernel\Kernel would be found in the src/Symfony/Component/HttpKernel/Kernel.php file
Foreign class symbols can be imported into the current scope via a specific statement:
in Java: import com.badlogic.gdx.Application;
in PHP: use Symfony\Component\HttpKernel\Kernel;
I’m used to this type of project organization, but I do realize that it’s specific to class/namespace-based languages and that it might not match JavaScript/Node.js’ usual idioms. If I understand the concept of Node.js modules correctly, it’s 1 source file = 1 module, but from what I’ve seen in a lot of NPM packages, a module usually export more than one symbol, and more often than not those exports are functions and not classes/constructors, so it’s pretty different from the conventions described above.
So, I have the following questions:
In JavaScript/Node.js, is it relevant at all to think about distribution of responsibilities in terms of «classes only» (using either the traditional constructor + prototype composition method or the new class shorthand)?
Is the type of project organization described above possible at all in the context of a Node.js project?
In JavaScript/Node.js, is it relevant at all to think about distribution of responsibilities in terms of «classes only» (or «prototypes only» for that matter)?
In Javascript it's a choice rather than a mandate. You can go full OOP even file structure wise. Or just write modules as pure functions. I'd advise you to stick to the structure that's easier for others, who may want to understand your code, to follow. For example, the OOP style:
Let namespace be the path under src
/src/org/xml/XMLDocument.js
and have a class very similar to the popular OOP languages:
// imports
const fs = require('fs');
const XMLNode = require('./XMLNode');
// class def
class XMLDocument extends XMLNode {
// constructor
constructor(filePath){
...
}
// property getter
get filePath(){
...
}
// method
function getElementsByName(name){
...
}
}
// export class to outer world
module.exports = XMLDocument;
Use the class
// import
const XMLDocument = require('./org/xml/XMLDocument');
// create an instance
const doc = new XMLDocument('./mydoc.xml');
So yes, following an OOP structure is relevant when you tackle the problem the OOP way. And there are alternate ways as well.
Another "creator" oriented custom style:
function createXMLDocument(filePath){
const doc = {};
doc._type = "XMLDocument";
... // make the object have XMLDocument features
return doc;
}
function createDXMLDocument(filePath){
const doc = cerateXMLDocument(filePath);
doc._type = "DXMLDocument";
... // modify parent object with DXML features
return doc;
}
You see, there are some patterns the developer adheres to and write all project code in that style.
Is the type of project organization described above possible at all in the context of a Node.js project?
A Node.js project can have any kind of code organisation because of certain features:
Javascript module system is nothing but referencing a js file present somewhere in file system. So there are no special restrictions on file placement. There are modules that are built in, or can be installed via npm.
Module exports can export one or multiple "things" to external world. So a lot of flexibility here as well.
Javascript itself can be easily written in many styles, functional, OOP, procedural etc. It allows developer to modify a lot of Javascript's own nature. Hence possibly "mimic" many programming styles.
In JavaScript/Node.js, is it relevant at all to think about distribution of responsibilities in terms of «classes only» (or «prototypes only» for that matter)?
To be honest I don't really understand this question. You should follow OOP principles if you use classes, but if you do not, you still need to find cohesion between your functions and organize them in modules and folders based on that.
Is the type of code organization described above usual or relevant at all in the context of a Node.js project, and is it technically implementable without too much trouble?
Javascript modules don't have namespaces, which make things a bit easier (Remember that C# and c++ projects usually have a folder structure totally different than the namespaces). Use folders as namespaces and you'll be fine. There is no such rule that you can only have one class per source file. I usually start writing classes and functions in a single file, and reorganize into multiple files when the file grows big. JavaScript's module system is very flexible, you can organize the code literally any way you want.
If not, what are the traditional ways of handling repartition of responsibilities and code reuse in a Node.js project?
The same as anywhere else.
Related
This question is about ES6 not about global variables.
When the new ES2015 export or export default were introduced. They were made so that you can import/get the same variables, values or items somewhere else using import. So I have a simple question. Why should we use export and import instead of just making a simple object of a class and getting items through it or just making static or global variables?
I know the fact that it can be used to make your code much cleaner and also to put the code easily into multiple files but let's just assume we have first.js and second.js and we have a variable called names in the first.js that we want to get in the second.js. Now you can either do that with import and export or by making an object in the second.js and accessing our variable by that object. So why is it better to use export and import?
export was introduced to be used alongside import (you need to explicitly declare what you need to later import), as part of the ES2015 module standard.
Before these standard modules were implemented, splitting up Javascript code into multiple files and not have all objects pollute the global object was only possible using sort short of non-standard module definition and/or module loaders like RequireJS. The simplest case was to wrap your code in Immediately Invoked Functions. ES6/2015 just standardize Javascipt modules.
Now you asked why not just have Javascript objects even in many files? The answer to that is namespacing
Actually - you make a good point.
namespace stuff is in C++. There are lots of people who think it is cool to have a namespace indicator in front of everything they use.
So, instead of saying { cout << my_string << endl; }, their whole program has { std::cout << my_string << std::endl; }.
Sometimes you see stuff like { disk::io::byte::bit::atom::neutron::quark::say_hi(2) }. And, the guy who wrote that thinks he's a super developer.
But, as they are purist, it more likely you will see { std::cout << myString << endl; } because camel case is so much more preferential than human readable strings.
Now, in node.js I am always doing something like const ClassFromMod = require('mod-with-class'). In the file, you have to say module.exports = ClassDeclaredInHere. I always do this, because really, is there any other way provided?
Or you can do this const {ClassFromMod} = require('mod-with-class').
Then you have to have, module.exports.ClassFromMod = ClassDeclaredInHere.
So, doing the same thing in the browser is sort of OK. But, now global contexts and local contexts are harder to work with - really. Just a little harder sharing things between modules when you have to. But, not to worry almost all of the time people partitions their modules just right. That's because they are people - in fact the sort of people who are more cautious than those in charge of nuclear reactors - because those people do some web programming. So, no Chernobyl when it comes to partitioning modules. Right?
Now, you can get your hands into a class def. And, the class is itself something of a namespace.
So, then why is there not a global registry of classes? Only that maybe different companies (individual developers) will use the same name for two remotely different classes. But, likely there would be some way around that.
One way might be to assign classes to uses (sort of name spacey). But, it might be more categorical. Like "engine" for something with a car feature, or "engine" for something that runs a script. Programming languages might have something like "talking about cars here". What would that be like?
start>> talking about cars <
let bval = engine.rev()
if ( bval ) {
<about scripts> engine.run("small program")
}
<<stop talking about car
That's an idea. Looking at it, I don' like it. It's sort of like "with" that lots of languages use.
So, with new strictures imposed on the programming environments, you get bugs and scope troubles that add to your long long long day. But, you should get that your question drawn from clear thinking is in some sense being steamrolled by a small group of people who can. And, you can take out the trash for them.
So, what about identifying objects by features and enabling sort of a flat namespace management? Could be driven by AI. Could have been done thirty years ago. But, now is now. But, the future exists for correcting the mistakes of the past.
I am learning design pattern in JavaScript, and I'm going to use the module pattern. I'm puzzled with two things.
1 - If I would create a plugin, then I can use the module pattern, and have private and public methods/variables. But if I have a full JavaScript file, I don't need private and public methods, since one part of the program has nothing to do with another part. So what's the point of private and public methods?
2 - Since the JavaScript file is really long, should I have nested module's? How should I go about a full file of JavaScript?
JavaScript has moved on. ES6--which there is no real reason not to move up to, if you haven't already--has its own modules. So there is no need to "simulate" modules with old patterns. Example:
// Old style.
var myModule = function() {
var privateVar;
function getPrivateVar() { return privateVar; }
return {getPrivateVar: getPrivateVar};
}();
console.log(myModule.getPrivateVar());
// New style.
let privateVar;
function getPrivateVar() { return privateVar; }
export {privateVar};
// Using it
import {getPrivateVar} from './myModule';
console.log(getPrivateVar());
In the above, privateVar is by definition private to the module (file). There's no need to keep it private by wrapping it in an IIFE. Instead of handling the exports ourselves as properties of a single returned object, we use the ES6 export mechanism to export it explicitly.
(1)
When all Javascript files are loaded, all the scripts in all files are just like they are in one file. Script in one file can access (read, update, delete) global variables in other files. There are a lot of questions on this, you can easily search for those.
Of course, "one part of the program has nothing to do with another part", but in case you are in team with many members, each works on a part of the system (or in some cases, a file). Then, there is a chance that one person accidentally changes variables created by another person. Those kinds of error are quite easy to detect. But if you can modularize you script, you can avoid those kinds of error altogether.
(2)
You can go slow. While writing code to complete requirements, try to recognize the parts of code that can be separated to a modules (or even nested modules). Them put them into other files.
You should be creative and careful while doing so. The code might grow very fast and things get out of control very quickly.
I don't understand WHY and in what scenario this would be used..
My current web setup consists of lots of components, which are just functions or factory functions, each in their own file, and each function "rides" the app namespace, like : app.component.breadcrumbs = function(){... and so on.
Then GULP just combines all the files, and I end up with a single file, so a page controller (each "page" has a controller which loads the components the page needs) can just load it's components, like: app.component.breadcrumbs(data).
All the components can be easily accessed on demand, and the single javascript file is well cached and everything. This way of work seems extremely good, never saw any problem with this way of work. of course, this can (and is) be scaled nicely.
So how are ES6 imports for functions any better than what I described?
what's the deal with importing functions instead of just attaching them to the App's namespace? it makes much more sense for them to be "attached".
Files structure
/dist/app.js // web app namespace and so on
/dist/components/breadcrumbs.js // some component
/dist/components/header.js // some component
/dist/components/sidemenu.js // some component
/dist/pages/homepage.js // home page controller
// GULP concat all above to
/js/app.js // this file is what is downloaded
Then inside homepage.js it can look like this:
app.routes.homepage = function(){
"use strict";
var DOM = { page : $('#page') };
// append whatever components I want to this page
DOM.page.append(
app.component.header(),
app.component.sidemenu(),
app.component.breadcrumbs({a:1, b:2, c:3})
)
};
This is an extremely simplified code example but you get the point
Answers to this are probably a little subjective, but I'm going to do my best.
At the end of the day, both methods allow support creating a namespace for a piece of functionality so that it does not conflict with other things. Both work, but in my view, modules, ES6 or any other, provide a few extra benefits.
Explicit dependencies
Your example seems very bias toward a "load everything" approach, but you'll generally find that to be uncommon. If your components/header.js needs to use components/breadcrumbs.js, assumptions must be made. Has that file been bundled into the overall JS file? You have no way of knowing. You're two options are
Load everything
Maintain a file somewhere that explicitly lists what needs to be loaded.
The first option is easy and in the short term is probably fine. The second is complicated for maintainability because it would be maintained as an external list, it would be very easy to stop needing one of your component file but forget to remove it.
It also means that you are essentially defining your own syntax for dependencies when again, one has now been defined in the language/community.
What happens when you want to start splitting your application into pieces? Say you have an application that is a single large file that drives 5 pages on your site, because they started out simple and it wasn't big enough to matter. Now the application has grown and should be served with a separate JS file per-page. You have now lost the ability to use option #1, and some poor soul would need to build this new list of dependencies for each end file.
What if you start using a file in a new places? How do you know which JS target files actually need it? What if you have twenty target files?
What if you have a library of components that are used across your whole company, and one of they starts relying on something new? How would that information be propagated to any number of the developers using these?
Modules allow you to know with 100% certainty what is used where, with automated tooling. You only need to package the files you actually use.
Ordering
Related to dependency listing is dependency ordering. If your library needs to create a special subclass of your header.js component, you are no longer only accessing app.component.header() from app.routes.homepage(), which would presumable be running at DOMContentLoaded. Instead you need to access it during the initial application execution. Simple concatenation offers no guarantees that it will have run yet. If you are concatenating alphabetically and your new things is app.component.blueHeader() then it would fail.
This applies to anything that you might want to do immediately at execution time. If you have a module that immediately looks at the page when it runs, or sends an AJAX request or anything, what if it depends on some library to do that?
This is another argument agains #1 (Load everything) so you start having to maintain a list again. That list is again going to be a custom things you'll have come up with instead of a standardized system.
How do you train new employees to use all of this custom stuff you've built?
Modules execute files in order based on their dependencies, so you know for sure that the stuff you depend on will have executed and will be available.
Scoping
Your solution treats everything as a standard script file. That's fine, but it means that you need to be extremely careful to not accidentally create global variables by placing them in the top-level scope of a file. This can be solved by manually adding (function(){ ... })(); around file content, but again, it's one more things you need to know to do instead of having it provided for you by the language.
Conflicts
app.component.* is something you've chosen, but there is nothing special about it, and it is global. What if you wanted to pull in a new library from Github for instance, and it also used that same name? Do you refactor your whole application to avoid conflicts?
What if you need to load two versions of a library? That has obvious downsides if it's big, but there are plenty of cases where you'll still want to trade big for non-functional. If you rely on a global object, it is now up to that library to make sure it also exposes an API like jQuery's noConflict. What if it doesn't? Do you have to add it yourself?
Encouraging smaller modules
This one may be more debatable, but I've certainly observed it within my own codebase. With modules, and the lack of boilerplate necessary to write modular code with them, developers are encouraged to look closely on how things get grouped. It is very easy to end up making "utils" files that are giant bags of functions thousands of lines long because it is easier to add to an existing file that it is to make a new one.
Dependency webs
Having explicit imports and exports makes it very clear what depends on what, which is great, but the side-effect of that is that it is much easier to think critically about dependencies. If you have a giant file with 100 helper functions, that means that if any one of those helpers needs to depend on something from another file, it needs to be loaded, even if nothing is ever using that helper function at the moment. This can easily lead to a large web of unclear dependencies, and being aware of dependencies is a huge step toward thwarting that.
Standardization
There is a lot to be said for standardization. The JavaScript community has moved heavily in the direction of reusable modules. This means that if you hope into a new codebase, you don't need to start off by figuring out how things relate to eachother. Your first step, at least in the long run, won't be to wonder whether something is AMD, CommonJS, System.register or what. By having a syntax in the language, it's one less decision to have to make.
The long and short of it is, modules offer a standard way for code to interoperate, whether that be your own code, or third-party code.
Your current process is to concatenate everything always into a single large file, only ever execute things after the whole file has loaded and you have 100% control over all code that you are executing, then you've essentially defined your own module specification based on your own assumptions about your specific codebase. That is totally fine, and no-one is forcing you to change that.
No such assumptions can be made for the general case of JavaScript code however. It is precisely the objective of modules to provide a standard in such a way as to not break existing code, but to also provide the community with a way forward. What modules offer is another approach to that, which is one that is standardized, and one that offers clearer paths for interoperability between your own code and third-party code.
Regarding this question: What is the purpose of Node.js module.exports and how do you use it?
I'm a Javascript beginner. In the referenced question...
mymodule.js code
var myFunc = function() { ... };
exports.myFunc = myFunc;
main js file
var m = require('./mymodule.js');
m.myFunc();
Is mymodule essentially a class file defining objects?
Node.js allows code to be separated into different modules. This modules are just javascript files that can expose functions or objects using the exports object.
There are more details of this convention
Nice documentation of the Node.js modules
There are no Classes in JavaScript but you can use patterns to emulate that behaviour. There is a question about implementing OOP patterns in JavaScript: what pattern to use when creating javascript class?
As a beginner there are very good books for JavaScript:
JavaScript: The Good Parts
JavaScript Patterns
They are short and will give you a very good insight of the JavaScript Language.
Is mymodule essentially a class file defining objects?
and functions, although in Javascript functions are objects, so the distinction may be moot.
Importantly, each module has its own scope, so any var declared therein will not be visible outside of the module.
The rest of your question about users and lists doesn't make sense as written. Javascript OO programming is a complete topic in its own right, and the module system doesn't really change that. Modules are just a way of wrapping code libraries.
I've recently been playing with the awesome tool from google that does some code-optimization and partial execution, for instance it would take something like:
//Just an alias for an elementByID selector
function $(bar){
return document.getElementById(bar);
}
//Call the selector
alert($("foo").value);
And shorten it into alert(document.getElementById("foo").value);, which is fairly awesome from an optimization viewpoint.
I'm only explaining this because I would have thought this concept works for larger libraries such as jQuery, which basically attempts to abstract away a bunch of things JavaScript does, like select by IDs.
In a quick test, I loaded the whole jQuery production file up to the compiler and appended a single bit of text at the end of it: alert($("#foo").val());
And quite tragically, the compiler wasn't able to map through jQuery's design and result with the simple example I had above, but rather my output is about 85kb of text with alert($("#foo").K()); stuck on the end. Basically, I just have minified code, and didn't take advantage of the awesome feature demonstrated above.
So my question is, if I do end up using a library, how can I code in such a way that closure compiler is able to simplify my code to it's native JS (or something more effective than 85kb of unused code)? Alternatively, what design should someone take if they wanted to make a small library that plays nice?
AFAIK, jQuery is not (yet) written to be optimized by the Closure Compiler's Advanced Mode. It has an "externs" file which will enable its public properties and classes not to be renamed, but it does not enable most of the optimizations (e.g. dead code removal) as you've discovered. Which is quite a pity, because the jQuery object, if property written, does lends itself quite readily and nicely to the Closure Compiler's prototype virtualization feature.
Slightly off-topic
If you are not tied to jQuery, you may consider the Dojo Toolkit, which can be modified to be used with the Closure Compiler while enabling most optimizations (especially dead-code removal).
See this document for details.
jQuery takes special pains to minify itself and in the process makes itself opaque to the Closure Compiler.
Closure Library is an example of a library that is written to make good use of the Closure Compiler.
Generally, the compiler does best with prototype inheritance and simple structures:
/** #constructor */
function Class () {}
Class.prototype.f = function() {};
With an explicitly exported interface:
window['MyLib'] = { 'method', method };
Generally, advanced mode only makes sense for a library if it has a small external interface relative to the amount of internal code. However, I definitely would encourage writing your library so that it can be consumed by an advanced mode compiled project (this requires separating out the export used when it is used as a stand-alone library, if they library itself is minified using advanced mode).