Node.js code reuse,

but in the right way

The ability to reuse code is important, but it is also important to do it in the right way.
In the last few days I've been working on a web Platform built in Node.js that exposes some REST APIs.
One of the most common choices in this case is Express.js which simplifies the development of this kind of platforms.
During the development I've faced a classic problem, parameters validation.

To do this operation there are a lot of ways.
The one I've chosen is to write routes in an independent way from where the parameters are from (url, query, body) or from how they are sent (form-url-encoded, json, ecc..).
The collection and validation of the parameters is demanded to middlewares.
This allows me to rouse those middlewares when they are common to many routes, and to exchange them easily (for example move a parameter from Query to Body).

Let's leave the technical aspects and go the main problem.

Many of this middlewares are more or less the same, the only differences are the name of the parameter and eventually limits (ex: minimum, maximum).

An obvious choice is to write a parametric middleware and use it from the others.

Here is the hard choice: how to do that?

I've tried 2 different ways:

1) Nested Functions

The middleware is a function that calls the generic one with additional parameters.

Generic Version:

  1. var checkMinMax = function (req, res, next, property, min, max) {
  2. var value = req.query[property];
  3. if (
  4. (min !== undefined && value < min)
  5. || (max !== undefined && value > max)) {
  6. req.errors.push({
  7. location: "query",
  8. property: property,
  9. message: "Property '" + property + "' out of bound"
  10. });
  11. }
  12. }

Specific Version:

  1. var checkCount = function (req, res, next) {
  2. checkMinMax(req, res, next, "count", undefined, 100);
  3. }
  4.  
  5. var checkId = function (req, res, next) {
  6. checkMinMax(req, res, next, "id", 0);
  7. }

Pros:

  • easy to read

Cons:

  • many parameters have to be passed to the nested function
  • the error message is generate during runtime

2) Functions "Builder"

The parameters of checkMinMax can be divided in two categories Fixed Parameters and Dynamic Parameters. The fixed ones are always the same, the dynamic ones are dependent on the particular execution. Why pass the fixed ones over and over again even if they do not change?

An alternative is to write a functions "Builder" that generates middlewares, based on the Fixed Parameters, that take as inputs the Dynamic Parameters.

Builder:

  1. var checkMinMax = function (property, min, max) {
  2. var error = {
  3. location: "query",
  4. property: property,
  5. message: "Property '" + property + "' out of bound"
  6. };
  7. if (min !== undefined) {
  8. if (max !== undefined) {
  9. return function (req) {
  10. var value = req.query[property];
  11. if (value < min || value > max) {
  12. req.errors.push(error);
  13. }
  14. }
  15. } else {
  16. return function (req) {
  17. if (req.query[property] < min) {
  18. req.errors.push(error);
  19. }
  20. }
  21. }
  22. } else {
  23. if (max !== undefined) {
  24. return function (req) {
  25. if (req.query[property] > max) {
  26. req.errors.push(error);
  27. }
  28. }
  29. } else {
  30. return function (req) { }
  31. }
  32. }
  33. }

Instances:

  1. var checkCount = checkMinMax("count", undefined, 100);
  2. var checkId = checkMinMax("id", 0);

Pros:

  • instance creation is extremely readable
  • parameters are hiden in the function (in the scope actually)
  • the error message is generate only once

Cons:

  • complex builder

Performance Test

In order to confirm what I've said, I've written two example scripts that test the real impact of the techniques from the performance point of view.

Test:

  • Average execution time on 100 iterations
  • Validation of 2 x 1.000.000 parameters

slow.jsslow.js

slow.jsfast.js

Results:

  1. Nested functions:120 ms
  2. Functions "Builder": 85 ms

The gap is considerable, more than 25% faster.

Obviously this test is built to point out the differences between the two approaches. In a real world application the are many other critical points and bottlenecks that reduce the gap.

I think however that this result is interesting, at least in my situation. If the application spends less time validating parameters -especially when there are invalid ones- it can serve more requests in the same time. Time is money, do not forget it.

 

If you reached this line I thank you and I hope you enjoyed the article.

If you have doubts, questions, suggestions or clarifications (or just if you want to say hello) leave a comment below, they are really appreciated.

blog comments powered by Disqus


We use cookies to improve your experience. By closing this banner, scrolling this page or clicking on a link in this page you accept such use.