Praktik Terbaik Node.js - Tip Struktur Proyek


Halo, Habr! Saya sajikan kepada Anda terjemahan adaptasi dari bab pertama " Praktik Terbaik Node.js " oleh Yoni Goldberg. Pilihan rekomendasi pada Node.js diposting di github, memiliki hampir 30 ton bintang, tetapi sejauh ini belum disebutkan di Habré. Saya kira informasi ini akan berguna, setidaknya untuk pemula.

1. Tip struktur proyek


1.1 Struktur proyek Anda dengan komponen


Kesalahan terburuk dari aplikasi besar adalah arsitektur monolit dalam bentuk basis kode besar dengan sejumlah besar dependensi (kode spaghetti), struktur ini sangat memperlambat perkembangan, terutama pengenalan fungsi-fungsi baru. Tip - pisahkan kode Anda menjadi komponen-komponen terpisah, untuk setiap komponen, pilih folder Anda sendiri untuk modul komponen. Penting agar setiap modul tetap kecil dan sederhana. Di bagian "Perincian", Anda dapat melihat contoh struktur proyek yang benar.

Jika tidak: akan sulit bagi pengembang untuk mengembangkan produk - menambahkan fungsionalitas baru dan membuat perubahan pada kode akan lambat dan memiliki peluang besar untuk melanggar komponen dependen lainnya. Diyakini bahwa jika unit bisnis tidak dibagi, maka masalah dapat muncul dengan meningkatkan aplikasi.

Detail
Penjelasan satu paragraf

Untuk aplikasi ukuran sedang dan di atas, monolith benar-benar buruk - satu program besar dengan banyak dependensi sulit untuk dipahami, dan seringkali mengarah ke kode spageti. Bahkan programmer berpengalaman yang tahu bagaimana “mempersiapkan modul” dengan baik menghabiskan banyak usaha pada desain arsitektur dan mencoba untuk secara hati-hati mengevaluasi konsekuensi dari setiap perubahan dalam hubungan antara objek. Pilihan terbaik adalah arsitektur yang didasarkan pada sekumpulan program komponen kecil: bagi program menjadi komponen terpisah yang tidak berbagi file dengan siapa pun, setiap komponen harus terdiri dari sejumlah kecil modul (misalnya, modul: API, layanan, akses basis data, pengujian dll.), sehingga struktur dan komposisi komponennya jelas. Beberapa orang mungkin menyebut arsitektur ini sebagai "layanan mikro", tetapi penting untuk memahami bahwa layanan mikro bukanlah spesifikasi yang harus Anda ikuti, melainkan serangkaian prinsip. Atas permintaan Anda, Anda dapat mengadopsi kedua prinsip ini dan semua prinsip arsitektur layanan mikro. Kedua metode ini baik jika Anda menjaga kompleksitas kode tetap rendah.

Paling tidak yang harus Anda lakukan adalah menentukan batas-batas antara komponen: menetapkan folder di root proyek Anda untuk masing-masing komponen dan membuatnya sendiri. Akses ke fungsionalitas komponen harus dilaksanakan hanya melalui antarmuka publik atau API. Ini adalah dasar untuk menjaga kesederhanaan komponen Anda, menghindari "neraka ketergantungan" dan membiarkan aplikasi Anda tumbuh menjadi layanan-mikro sepenuhnya.

Kutipan dari blog: "Penskalaan membutuhkan penskalaan seluruh aplikasi"
Dari Blog MartinFowler.com
Aplikasi monolitik bisa berhasil, tetapi orang semakin frustrasi dengan mereka, terutama ketika berpikir tentang penggelaran ke cloud. Perubahan apa pun, meskipun kecil, dalam aplikasi memerlukan perakitan dan pemindahan seluruh monolit. Seringkali sulit untuk mempertahankan struktur modular yang baik di mana perubahan dalam satu modul tidak mempengaruhi modul lainnya. Penskalaan membutuhkan penskalaan seluruh aplikasi, dan bukan hanya bagian-bagiannya saja, tentu saja, pendekatan ini membutuhkan lebih banyak usaha.

Kutipan dari blog: "Apa yang dibicarakan arsitektur aplikasi Anda?"
Dari blog paman-bob
... jika Anda pernah ke perpustakaan, maka Anda mewakili arsitekturnya: pintu masuk utama, meja resepsionis, ruang baca, ruang konferensi, dan banyak aula dengan rak buku. Arsitekturnya sendiri akan mengatakan: bangunan ini adalah perpustakaan.

Jadi apa yang dibicarakan oleh arsitektur aplikasi Anda? Ketika Anda melihat struktur direktori tingkat atas dan file modul di dalamnya, mereka berkata: Saya adalah toko online, saya seorang akuntan, saya sistem manajemen produksi? Atau apakah mereka berteriak: Aku Rails, aku Spring / Hibernate, aku ASP?
(Catatan Penerjemah, Rails, Spring / Hibernate, ASP adalah frameworks dan teknologi web).

