Back to site
Since 2004, our University project has become the Internet's most widespread web hosting directory. Here we like to talk a lot about web servers, web development, networking and security services. It is, after all, our expertise. To make things better we've launched this science section with the free access to educational resources and important scientific material translated to different languages.

Node i Express saveti

Jun 2012

U Segment.io , koristimo node.js sa express framework for već nekih 8 meseci. Prestali smo da koristimo java play! framework i uvideli smo da je express mnogo elegantniji. Jednostavan je, ne treži mnogo, i veoma je rečitiji nego isti java kod.

Tokom toga vremena, otksrio sam nekoliko obrazaca i pogodnosti koje čine moj kod mnogo čistijim i lakšim za pračenje. Evo ih.

Struktura koda

Osnovno je pravilo, napravite modul.

Node čini lakšim povezivanje foldera u jedan veliki dobro definisani interfejs - i nema razloga da to i ne uradi. Ako se ikada zateknete kako pišete ‘one-off’ fajl koji sadrži neke delove koda koji je odvojen od svega drugoga u folderu, razmislite dobro zašto da ne napravite modul. Dobre su šanse da ćete želeti taj kod da u budućnosti pozovete sa nekog mesta.

Moduli

Mi posvećujemo naše node module gitu od kada zavisimo od njih u svakom slučaju . U slučaju da ne programirate nešto za NPM i ne za logiku, biće vam potrebna vaša sopstvena verzija i određene module. To mogu biti symlinked ili iz nekog drugog dela vašeg drveta koji vam dozvoljavaju da ponovo koristite module kada god to poželite.

Ovo je zgodno iz nekoliko razloga, jedan je da kada se jednom član tima čekira van repo za git potpuno je spreman za pokret. Ako programer shvati da mu je potrebna nova verzija biblioteke, može da je testira i posveti bez brige da će drugi ažurirati tu verziju.

Kao dodatak, ovo vam veoma pojednostavljuje posao, jer je nod taj koji traži module za vas. Umesto da uključite module koristeći komplikovanu stranu nalik ovoj ('../../../shared/utils'), mnogo je jednostavnije zahtevati ('utils'). Utils može biti symlinked i iz nekod drugog foldera u drvetu izvora tako da možete nastaviti da aktivno razvijate i menjate sve u cilju refleksije zavisnih modula.

Kontrolori

Lakše mi je da imama ceo modul za kontrolore, koji se svi grupiraju u iznose sličnih kontrolora. Na primer, naš modul kontrolor izgleda nekako ovako

/ controllers |--- auth.js |--- registration.js |--- settings.js | ...

Ovo je uobičajeno podešavanje blisko je i django i igranju, samo je potrebno postaviti dve odvojene verzije kontrolora, tako da ne dođe ni do kakvih iznenađenja.

Kada je u pitanju pisanje metoda kontrolora, treba vam što manje logike nego što vam se čini. Kontrolori bi prvenstveno trebalo da se koriste za validaciju i parsiranje inputa. Jednom kada imaju sve neophodne delove pozivaju vaše module i rendiraju template sa rezultatima.

Ako moduli iamju većinu aplikacionih kodova, možete da uradite stvari kao što je pisanje vaše baze podataka direktno sa noda. Možete da procenite sve kodove koje ste prethodno napisali jednostavno tako što ćete zahtevatimodule. Veliki dobitak!

Middleware i Routing

Još jedno pitanje oko strukture kontrolora “Gde da stavimo middleware?”. Volim django i play! metode koje imaju različite rute poklapanja u jednoj jedinoj ruti modula ili fajlu, tako da isto radite sa deklaracijom rute:

app.get('/', middlewareA, middlewareB, controllerMethod);

Alternativa je da imate middleware kome se rute poklapaju bazirano na regeksu. Ali ja ne volim ovo rešenje ni priblično mnogo jer smatram da je url struktura manje eksplicitna.

