Keluar dari zona nyaman Anda: dari nodejs ke dlang

Pada 2017, saya mulai menulis proyek pada nodejs - sebuah implementasi protokol Weinzierl ObjectServer untuk mengakses nilai-nilai KNX. Selama proses penulisan, kami mempelajari: bekerja dengan protokol biner, menyajikan data, bekerja dengan soket (khususnya soket unix), bekerja dengan basis data redis dan saluran pub / sub.


Proyek ini telah mencapai versi stabil. Pada saat ini, saya perlahan-lahan memilih bahasa lain, khususnya Dart dan Flutter sebagai aplikasinya. Di rak dibersihkan tanpa tindakan yang dibeli pada saat buku pedoman siswa G. Schildt.


Suatu pemikiran yang gigih untuk menulis ulang proyek di C menetap di kepala saya. Saya mempertimbangkan opsi Go, Rust, menolak konstruksi sintaksis lainnya. Tidak ada cara untuk memulai, idenya ditunda untuk sementara waktu.


Pada bulan Mei tahun ini, saya memutuskan untuk melihat bahasa D, untuk beberapa alasan yakin bahwa huruf D berarti dinamis. Saya bertanya-tanya dalam waktu lama di mana dan mengapa pikiran ini ada di kepala saya, jadi saya tidak menemukan jawaban. TAPI ini tidak penting lagi, karena saya terbawa oleh penulisan ulang sepanjang musim panas.


Inti dari proyek