Struktur proyek yang tepat dengan komponen otonom



Struktur proyek salah dengan pengelompokan file berdasarkan tujuan



1.2 Pisahkan lapisan komponen Anda dan jangan campur dengan struktur data Express


Setiap komponen Anda harus memiliki "lapisan", misalnya, untuk bekerja dengan web, logika bisnis, akses ke database, lapisan ini harus memiliki format data sendiri tidak dicampur dengan format data perpustakaan pihak ketiga. Ini tidak hanya secara jelas memisahkan masalah, tetapi juga sangat memudahkan verifikasi dan pengujian sistem. Seringkali, pengembang API mencampur lapisan dengan mengirimkan objek lapisan web Express (seperti req, res) ke logika bisnis dan lapisan data - ini membuat aplikasi Anda bergantung dan sangat terhubung dengan Express.

Kalau tidak: untuk aplikasi di mana objek layer dicampur, lebih sulit untuk menyediakan pengujian kode, pengorganisasian tugas CRON dan panggilan non-Express lainnya.

Detail
Bagilah kode komponen menjadi beberapa lapisan: web, layanan, dan DAL



Sisi lain adalah mencampur lapisan dalam satu animasi gif



1.3 Bungkus utilitas dasar Anda dalam paket npm


Dalam aplikasi besar yang terdiri dari berbagai layanan dengan repositori mereka sendiri, utilitas universal seperti logger, enkripsi, dll., Harus dibungkus dengan kode Anda sendiri dan disajikan sebagai paket npm pribadi. Ini memungkinkan Anda untuk membaginya di antara beberapa basis kode dan proyek.

Jika tidak: Anda harus menciptakan sepeda sendiri untuk membagikan kode ini di antara basis kode yang terpisah.

Detail
Penjelasan satu paragraf

Segera setelah proyek mulai tumbuh dan Anda memiliki komponen yang berbeda di server yang berbeda menggunakan utilitas yang sama, Anda harus mulai mengelola dependensi. Bagaimana saya bisa mengizinkan beberapa komponen untuk menggunakannya tanpa menduplikasi kode utilitas Anda di antara repositori? Ada alat khusus untuk ini, dan ini disebut npm .... Mulailah dengan membungkus paket utilitas pihak ketiga dengan kode Anda sendiri sehingga Anda dapat dengan mudah menggantinya di masa mendatang, dan terbitkan kode ini sebagai paket npm pribadi. Sekarang seluruh basis kode Anda dapat mengimpor kode utilitas dan menggunakan semua fitur manajemen ketergantungan npm. Ingatlah bahwa ada cara berikut untuk mempublikasikan paket npm untuk penggunaan pribadi tanpa membukanya untuk akses publik: modul pribadi, registri pribadi, atau paket npm lokal .

Membagikan utilitas bersama Anda di lingkungan yang berbeda


1.4 Pisahkan Express menjadi "aplikasi" dan "server"


Hindari kebiasaan yang tidak menyenangkan untuk mendefinisikan seluruh aplikasi Express dalam satu file besar, pisahkan kode 'Express' Anda menjadi setidaknya dua file: deklarasi API (app.js) dan kode server www. Untuk struktur yang lebih baik lagi, letakkan deklarasi API dalam modul komponen.

Jika tidak: API Anda hanya akan tersedia untuk pengujian melalui panggilan HTTP (yang lebih lambat dan jauh lebih sulit untuk menghasilkan laporan cakupan). Namun, saya rasa, tidak terlalu menyenangkan bekerja dengan ratusan baris kode dalam satu file.

Detail
Penjelasan satu paragraf

Kami merekomendasikan penggunaan generator aplikasi Express dan pendekatannya untuk membangun database aplikasi: deklarasi API dipisahkan dari konfigurasi server (data port, protokol, dll.). Ini memungkinkan Anda untuk menguji API tanpa membuat panggilan jaringan, yang mempercepat pengujian dan membuatnya lebih mudah untuk mendapatkan metrik cakupan kode. Ini juga memungkinkan Anda untuk secara fleksibel menggunakan API yang sama untuk pengaturan jaringan server yang berbeda. Sebagai bonus, Anda juga mendapatkan pemisahan tanggung jawab dan kode bersih yang lebih baik.

Kode sampel: Deklarasi API, harus di app.js
var app = express(); app.use(bodyParser.json()); app.use("/api/events", events.API); app.use("/api/forms", forms); 

