totally agree about nesting and async is a smell.

Am Dienstag, 16. Oktober 2012 10:58:22 UTC+2 schrieb Eldar:
>
> But currently, it is important for me to use only standard (within the 
>> meaning of established/mainstream) componentes and libraries (like e.g. 
>> async) that every node programmer knows.
>
>
> No one encourages you to use the-box as is. It's essentials just about 
> 50-100 lines of code. Each app might want to have it's own optimized 
> version. But the pattern "hey I want this and that" is very common. 
> Delegating tasks of getting dependencies to well known infrastructure is 
> what makes code more simple and declarative. Here we see an idea of 
> separating control flow from business logic in action.    
>
> Can you please point out some more details why you don't find this code 
>> clean/easy maintainable? And give me some example code for improvements?
>
>
> Without concrete use case it's very hard to do. What you showed just has 
> some smells for me, but that's all pretty subjective. For example using of 
> async utils for sequential execution. They are adding their own noise both 
> in code and runtime. I personally can tolerate up to 5 levels of nesting 
> with 2 space tabs but can't remember when I had more than 3 levels. At the 
> same time async.waterfall adds 2 levels just by default. Another thing is 
>
> function doSomething () {
> var data = {}
> function a () {}
> function b () {} 
> a()
> b()
> }
>
> or
>
> function doSomething () {
> var data = {}
> a(data)
> b(data)
> }
>
> function a (data) {
> // body...
> }
>
> function b (data) {
> // body...
> }
>
> probably it's better to create object-method for such use case
>
> function DoSomething (data) {
> this.data = data
> }
>
> DoSomething.prototype.a = function  () {
> // body...
> }
>
> DoSomething.prototype.b = function  () {
> // body...
> } 
>   
>
> On Monday, October 15, 2012 11:18:37 AM UTC+4, Mil Werns wrote:
>>
>> @Tim:
>> Thanks, positive feedback is always welcome :)
>>
>> @Eldar:
>> the-box looks very interesting. I am curious to see what in this project 
>> happens next. But currently, it is important for me to use only standard 
>> (within the meaning of established/mainstream) componentes and libraries 
>> (like e.g. async) that every node programmer knows.
>>
>> Can you please point out some more details why you don't find this code 
>> clean/easy maintainable? And give me some example code for improvements?
>>
>>
>> On Sunday, October 14, 2012 11:58:31 AM UTC+2, Mil Werns wrote:
>>>
>>> Hi,
>>>
>>> I want to implement a REST API with node.js and restify. Because it is 
>>> my first node.js project, I spent some time to learn how to structure the 
>>> application to avoid the callback hell. Please have a look to the following 
>>> solution.
>>>
>>>
>>> *Assumptions*
>>> - This approach is for writing an end-user application, not a module or 
>>> a driver in the sense of a public library.
>>> - REST services are closely related to CRUD, so we have a lot of simple 
>>> sequential/interdependent operations (get_data + validate_data [+ 
>>> change_data] + save_data).
>>>
>>>
>>> *Goals*
>>> *===> Focus is writing maintainable, clean and easy to understand code! 
>>> <===*
>>> Conversely, this means...
>>> - Performance is secondary (scaling horizontally if necessary).
>>> - Avoid "low level" methods like process.nextTick(), instead use "high 
>>> level" methods/libs like middleware and control flow modules.
>>> - Use modules to implement a well known MVC structure.
>>>
>>>
>>> *Code*
>>> Please ignore the poor logging, the not very useful view tasks etc. in 
>>> the following example. It should only demonstrate the MVC / callback 
>>> structure.
>>>
>>>
>>> */* server.js */*
>>>
>>> var restify = require("restify");
>>> var router = require("./router");
>>> ...
>>> router.route(server);
>>> server.listen(...);
>>>
>>>
>>> */* router.js */*
>>>
>>> var userController = require("./controllers/user");
>>> ... // more controllers
>>>
>>> exports.route = function route(server) {
>>>   server.get("/users",
>>>     [
>>>       userController.checkRead,
>>>       userController.read,
>>>     ]
>>>   );
>>>   server.put("/users",
>>>     [
>>>       userController.checkUpdate,
>>>       userController.update,
>>>     ]
>>>   );
>>> ...
>>> };
>>>
>>>
>>> */* controllers/user.js */*
>>>
>>> var restify = require("restify");
>>> var async = require("async");
>>> var check = require('validator').check;
>>> var sanitize = require('validator').sanitize;
>>> var m = require("../models/user");
>>> var v = require("../views/user");
>>> ...
>>>
>>> var checkUpdate = function userCheckUpdate(req, res, next) {
>>>   // validate user input
>>>   try {
>>>     check(req.params.id, "id").isInt();
>>>     check(req.params.forename, "forename").len(1,50);
>>>     check(req.params.surname, "surname").len(1,50);
>>>     check(req.params.email, "email").isEmail();
>>>   } catch(err) {
>>>     if(err) {
>>>       return next(new restify.InvalidArgumentError("Invalid arguments"));
>>>     }
>>>   }
>>>   return next();
>>> };
>>>
>>>
>>> var update = function userUpdate(req, res, next) {
>>>   // create model
>>>   var model = {
>>>     forename: sanitize(req.params.forename).xss(),
>>>     surname: sanitize(req.params.surname).xss(),
>>>     email: sanitize(req.params.email).xss(),
>>>   };
>>>
>>>   //*** "sub-methods" part ***
>>>
>>>   // _example_ for data check
>>>   function checkOwner(curData, callback) {
>>>     if(curData.ownerId !== req.userId) {
>>>       return callback(new 
>>> restify.InvalidArgumentError("NotAuthorizedError"));
>>>     }
>>>     return callback(null, curData);
>>>   };
>>>
>>>   // _example_ for simple model manipulation
>>>   function addSimple(model, callback) {
>>>     model.updateDate = new Date().getTime();
>>>     return callback(null, model);
>>>   };
>>>
>>>   // _example_ for complex model manipulation
>>>   function addComplex(model, callback) {
>>>     // use async again to simulate synchronous/parallel/... flow
>>>     async.waterfall(
>>>       [
>>>         // do something
>>>       ]
>>>       function(err, model) {
>>>         if(err) {
>>>           return callback(new restify.InternalError());
>>>         }
>>>         return callback(null, model);
>>>       }
>>>     );
>>>   };
>>>
>>>
>>>   // *** main part ***
>>>   // use async to simulate synchronous flow
>>>   async.waterfall(
>>>     [
>>>       function(aNext) { m.get(req.params.id, aNext); },
>>>       function(curData, aNext) { checkOwner(curData, aNext); },
>>>       function(curData, aNext) { addSimple(model, aNext); },
>>>       function(model, aNext) { addComplex(model, aNext); },
>>>       function(model, aNext) { m.update(model, aNext); },
>>>       function(model, aNext) { v.update(model, aNext); },
>>>     ],
>>>     function(err, model) {
>>>       if(err) { return next(err); }
>>>       res.send(200, model);
>>>     }
>>>   );
>>>   return next();
>>> };
>>> ...
>>>
>>>
>>> */* models/user.js */*
>>> ...
>>> var get = function userGet(id, callback) {
>>>   var curData = ... // DB query for ID
>>>   if(err) {
>>>     console.log("DB error: " + err);
>>>     return callback(new restify.InternalError());
>>>   };
>>>   return callback(null, curData);
>>> };
>>>
>>> var update = ...
>>> ...
>>>
>>>
>>> */* views/user.js */*
>>> ...
>>> var update = function userUpdate(model, callback) {
>>>   // adjust model for output
>>>   delete model.updateDate;
>>>   ...
>>>   callback(null, model);
>>> };
>>>
>>>
>>> As you can see, this approach uses the middleware concept + async module 
>>> to separate the application in small (MVC) pieces that are hopefully easy 
>>> to understand.
>>> But as I said before: I'm a node.js newbie :)
>>>
>>> *What do you think about this structure?
>>> Are there any drawbacks?*
>>>
>>> Thanks a lot for your help
>>> Mil
>>>
>>>
>>>

-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Reply via email to