Best practices for extendable and modifiable node (npm) modules - javascript

I need advice from the more experienced javascript(typescript) / nodejs developers. For a few months a I’m trying to find best practice for making extendable and modifiable node (npm) modules.
For better understanding: In most of PHP frameworks (like as Symfony, Laravel, Nette) we have DI container which can be used for changing or adding own implementation for services coming from packages. For example. I have a cart package which implements service for calculating cart price and apply taxes. When i need to change taxes calculation I can change implementation over DI container like as
services:
myTaxCalculator:
class: MyTaxCalculator
Package\Taxes\CalculatorInterface: ‘#myTaxCalculator’
and now when package work with Package\Taxes\CalculatorInterface use my own calculator instead of default implementation.
And I looking for something like this in javascript(typescript)/nodejs. If I build any package and in package I need function for calculate taxes use this const taxCalculator = require(‘...’) but now I can’t change implementation of this function.
Of course I can make package configurable. Add some mechanism for set a custom function for specific cases but I think that I need this logic for all classes / function which is used in application to never have to call require(‘something’).
The point is build basic and standard package with default logic which can be in concrete application modify to solve customer problems without writing a new package with 90% same code.
I know that exists some IoC/DI implementation for javascript(typescript) / nodejs like as InversifyJS but I’m not sure when is a best way for javascript(typescript) / nodejs applications.
Do you have any experiences with this? How do you solve these problems?
Thanks for any response!

I wouldn't say I'm an expert or "best practices guru", but I think three scenarios are pretty common. I won't dig into Inversify because you're already aware of it.
Take an object with config at the entry point class/function. Default to your implementation.
interface TaxCalculator { /* tax related stuff */ }
interface CalculateCartPriceArgs {
taxCalculator: TaxCalculator,
// probably lots of other stuff
}
export function calculateCartPrice({
taxCalculator = defaultTaxCalculator
}: CalculateCartPriceArgs) {
// implementation
}
Plugins / middleware.
Expose internals to allow the user to build his own version of your thing.

Related

Use "require" in sails js app

When disabling globals the docs suggests using the following alternatives:
_ = require('lodash')
myService = sails.services.myservice
myModel = sails.models.mymodel
sails = req._sails
Would there be any issue requiring "sails", "services", and "models" much like any other module?
Having tried It, it does appear to work, however I feel I might be missing something.
Using require for services is always valid; the globalizing is merely for convenience.
On the other hand, doing require('api/models/User.js') will almost certainly not give you what you want, since those files are used by Sails to build model classes. So the only way to reliably use models in Sails without globals turned on is via sails.models.
Finally, while require('sails') will usually give you a reference to the running Sails app, it's not recommended that you use it that way. If you were running multiple Sails apps in the same process (which you might do in automated tests) then it would not reliably return the correct app. You're much better off using req._sails in controllers, and this.sails in models and services.

Can I use Laravel's "Service Container pattern" in JavaScript?