Contoh kode: parameter jaringan server, harus dalam / bin / www
 var app = require('../app'); var http = require('http'); /** *          Express. */ var port = normalizePort(process.env.PORT || '3000'); app.set('port', port); /** *  HTTP-. */ var server = http.createServer(app); 


Contoh: menguji API kami menggunakan supertest (paket pengujian populer)
 const app = express(); app.get('/user', function(req, res) { res.status(200).json({ name: 'tobi' }); }); request(app) .get('/user') .expect('Content-Type', /json/) .expect('Content-Length', '15') .expect(200) .end(function(err, res) { if (err) throw err; }); 


1.5 Gunakan konfigurasi hierarki aman berdasarkan variabel lingkungan


Pengaturan konfigurasi yang ideal harus menyediakan:

(1) membaca kunci dari kedua file konfigurasi dan variabel lingkungan,
(2) menyimpan rahasia di luar kode repositori,
(3) struktur data hierarkis (bukan datar) dari file konfigurasi untuk memudahkan pekerjaan dengan pengaturan.

Ada beberapa paket yang dapat membantu mengimplementasikan poin-poin ini, seperti: rc, nconf, dan config.

Jika tidak: kegagalan untuk mematuhi persyaratan konfigurasi ini akan menyebabkan terganggunya pekerjaan baik pengembang individu dan seluruh tim.

Detail
Penjelasan satu paragraf

Saat Anda berhadapan dengan pengaturan konfigurasi, banyak hal yang dapat mengganggu dan memperlambat:

1. Mengatur semua parameter menggunakan variabel lingkungan menjadi sangat membosankan jika Anda perlu memasukkan 100+ kunci (alih-alih hanya memperbaikinya dalam file konfigurasi), namun, jika konfigurasi hanya akan ditentukan dalam file pengaturan, ini mungkin merepotkan bagi DevOps. Solusi konfigurasi yang andal harus menggabungkan kedua metode: file konfigurasi dan parameter yang ditimpa dari variabel lingkungan.

2. Jika file konfigurasi JSON "flat" (yaitu, semua kunci ditulis sebagai satu daftar), maka dengan peningkatan jumlah pengaturan akan sulit untuk bekerja dengannya. Masalah ini dapat diselesaikan dengan membentuk struktur bersarang yang berisi kelompok kunci sesuai dengan bagian pengaturan, mis. mengatur struktur data JSON hirarkis (lihat contoh di bawah). Ada pustaka yang memungkinkan Anda untuk menyimpan konfigurasi ini di beberapa file dan menggabungkan data dari mereka pada saat run time.

3. Tidak disarankan untuk menyimpan informasi rahasia (seperti kata sandi basis data) dalam file konfigurasi, tetapi tidak ada solusi mudah yang pasti untuk tempat dan cara menyimpan informasi tersebut. Beberapa perpustakaan konfigurasi memungkinkan Anda untuk mengenkripsi file konfigurasi, yang lain mengenkripsi entri ini selama git melakukan, atau Anda tidak perlu menyimpan parameter rahasia dalam file sama sekali dan menetapkan nilainya selama penyebaran melalui variabel lingkungan.

4. Beberapa skenario konfigurasi lanjutan mengharuskan Anda memasukkan kunci melalui baris perintah (vargs) atau menyinkronkan data konfigurasi melalui cache terpusat seperti Redis sehingga beberapa server menggunakan data yang sama.

Ada pustaka npm yang akan membantu Anda dengan implementasi sebagian besar dari rekomendasi ini, kami sarankan Anda untuk melihat pustaka berikut: rc , nconf dan config .

Contoh kode: struktur hierarkis membantu menemukan catatan dan bekerja dengan file konfigurasi yang banyak

 { // Customer module configs "Customer": { "dbConfig": { "host": "localhost", "port": 5984, "dbName": "customers" }, "credit": { "initialLimit": 100, // Set low for development "initialDays": 1 } } } 

(Catatan Penerjemah, komentar tidak dapat digunakan dalam file JSON klasik. Contoh di atas diambil dari dokumentasi perpustakaan konfigurasi, yang menambahkan fungsionalitas untuk pra-membersihkan file JSON dari komentar. Oleh karena itu, contoh ini cukup berfungsi, namun, serat seperti ESLint dengan pengaturan default dapat "Bersumpah" pada format yang sama).

Kata penutup dari penerjemah:

  1. Deskripsi proyek mengatakan bahwa terjemahan ke dalam bahasa Rusia telah diluncurkan, tetapi saya tidak menemukan terjemahan ini di sana, jadi saya mengambil artikel itu.
  2. Jika terjemahannya tampak sangat singkat bagi Anda, maka cobalah untuk memperluas informasi terperinci di setiap bagian.
  3. Maaf ilustrasi tidak diterjemahkan.

Source: https://habr.com/ru/post/id454476/


All Articles