Glavni problem sa prvim pristupom je da je teško odlučiti koja vrsta middleware je već pokrenuta kada posmatrate sve kontrolor kodove. Kako ćemo znati da li imamo pristup User objektu unutar funkcije kontrolora? Da bi smo ovo rešili objaviću eksplicitno da je middleware unutar kontrolora eksporta. Svaka ruta onda direktno se odnosi na middleware sa kontrolorom. Hajde da koristimo jedan primer aktivnosti polja - evo ga kontrolor:

var middleware = require('middleware'), // yeah, middleware's a module too! feed = require('feed'); exports.middleware = function (app) { middleware.session(app), middleware.auth(app), middleware.user(app) }; exports.get = function (req, res, next) { var user = req.session.user; feed.load(user, function (err, result) { if (err) next(err); else res.render('feed.jade', { feed : result }); }); }

Volim ovaj pristup jer kada se posmatra kod kontrolora lako je uvideti šta se događa. Middleware se jasno gore prikazuje, tako da imate ideju, veoma dobru, kojim varijablama imate pristup. Rute su takođe pojednostavljene:

var controllers = require('controllers'); var feed = controllers.feed, auth = controllers.auth; app.get('/feed', feed.middleware(app), feed.get);

Rukovođenje greškama

Poslednji deo middleware i routiranja jeste rukovođenje greškama što je veoma teška tema. Ekspresna dokumentacija preporučuje da preuzmete poslednji deo middleware što u stvari jeste rukovošenje idejama, što i jeste dobra ideja. Ostavljam ove middleware greške jednostavnim: prevazišete greške i druge ridere na stranici ili vam se prenose JSON odgovori.