So, let's say that I am building a single-page app in JavaScript. For now I do not have a persistence layer in my app but I still need to write the code.
class App {
handleClick(event) {
User.saveToFile(event.target.value);
}
render() {
return 'Some template...';
}
}
So, I create my concrete user class. But for now just save it to the local storage.
class User {
constructor(localStorageHelper) {
this.localStorageHelper = localStorageHelper;
}
save(name) {
this.localStorageHelper.users.save({
name
});
}
}
When the database is ready, I need to switch to the database. If I was in an object-oriented language I can simply create an interface and use polymorphism or repository pattern to solve this problem.
I was wondering what if I create an app container to contain all of the concrete implementations. For example I can create a bindings.js file like the following:
import UserPersister from './Repos/Db/User'
import PostPersister from './Repos/File/Post'
const Bindings = {
'UserPersister': UserPersister,
'PostPersister': PostPersister
};
So now in my App.js file. I can do something like:
let User = Container.make('UserPersister');
class App {
handleClick(event) {
User.saveToFile(event.target.value);
}
render() {
return 'Some template...';
}
}
Now I can easily switch between different implementations by just changing them in bindings.js. If you've worked a little bit with Laravel this should seem familiar (except for the service providers of course).
This sounds OK to me but I am not sure if it is ACTUALLY OK to do this sort of thing in JavaScript. What advice would you give based on your experience with JavaScript?
If you want to reproduce laravel's pattern - that can be hard - but I can suggest you two technologies that can helps you with it. When you combained them you can easily implement quite similar code conception.
1 TypeScript
In fact you're using it in above code. It's a kind of JavaScript wrapper in which you can write a code similar to Java solutions. You have access here to polymorphism, inheritance and encapsulation like in typical PHP OOP. This can speed up your work a bit and it's pure and it's uses ECMAScript 2015.
2 AngularJS
The large JS Framework which is very strong and have big community. This one privides you for example injection service (like Laravel's IoC) which will automaticcly resolve all your dependencies. You can create easily repositories using $resources which is ajax wrapper for REST API requests. There are service providers that works greate on application load. And the best is that - yo can build one-page-application with Angular. It have many other advanteges. There is stable version 1 and unstable verison 2 which is developed in TypeScript.
With these two tools you can build awesome stuff for the frontend (client side). If you want more tools here it is:
PuppetJS - server side generating client side JS scripts (one implementation fort both sides!).
React - great library based on components

Code seperation in AngularJS

I'm quite new to AngularJS so please bear that in mind when reading this question...
I have some functions that I would like to make globally available to different modules within my website, plan is to have pages performing their own functions in a single page app style (so a user list / create / modify would be one page, and a product list / create / modify would be another). I would like to have some shared logic, say utility functions, and also user authorisation that can be shared between the different page modules.
This leads to my question.
Assuming I have all the account functions encapsulated within a service (app.factory('account, etc etc...') for example) and separated into it's own JS file, is it better to place it within it's own module and using dependency injection like so:
var accountMod = angular.module('accountModule', ['dependencies']);
accountMod.factory('account', ['dependencies', function (...) { }]);
Or just assume the name of the app variable will always be app and express it like so:
app.factory('account', ['dependencies', function (...) { }]);
Functionally both of these work, but I am trying to use best practices. The second option seems limited, I have never been keen on assuming variable are the same name throughout, for me the dependency injection method seems better but I have seen many examples of both styles out there!
Any help is much appreciated!
Really nice question. There are subtle things in this.
I think it would helpful to use following code, which is using module.
var accountMod = angular.module('accountModule', ['dependencies']);
accountMod.factory('account', ['dependencies', function (...) { }]);
However with help of angular provider and adding module level config we can mock object or service. Eventually this will increase the test ability of code.
If there are multiple services under accounting, then I would prefer to group them inside module.
These are my aspect of to look at it. Please add more if you found.
Thanks.
Just my 2 cents on your code examples.
The following approach is not recommended:
var accountMod = angular.module('accountModule', ['dependencies']);
accountMod.factory('account', ['dependencies', function (...) { }]);
A best practice is to only have 1 component per file, therefore no need to define a variable. Take a look at this: https://github.com/johnpapa/angular-styleguide#definitions-aka-setters
If you are just starting out with Angular, I recommend that you go through the rest of John Papa's Style Guide.
I love the structure that angular fullstack generator for yeoman has.
https://github.com/DaftMonk/generator-angular-fullstack
You can see how each module and component is separated and inside, de factory, services, directives, etc. and their associate test are split in one file per functionality.
This probably is overkilling for your propose, you can take only the angular idea.

Test-driven development of JavaScript web frontends

This might sound a little dumb, but I'm actually a bit confused how to approach JavaScript testing for web frontends. As far as I'm concerned, the typical 3-tier architecture looks like this:
Database tier
Application tier
Client tier
1 is of no concern in this question. 2 contains all the program logic ("business logic") 3 the frontend.
I do test-driven development for most projects, but only for the application logic, not the frontend. That is because testing the UI is difficult and unusual in TDD, and normally not done. Instead, all application logic is separated from UI, so that it is simple to test that logic.
The three tier architecture supports this: I can design my backend as a REST API which is called by my frontend. How does JS testing fit in? For the typical three-tier-architecture, JS (i.e. JS on the client) testing doesn't make much sense, does it?
Update:
I've changed the question's wording from "Testing JavaScript in web frontends" to "Test-driven development of JavaScript web frontends" to clarify my question.
Remember what the point of unit-testing is: to ensure a particular module of code reacts to some stimuli in an expected manner. In JS, a significant portion of your code, (unless you have some lifecycle framework like Sencha or YUI) will either be directly manipulating the DOM or making remote calls. To test these things, you simply apply traditional unit-testing techniques of dependency injection and mocking/stubbing. That means you must write each function, or class, that you want to unit-test to accept mocks of the dependent structures.
jQuery supports this by allowing you to pass an XML document into all traversal functions. Whereas you might normally write
$(function() { $('.bright').css('color','yellow'); }
you'll instead want to write
function processBright(scope) {
// jQuery will do the following line automatically, but for sake of clarity:
scope = scope || window.document;
$('.bright',scope).css('color','yellow');
}
$(processBright);
Notice we not only pull the logic out of the anonymous function and give it a name, we also make that function accept a scope parameter. When that value is null, the jQuery calls will still function as normal. However, we now have a vector for injecting a mock document that we can inspect after the function is invoked. The unit-test could look like
function shouldSetColorYellowIfClassBright() {
// arrange
var testDoc =
$('<html><body><span id="a" class="bright">test</span></body></html>');
// act
processBright(testDoc);
// assert
if (testDoc.find('#a').css('color') != 'bright')
throw TestFailed("Color property was not changed correctly.");
}
TestFailed could look like this:
function TestFailed(message) {
this.message = message;
this.name = "TestFailed";
}
The situation is similar with remote calls, though rather than actually injecting some facility, you could get away with a masking stub. Say you have this function:
function makeRemoteCall(data, callback) {
if (data.property == 'ok')
$.getJSON({url:'/someResource.json',callback:callback});
}
You would test it as such:
// test suite setup
var getJSON = $.getJSON;
var stubCalls = [];
$.getJSON = function(args) {
stubCalls[stubCalls.length] = args.url;
}
// unit test 1
function shouldMakeRemoteCallWithOkProperty() {
// arrange
var arg = { property: 'ok' };
// act
makeRemoteCall(arg);
// assert
if (stubCalls.length != 1 || stubCalls[0] != '/someResource.json')
throw TestFailed("someResource.json was not requested once and only once.");
}
// unit test 2
function shouldNotMakeRemoteCallWithoutOkProperty() {
// arrange
var arg = { property: 'foobar' };
// act
makeRemoteCall(arg);
// assert
if (stubCalls.length != 0)
throw TestFailed(stubCalls[0] + " was called unexpectedly.");
}
// test suite teardown
$.getJSON = getJSON;
(You can wrap that whole thing in the module pattern to not litter the global namespace.)
To apply all of this in a test-driven manner, you would simply write these tests first. This is a straightforward, no frills, and most importantly, effective way of unit-testing JS.
Frameworks like qUnit can be used to drive your unit-tests, but that is only a small part of the problem. Your code must be written in a test-friendly way. Also, frameworks like Selenium, HtmlUnit, jsTestDriver or Watir/N are for integration testing, not for unit-testing per se. Lastly, by no means must your code be object-oriented. The principles of unit-testing are easily confused with the practical application of unit-testing in object-oriented systems. They are separate but compatible ideas.
Testing Styles
I should note that two different testing styles are demonstrated here. The first assumes complete ignorance of the implementation of processBright. It could be using jQuery to add the color style, or it could be doing native DOM manipulation. I'm merely testing that the external behavior of the function is as expected. In the second, I assume knowledge of an internal dependency of the function (namely $.getJSON), and those tests cover the correct interaction with that dependency.
The approach you take depends on your testing philosophy and overall priorities and cost-benefit profile of your situation. The first test is relatively pure. The second test is simple but relatively fragile; if I change the implementation of makeRemoteCall, the test will break. Preferably, the assumption that makeRemoteCall uses $.getJSON is at least justified by the documentation of makeRemoteCall. There are a couple more disciplined approaches, but one cost-effective approach is to wrap dependencies in wrapper functions. The codebase would depend only on these wrappers, whose implementations can be easily replaced with test stubs at test-time.
There is a book titled Test-Driven JavaScript Development by Christian Johansen that might help you. I have only looked at some of the samples in the book (just downloaded a sample to Kindle the other day) but it looks like a great book that addresses this very issue. You might check it out.
(Note: I have no connection with Christian Johansen and no investment in sales of the book. Just looks like a good thing that addresses this problem.)
I have a similary architected application with JS client tier. In my case i use our company's own JS-framework to implement client tier.
This JS framework is created in OOP-style thus i can implement unit-testing for core classes and components. Also, to cover all user interactions (which can't be covered using unit-testing) i am using Selenium WebDriver to do an integration testing of framework visual components and test them under different browsers.
So, TDD can be applied to JavaScript development if code under test is written in OOP-manner. Also integration test is also possible (and can be used to do some kind of TDD).
Have a look at QUnit, as well, for unit tests of JavaScript methods and functions.
You can test your application from a user perspective with tools such as Rational Functional Tester, the HP tools or other equivalent software.
These tools test the application as if a user was sitting in front of it, but in an automated fashion. This means that you can test all three tiers at the same time, and especially the Javascript which may be difficult to test otherwise. Functional testing like this may help to find UI bugs and quirks with how the UI is using the data pushed out by your middle tier.
Unfortunately these tools are very expensive, so there may be other equivalents (and I'd be interested to know of such tools).
In our company we use jsTestDriver. It's a feature rich environment for testing frontend.
Take a look at it.

tips for working on a large javascript project

I have some experience with JavaScript - but mainly with some small stuff, I never did anything really big in Javascript previously.
Right now, however, I'm doing quite a large javascript-related project, a jquery-powered frontend that communicates with the server-side backend by sending/receiving JSON via Ajax.
I'm wondering if you could provide some useful information on how to deal with large javascript projects - are there any helpful tools/libaries/good practices?
Thanks in advance.
My one big tip would modularize
In JavaScript, it is very easy for variables to clobber other variables. In order to avoid this, modularization is a must. There are several ways to take advantage of JavaScripts scope rules to minimize the possibility of variable conflicts.
var myProject = {};
myProject.form = function(p_name, p_method, p_action)
{
var name = p_name,
method = p_method,
action = p_action;
var addInput = function(p_input)
{
// etc...
}
return {
addInput: addInput,
name: name
};
}
myProject.input = function(p_name, p_type, p_value)
{
var name, method, value;
var setValue = function(p_value)
{
value = p_value;
return true;
}
return {
setValue: setValue,
name: name
};
}
// etc...
If you're careful about using var, and keep track of your function scope, then you have only one global variable - myProject.
In order to get a new form Object, you'd simply do the following: var myForm = myProject.form('form1', 'post', 'post.php').
You may want to check out Backbone.js
Backbone supplies structure to
JavaScript-heavy applications by
providing models with key-value
binding and custom events, collections
with a rich API of enumerable
functions, views with declarative
event handling, and connects it all to
your existing application over a
RESTful JSON interface.
Grigory ,
Even i moved from a backend to UI few months back only follow this approach
read all the concepts of jquery
either from google or through some
book or through jquery
documentation.
follow some of the jquery best practices http://psdcollector.blogspot.com/2010/03/77-best-jquery-tips-i-have-ever-read.html
write utitlity functions for all repeated code like getcookie ,subsstrings etc etc
keep getting your code reviewed by experienced person who can guide you
post to stackoverflow if you get stuck anywhere.
as it is big project divide into mutiple files and use proper naming convintion.
please let me know if you need anything else
jQuery and YUI 3: A Tale of Two JavaScript Libraries is a nice comparison of them in the context of a complex application, and gives useful hints for jQuery programmers as well.
The best advice is to keep your code segmented in different files as "classes". I personally hate working in a file that's more than a few hundred lines long.
Then assemble and minify your code with one of the tools on the web, like Shrinksafe or Google Closure Compiler
Note that Dojo, YUI, and Ext are all designed to handle large Ajax applications. You'll struggle a bit with jQuery. But I'm guessing this app isn't all that big and you should be fine.
Have you consider checking out MooTools?
MooTools is a compact, modular, Object-Oriented JavaScript framework designed for the intermediate to advanced JavaScript developer. It allows you to write powerful, flexible, and cross-browser code with its elegant, well documented, and coherent API.

Categories

Resources