Modul KNX BAOS 830/832/838 terhubung melalui UART ke komputer, protokol ObjectServer dibungkus dalam FT1.2. Aplikasi membuat koneksi dengan /dev/ttyXXX , memproses data yang masuk, mengirimkan byte permintaan pengguna yang berasal dari saluran PUB / SUB ke antrian yang sama, atau ke antrian pekerjaan berdasarkan daftar Redis (untuk nodejs, antrian diimplementasikan dalam paket antrian lebah) )


 queue.on("job", data => { //   : //  ,     //  ,      }); baos.on("data", data => { // ,  :    //  ,      //   -     pub/sub }); 

Dinamisme


JSON dalam js adalah hal asli, saya tidak tahu bagaimana pemrosesan terjadi dalam bahasa yang diketik secara statis. Ternyata, sedikit perbedaan. Misalnya, ambil metode get value . Sebagai argumen, dibutuhkan nomor - nomor titik data, atau array nomor.


Di js, pemeriksaan dilakukan:


 if (Array.isArray(payload)) { //     return values; } if (typeof id === "number") { //     return value; } throw new Error(" id"); 

Pada dasarnya sama pada D:


 if (payload.type() == JSONType.integer) { //    } else if (payload.type() === JSONType.array) { //    } else { throw Errors.wrong_payload_type; } 

Untuk beberapa alasan, pada saat Rust-sebuah pertimbangan, adalah kurangnya pemahaman bekerja dengan JSON yang memperlambat saya. Poin lain yang terkait dengan dinamisme: array. Di js, Anda terbiasa dengan fakta bahwa cukup memanggil metode push untuk menambahkan elemen. Di C, dinamika diterapkan oleh alokasi memori manual, tetapi saya tidak benar-benar ingin naik ke sana. Dlang, ternyata, mendukung array dinamis.


 ubyte[] res; //   -     res.length = 1000; //        res.length = count; //        1 

Data UART yang masuk dalam js dikonversi ke Object . Untuk tujuan ini, struktur, enumerasi dengan nilai, dan gabungan sangat bagus dalam D.


 enum OS_Services { unknown, GetServerItemReq = 0x01, GetServerItemRes = 0x81, SetServerItemReq = 0x02, SetServerItemRes = 0x82, // ... } // ... struct OS_Message { OS_Services service; OS_MessageDirection direction; bool success; union { // union of possible service returned structs // DatapointDescriptions/DatapointValues/ServerItems/ParameterBytes OS_DatapointDescription[] datapoint_descriptions; OS_DatapointValue[] datapoint_values; OS_ServerItem[] server_items; Exception error; }; } 

Dengan pesan masuk:


 ubyte mainService = data.read!ubyte(); ubyte subService = data.read!ubyte(); try { if (mainService == OS_MainService) { switch(subService) { case OS_Services.GetServerItemRes: result.direction = OS_MessageDirection.response; result.service= OS_Services.GetServerItemRes; result.success = true; result.server_items = _processServerItemRes(data); break; case OS_Services.SetServerItemRes: result.direction = OS_MessageDirection.response; // ... 

Dalam js, saya menyimpan nilai byte dalam array, dengan data yang masuk, saya mencari dan mengembalikan sebuah string dengan nama layanan. Struktur, enumerasi, dan asosiasi terlihat lebih ketat.


Bekerja dengan array data byte


Node.js Saya suka abstraksi Buffer . Sebagai contoh: akan lebih mudah untuk melakukan konversi dua byte ke integer yang tidak ditandatangani menggunakan metode readUInt16BE(offset) , untuk menulis - writeUInt16BE(value, offset) , buffer yang digunakan secara aktif untuk bekerja dengan protokol biner. Untuk dlang, saya awalnya memulai paket repositori ke sesuatu yang serupa. Jawabannya ditemukan di perpustakaan standar std.bitmanip . Untuk bilangan bulat bertanda 2 byte: panjang ushort start = data.read!ushort() , untuk menulis: result.write!ushort(start, 2); dimana argumen ke-2 adalah ofset.


EE, janji, async / menunggu.


Bagian terburuk adalah pemrograman tanpa EventEmitter . Dalam node.js, fungsi pendengar hanya terdaftar, dan pada suatu peristiwa, mereka dipanggil. Jadi, seseorang tidak harus berpikir keras. Paket tinylis dan serialport dlang (dependensi aplikasi saya) memiliki metode non-pemblokiran untuk memproses pesan. Solusinya sederhana: untuk saat ini, memang benar untuk menerima port serial dan pesan pub / sub channel secara bergantian. Jika ada permintaan pengguna yang masuk ke saluran pub / sub, program harus mengirim pesan ke port serial, dapatkan hasilnya dan mengirim pengguna kembali ke pub / sub. Diputuskan untuk membuat metode untuk memblokir permintaan serial.


 while(!(_responseReceived || _resetInd || _interrupted)) { try { processIncomingData(); processIncomingInterrupts(); if (_resetInd || _interrupted) { _response.success = false; _response.service = OS_Services.unknown; _response.error = Errors.interrupted; _responseReceived = true; _ackReceived = true; } // ... // ... return _response; 

Dalam loop sementara, data disurvei oleh metode metode non-blockingIncomingData processIncomingData() . Kemungkinan modul KNX dapat di-boot ulang (terputus dan dihubungkan kembali ke bus atau perangkat lunak KNX) juga disediakan. Juga, penangan processIncomingInterrupts() memeriksa pub layanan / sub saluran untuk permintaan reset . Tidak ada fungsi janji atau asinkron, tidak seperti implementasi js sebelumnya. Saya harus berpikir tentang struktur program (yaitu, urutan fungsi panggilan), tetapi, karena tidak adanya abstraksi yang tidak perlu, menjadi lebih mudah untuk diprogram. Bahkan, ketika await someAsyncMethod dipanggil dalam kode js, fungsi asynchronous disebut sebagai blocking, melewati event loop. Kemungkinan bahasa itu baik, tetapi Anda bisa melakukannya tanpa itu.


Perbedaan


Antrian pekerjaan. Implementasi node.js menggunakan paket bee-queue untuk tujuan ini. Dalam implementasi pada D, permintaan dikirim hanya melalui pub / sub.
Kalau tidak, semuanya hampir identik.


Versi yang dikompilasi mengkonsumsi 10 kali lebih sedikit RAM, yang mungkin penting untuk komputer papan tunggal.


Kompilasi


Kompilasi dilakukan menggunakan ldc pada platform aarch64.


Untuk menginstal ldc:


 curl -fsS https://dlang.org/install.sh | bash -s ldc 

Motherboard telah dirakit, terdiri dari tiga komponen utama: NanoPi Neo Core2 sebagai komputer, modul KNX BAOS 830 untuk komunikasi dengan bus KNX, dan Silvertel Ag9205 untuk daya PoE, di mana pemrograman dilakukan.


Penampilan papan


Kesimpulan


Saya tidak akan menilai bahasa mana yang lebih baik atau lebih buruk. Untuk masing-masing: js sangat bagus untuk belajar, tingkat abstraksi (janji, penghasil emisi) membuatnya mudah dan cepat untuk membangun struktur aplikasi. Saya mendekati implementasi dlang dengan rencana yang jelas dan hafal selama satu setengah tahun, apa yang harus dilakukan. Ketika Anda tahu data apa yang perlu diproses dan bagaimana, pengetikan statis tidak menakutkan. Metode non-blocking memungkinkan Anda untuk mengatur siklus kerja. Ini adalah pekerjaan pertama saya di D, sebuah karya yang menarik dan informatif.


Adapun meninggalkan zona nyaman (seperti yang ditunjukkan dalam judul): dalam kasus saya, rasa takut memiliki mata besar, yang untuk waktu yang lama mencegah saya mencoba sesuatu selain nodejs.


Kode sumber terbuka dan dapat ditemukan di github.com/dobaos/dobaos

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


All Articles