exports.error = function (err, req, res, next) { err.status = err.status || 500; err.message = err.message || 'Internal server error'; err.code = err.code || 'INTERNAL_ERROR'; if (req.xhr) { // If AJAX, send back json response. ajaxHandler(err, req, res, next); } else { // Else, give appropriate error page. pageHandler(err, req, res, next); } };

Dobra stvar u vezi ovoga jeste da middleware sam po sebi ne mari mnogo o greškama koje prevaziđe. Servira odgovor zavisno od koda is tatusa koji se vraća.

Umesto toga, koristim podešavanje grešaka koje definiše greške koje želim da prevaziđem. Definisanje podešavanja grešaka je veoma jednostavno jednom kada sve razumete . Štaviše, možete da status stavite u kategorije, a kodove grešaka u module, i onda da prebacite podešavanje poruka zavisno od situacije greške.

Veoma je lepo vlasništvo aplikacioni kod koji se nosi sa greškama i koji sam odličuje kako se greške prenose. Ovo je najlogičnije mesto za generisanje grešaka, pošto funkcija pozivanje funkcija ima više informacija o tome šta ne valja. Greška prolazi pored pozivanje i pored () middleware, gde middleware ima nekoliko metoda koje koristi svesno zavisno od informacija koje se u grešci nalaze.

Stil koda

Moj vodič za stil koda je veoma blizu zenu pitona - sa nekoliko glavnih određenih tačaka.

Eksplicitno je bolje od implicitnog. Ravno je bolje od krivudavog. Čitljivost se računa.

Zen Pitona

Kod nod koda, eksplicitno se definiše trasa koda, i pridržavamo se skoro ravne metode koja je važna. U suprotnom, veoma je lako završiti sa umršenim kodovima i pozivima svuda okolo.

Eksplicitno je bolje od implicitnog

Verovatno je moje glavno upustvo to - eksplicitno pre nego implicitno. Vidim da funkcioniše sa svim vrstama mesta i nikada se ne dogodi da se određeni etiketira zavisno od onoga đto radi bolje ili gore.

  • Ne dodajte metode via nizom

  • Koristite dokumentovani API kada god je to moguće. Dodata funkcionalnost mora biti dokumentovana

  • Kada se pojavi bilo koja izvedena funkcija, mora biti dokumentovana

  • Definišite izvod i izvedene varijable na jednom jedinstvenom mestu

Ako želite da napravite eksplicitne metode vema je lako, ako koristite određene alate. Ako želite da naglasite da je funkcija javna, postavite je u odeljku izvoz, kada su u pitanju privatne trebalo bi da koristite samo var izjave. Ako koristite sublime, koje nemaju nikakvo imenovanje vaš lepo funkcionalan dockblockr će automatski generisati komandu bloka u ime vaše metode.

/** * Create a new user * @param {String} email * @param {Object} options (optional) * @option {String} id * @option {String} username * @option {Date} created * @param {Function} callback (err, user) */ var create = exports.create = function (email, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } ... }

Ova funkcija izgleda jednostrano, ali činjenica da su opcije ekspliicitno izjavljene čini lakim korišćenje bez nepotrebnog kopanja za kodom. Samo pogledajte potpis, mogu reći da je ova funkcionalnost bolje eksponirana i lakđe se koristi bez modula.

Prethodno, stavljamo eksporte na dno fajla, ali sam promenio mišljenje. Ako imamo samo jedno mesto na koje se eksport odnosi u svojoj funkcionalnosti, onda nikada neće doći do nedoslednosti u funkcionalnosti unutrašnjeg reimenovanja.

Ravno je bolje od krivudavog

Smatram da će ovo biti propraćeno snažnim oduševljenjem. Da imam funkciju koja je propraćena sa dva poziva unutar, moralo bi to onda biti deo jednostavnog toka kontrole koji se mora podeliti na manje funkcije. Većinu vremena to je samo deo jednostavnog toka kontrole koji je u sekvenci akcije. Ako je to slučaj, koristim koalan asinc nod modulu . Lako je odrediti seriju asink poziva - i dobijate bonus korišćenjem funkcionalnih imena koja određuju ono što se događa:

async.parallel([{ function loadUser(callback) { db.users.get(user.id, callback); }, function getFriends(callback) { db.friends.get(user.id, callback); } ], function (err, results) { // Do something });

Najbolje od svega svaka sinhronizovana funkcija momentalno predaje greške u određeni poziv. Samo moramo da se rukovodimo greškama u pojedinačnim slučajevima, iako je neophodno da pojedinačne funkcije mogu da imaju greške kojima sami rukovode.

Pogledajte poziv nodu kao podstrek pisanju više modularnog koda. Ne upadajte u nered nesmirene logike!

Čitljivost se računa

Teško je definisati šta to tačno čini kod lakšim i jednostavnijim za definisanje, a to je ono što čini i čitljivost lakšom. Imenovanje je verovatno najnepredvidljiviji deo svega, ali postavljanje i struktura su takođe podjednako važni.

Imenovanje je teško na bilo kom jeziku, i za to je potrebno mnogo prakse. Kod mojih modula pokušavam da izbegnem slučaj kamile i složena imena u korist imena sa prorezom.Da bi ste videli šta pod tim mislim, dajem vam jednu od igračaka iz naše baze podataka:

exports.getUser = function (id, callback) {} // redundant name exports.get = function (id, callback) {} // clearer name

Naš stari poziv korisniku je bio db.user.getUser(id, funkcija), ali već znamo da pristupamo korisničkom modulu! Možemo se otarasiti posljednjeg korisničkog dela i umesto toga možemo db.user.get. Ovo izgleda kao mala promena - ali to je ono što čini kod mnogo lakšim za čitanje. Ako je to moguće, dodajte module i imena umesto složenih funkconalnih imena.

Ovo su druge stvari koje se mogu uraditi:

  • povežite objekte i var deklaracije

  • rano se povratite da bi ste izbegli velike ako...drugo...blokove

  • kombinujte var deklaracije zarad “velikih varijabli”

Za poneti

Veoma je lako videti da nod i express jesu fleksibilni i da se mogu skrasiti na velikom polju programskog stila. Moj pristup teži ukorenjenijem stavu kod MVC načina razmišljanja, ali nema razloga da express ne može biti dodat mnogim drugim obrascima.

Voleo bih da čujem vaše savete i iskustva: možete me zatrpati na @calvinfo , ili mi poslati o email na calvin na ovom domenu.

Želite da vidite na čemu još raadim? Proverite sve na segment.io u cilju analize i pregleda.





Published (Last edited): 29-04-2013 , source: http://calv.info/node-and-express-tips/