Node Master – Telegram
Node Master
1.03K subscribers
24 photos
2 files
156 links
Group Chat: @nodemastergp
Admin: @napoleon_n1
Download Telegram
یکبار داشتم تست مینوشتم و داشتم type ها رو assert میکردم که به این موضوع خوردم که چند ساعتی داشتم دنبالش میگشتم که داستان چیه و در نهایت متوجه شدم که اگر string رو با String class مستقیم بسازید typeof مربوط بهش میشه object و نه string.
const text1 = new String("NodeMaster");
const text2 = "NodeMaster";

console.log(typeof text1); // object
console.log(typeof text2); // string

دقیق یادم نمیاد که کد چی بود ولی مشکلش این typeof بود که object میشد و من انتظار داشتم string بشه.

#Tip
👍7
Node Master
دوستان. برای نصب #NodeJS روی سیستم خودتون سعی کنید از nvm استفاده کنید. فرایند آپدیت کردن و نگهداری همزمان ورژن های مختلف #NodeJS رو براتون خیلی راحت میکنه. https://github.com/nvm-sh/nvm
اگر میخواید #NodeJS رو روی سیستم خودتون نصب کنید یک سری ابزار ها هست که اینکار رو برای شما راحت تر میکنه و قابلیت های بیشتری به شما میده.
- آپدیت کردن راحت تر
- داشتن چند ورژن همزمان و سویچ کردن
و ... . ۳ تا از این ابزار ها پایین هست من خودم از nvm استفاد میکنم ولی بعضی دوستان volta رو معرفی کردن. ویژگی خوب volta این هست که روی ویندوز هم کار میکنه ولی nvm فقط لینوکس هست فک کنم.

https://volta.sh/
یکی دیگ هم هست به اسم fnm که با rust نوشتن میتونید چک کنید.
https://github.com/Schniz/fnm

درکل همشون یک کار میکنن هرکدوم رو چک کنید و دوست داشتید استفاده کنید.

مرسی از @dev_a_loper بابت معرفی volta
👍14
Node Master
گاهی اوقات در زمان توسعه برنامه نیاز است که از یک Object یک کپی ایجاد کنیم و Object اصلی رو به هیچ عنوان mutate نکنیم. برای کپی کردن object معمولا دو حالت دارد. - deep copy - shallow copy بزارید با مثال براتون تفاوت این دو مدل رو توضیح بدم. const user = {…
قبلا درمورد identity check صحبت خیلی کوتاهی کردیم که با استفاده از "===" میتونیم reference ها رو چک کنیم. فرض کنید ما دوتا object رو میخوایم مقایسه کنیم نه بر اساس reference ها بلکه براساس attr ها. اینجا "node:util" به کمک ما میاد.
import util from "node:util";

const obj1 = { name: "NodeMaster" };
const obj2 = { name: "NodeMaster" };

console.log(util.isDeepStrictEqual(obj1, obj2));
console.log(obj1 === obj2);

دو obj که داریم با این که دقیقا یک شکل هستن ولی داخل دو خونه حافظه جدا هستن یعنی reference های متفاوت دارن. حالا با isdeepStrictEqual میتونیم این دوتا رو با هم چک کنیم که اگر کد رو اجرا کنید کاملا متوجه میشید داستان چیه.
دقیقا یک نسخه از همین فانکشن رو داخل "node:assert" داریم که لاجیکی که داره همین هست ولی بجای bool type به ما AssertionError برمیگردونه.
assert.deepStrictEqual(obj1, obj2);
util.isDeepStrictEqual(obj1, obj2);

حالا سوال پیش میاد بنظرتون چرا باید دو مدل api برای یک لاجیک و خروجی ها متفاوت داشته باشیم؟

#Tip
#NodeJS
👍8
سلام و ارادت دوستان. خیلی وقت بود میخواستم ویدیو بسازم و راجع به یک سری موضوعات صحبت کنم. البته این ویدیو بیشتر معرفی خودم و یکسری نکات درمورد چنل هست.

به زودی ویدیو های تکنیکال درمورد موضوعاتی که تو کانال داریم به صورت عمیق تر خواهیم داشت.
جا داره از همتون تشکر کنم و خوشحالم اگر مطالب براتون مفید بوده❤️

ممنون میشم این ویدیو هم ببینید.

https://youtu.be/znWtGcqHWbQ?si=IJDCOcPqDDJ_SeAF
👍15
Node Master
یکی از مشکلاتی که Node داشت و Deno سعی بر حل آن بود امنیت اجرای پکیج های 3rd party بود که اگر پکیجی بخواهد کارهایی از قبیل دسترسی به network یا خواندن و نوشتن دیتا روی disk انجام دهد شما باید به عنوان developer تایید کنید و اجازه دسترسی بدهید. و حالا در Node…
یک خبری چند روز پیش درمورد امنیت پکیج های NPM اومده بود که کره شمالی قصد دزدی از کیف پول های cryptocurrency ها با استفاده از پکیج آلوده داشته که میتونید جزیاتش رو از لینک زیر مطالعه کنید.
https://www.nodejs-security.com/blog/north-korea-malware-on-npm-and-ledger-connect-kit-crypto-heist

این دقیقا همون دلیلی هست که #Deno برای امنیت permission رو اضافه کرد و #NodeJS هم این قابلیت رو در حال حاظر به صورت experimental برای جلوگیری از این دسته مشکلات اضافه کرد.

خلاصه بگم. اگر پکیج اضافه میکنید به پروژه که دارید. چندین بار درمورد اون پکیج فکر کنید که آیا اصلا لازم دارید یا خیر.

نکته best practice : هرچقدر از پکیج های کمتری استفاده کنید زندگی راحت تری در نگهداری پروژه در طولانی مدت خواهید داشت.

#NodeWeekly
👍3
در خیلی از زبان های برنامه نویسی مثل #Python #javanoscript #Golang و ... میبینیم که میگن فانکشن ها first class citizen function هستن. این موضوع خیلی میتونه تاثیر در برنامه های نوشته شده در زبان مورد نظر داشته باشه.
اصلا چرا بهشون میگیم first class citizen ؟
چیکار ها میتونیم انجام بدیم باهاشون؟

یکم راجع به این موضوع فکر کنید فردا راجع بهش صحبت خواهیم کرد.
https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function
👍4
خب first class function یعنی چی؟
به این موضوع هست که شما میتونید با function ها مثل بقیه object ها رفتار کنید. یعنی در متغیر ذخیرشون کنید یک لیستی از function ها داشته باشید و یا حتی در runtime فانکشن جدید بسازید و return کنید.
این موضوع خیلی نکته قوی هست که کلا decorator pattern درمورد این موضوع هست. البته این موضوع فقط مربوط به فانکشن ها نیست و بلکه شما میتونید همین کار رو برای کلاس ها و attr ها هم انجام بدید.

یکم بخوایم به موضوع بهتر نگاه کنیم در اصل این کار یکی از تکنیک های پر استفاده در Metaprograming میباشد که در فریمورک ها خیلی پر استفاده هست. یکسری فریمورک ها مثل NestJS سنگین از این موضوع استفاده میکنند.
فرض کنید لیستی داریم از چهار فانکشن که ۴ عمل اصلی ریاضی رو انجام میدن.
const sum = (a, b) => a + b;
const division = (a, b) => a / b;
const multiply = (a, b) => a * b;
const minus = (a, b) => a - b;

const operators = [sum, division, multiply, minus];

operators.forEach((fn) => {
console.log(fn(6, 2));
});

همچین چیزی رو داخل کد هایی که روزمره استفاده میکنید ممکنه که نبینید. این موضوع منطقی هست استفاده از این تکنیکا ها کاربردهای خاصی دارند که کمتر در پروژه های saas بهشون نیاز میشه. ( به معنی صفر بودن استفاده نیست :) )

یک مثال یک خورده عملی تر در express میتونیم middleware بسازیم. فرض کنید میخوایم یک سری route رو محافظت کنیم که یک سری role خاص بتونن به اون دسترسی داشته باشن. در ساده ترین حالت ممکن این هست.
let app; // imagine it's an express instance. :)

// Dummy controller function.
const protectedLogic = () => {};

const ADMIN = "ADMIN";
const NORMAL = "NORMAL";

function adminUse(req, res, next) {
if (req.role === NORMAL) next();
}
function normalUse(req, res, next) {
if (req.role === ADMIN) next();
}

// Express routes.
app.get("/admin", adminUse, protectedLogic);
app.get("/user", normalUse, protectedLogic);

این مدل کد خیلی استفاده میشه. مزیتی که داره ساده و خوانا هست ولی عیب بزرگش scale نمیشه رفت. فرض کنید 100 تا role داریم. یعنی 100 فانکشن. نکته سخت داستان این هست که در route ها ما باید reference از فانکشن ها بدیم و نه call کنیم یکم دقیق تر بگم در اینجا express برای ما IOC (inversion of control) داره انجام میده و مجبورمون میکنه اینطور کد بزنیم.
دلیل این هم که نمیتونیم کاری کنیم این هست که ما در زمان compile time داریم adminUse و normalUse رو ایجاد میکنیم که باز دست ما رو میبنده. اگر بتونیم با code مثل بقیه data ها رفتار کنیم مشکل حل میشه یعنی در runtime فاکشن ایجاد کنیم نه compile time !
اگر بخوایم حرف بالا رو عملی کنیم این شکل میشه.
function roleFactroy(rank) {
return function (req, res, next) {
if (req.role === rank) next();
};
}

// Express routes.
app.get("/admin", roleFactroy(ADMIN), protectedLogic);
app.get("/user", roleFactroy(NORMAL), protectedLogic);

دقت کنید دوستان ما فانکشن رو invoke نمیکنیم و حالا در runtime داریم اون رو میسازیم. موضوع خیلی خیلی مهمی که باید برای پشت پرده این داستان بدونید Closure هست. فانکشن roleFactory در حقیقت وظیفه تولید function جدید در runtime دارد. حالا شما همین کار رو میتونید برای هرچیزی در #Javanoscript کنید.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures

توجه داشته باشید این مثال production ready نیست و صرفا برای گرفتن دید درمورد این موضوع هست. این موضوع اینجا تموم نشده و در پست بعدی مثال دیگه ای میزنیم.

درمورد کاربرد های دیگه این موضوع فکر کنید و نظراتتون رو کامنت کنید.

#Tip
👍18
Node Master
خب first class function یعنی چی؟ به این موضوع هست که شما میتونید با function ها مثل بقیه object ها رفتار کنید. یعنی در متغیر ذخیرشون کنید یک لیستی از function ها داشته باشید و یا حتی در runtime فانکشن جدید بسازید و return کنید. این موضوع خیلی نکته قوی هست…
خب هنوز یک قدم میخوایم پا رو فراتر بزاریم و class رو در runtime بسازیم. اول این که در #Javanoscript کلاس ها در حقیقت همون فانکشن ها هستن و صرفا کلمه class یک syntactic sugar روی نسخه ES5 هست. کلمه class در آپدیت معروف ES6 به #Javanoscript اضافه شد.
یعنی این دوتا باهم برابر هستند.
// Syntactic Sugar
class User {
constructor(name, last_name) {
this.name = name;
this.last_name = last_name;
}

printFullName() {
console.log(this.name + " " + this.last_name);
}
}

function User2(name, last_name) {
this.name = name;
this.last_name = last_name;
}
User2.prototype.printFullName = function () {
console.log(this.name + " " + this.last_name);
};

// Think about this part. 🤔

const users = [new User("iman", "hpr"), new User2("iman", "hpr")];

users.forEach((user) => console.log(user.printFullName()));

قدیما وقتی میخواستن کلاس بسازن از syntax به شکل User2 استفاده میکردن. اسم این مدل ES5 function constructors ولی چون شکل قشنگی نداشت class syntax رو اضاف کردن. هردو اینا دقیق برابر هستن یعنی در اصل class syntax اون پشت تبدیل میشه به مدل User2 اینطور تصور کنید.
اونجا که کامنت کردم خیلی میتونست ساده تر باشه. دیدم فرصت خوبی هست که بحثش رو بیارم وسط. بحث خیلی مهمی هست و یکی از خاصیت های زبان های dynamic type هست. فکر کنید راجع بهش کامنت بزارید در ادامه درموردش صحبت خواهیم کرد.

میریم سر اصل مطلب. اگر دقت کنید قدیما وقتی میخواستن کلاس بسازن از function استفاده میکردن ( منطقی یا غیرمنطقی بودن این موضوع یک بحث دیگس که کاری نداریم) پست قبلی یاد گرفتیم که function ها در حقیقت first class هستن و میتونیم هرکاری باهاشون کنیم! آفرین دقیقه نکته داستان همینه. به این دلیل که کلاس ها تبدیل میشن به ES5 function constructors اون پشت پس تمامی کارایی که قبل میتونستیم کنیم مجازه. بریم برای مثال.
function buttonFactory(color) {
return class {
#color = color;
get color() {
return this.#color;
}

show() {
console.log("Button is " + this.#color);
}
};
}

const BlueBtnCls = buttonFactory("blue");
const RedBtnCls = buttonFactory("red");

const blueBtn = new BlueBtnCls();
const redBtn = new RedBtnCls();

// Here we go agin 😉. Think about it one more 🤔
const btns = [blueBtn, redBtn].forEach((btn) => btn.show());

مثال یکم فرانتی هست. ما کلاس رو در runtime ایجاد کردیم و براش private attr ست کردیم و اگر این کد رو اجرا کنید میبینید هم getter به درستی کار میکنه و هم شما مستقیم دسترسی به color ندارید. نکته جالب اینه دوباره برا مثال خوردیم به pattern بالا که گفتم. بهش فکر کنید.

یک نکته ای که وجود داره اینه که این ها anonymous class هستن و اسم ندارند. کد زیر رو اجرا کنید
const BlueBtnCls = buttonFactory("blue");
console.log(BlueBtnCls) // out : [class (anonymous)]
console.log(BlueBtnCls.name)

حالا اگر بخوایم name رو به صورت HardCode بزنیم داخل btnFactory قشنگ در نمیاد چون همه کلاس ها یک اسم خواهند داشت. اگر anonymous هم باشیم ساعت های سختی رو برای debug خواهیم داشت.
تا همینجا برای این پست کافیه پست بعدی یکم عمیق تر میشیم در metaprograming.
👍13
Node Master
Hint for question :) 🦆
جواب این سوال Duck Typing بود که در آینده حتما راجع بهش صحبت میکنیم.
پست بعدی ادامه همین پست رو کامل میکنیم👍
👍3
Node Master
خب هنوز یک قدم میخوایم پا رو فراتر بزاریم و class رو در runtime بسازیم. اول این که در #Javanoscript کلاس ها در حقیقت همون فانکشن ها هستن و صرفا کلمه class یک syntactic sugar روی نسخه ES5 هست. کلمه class در آپدیت معروف ES6 به #Javanoscript اضافه شد. یعنی این دوتا…
در پست قبل یاد گرفتیم که چطور یک کلاس در Runtime بسازیم. و موضوعی باز موند که چطور میتونیم اسم کلاس ها هم در Runtime تغییر بدیم. برای این کار نیاز به یک تکنیک دیگه که در #Metaprogramming خیلی پر استفاده هست باید استفاده کنیم. به اسم Reflection. این تکنیک در اکثر زبان ها به طریقی وجود داره. golang و java دقیقا lib های خیلی قوی مربوط به این تکنیک دارند. متاسفانه Reflection در #Javanoscript خیلی محدود هست و قدرت زبان های دیگ رو نداره ولی اینجا کاربرد داره.
- حالا Reflection چیست؟ در حقیقت Reflection به معنی توضیح دادن یک کد با استفاده از یک کد دیگه.
زبان Lisp یک زبان قدیمی هست و استفاده خاصی این روزا نداره ولی یک فلسفه خیلی معروف به دنیای برنامه نویسی معرفی کرد.
- "Code Is Data"
بخوایم توضیح بالا رو کامل تر و ساده تر کنیم یعنی با کد برنامه مثل دیتا معمولی رفتار کنیم! این هم بگم اگر یکم درکش سخت هست براتون کاملا منطقیه. این نوع تفکر نیاز به تمرین زیادی داره پس زیاد سخت نگیرید.
راجع به Lisp و این موضوع در آینده بیشتر صحبت میکنیم.

حالا کد بالا رو در نظر بگیرید. و به مثال زیر دقت کنید.
function buttonFactory(color) {
const cls = class {
#color = color;
get color() {
return this.#color;
}

show() {
console.log("Button is " + this.#color);
}
};
Reflect.defineProperty(cls, "name", {
writable: false,
value: color[0].toUpperCase() + color.slice(1) + "Btn",
});
return cls;
}

برای این که کد بالا رو توضیح بدم اول این نکته رو باید در نظر داشته باشید که هر function یک attr به اسم name داره که اسم فانکشن هست. اگر راهی پیدا کنیم که بتونیم این رو در runtime تغییر بدیم پس مشکلی نخواهیم داشت.
function SayMyName() {}
console.log(SayMyName.name);

در #Javanoscript دو namespace برای کمک به ما در Reflection وجود دارد.
- Reflect
- Object
در این name space ها یک سری static method برای کمک هستن که در کد بالا نمونه ای میبینید که ما اومدیم یک cls رو ساختیم و reference اون رو نگهداری میکنیم. بعد با استفاده از اون ref و کمک reflection در runtime به راحتی name رو به چیزی که میخوایم تغییر میدیم. بعد ref رو return میکنیم.

نکته در مورد مثال:
- خیلی خلاصه گویی شده به دلیلی که مطلب طولانی نشه.
- اینجا هدف فقط اشاره و لمس این موضوع هست در آینده بیشتر صحبت خواهیم کرد.
👍14
نسخه 20.11 LTS برای #NodeJS منتشر شد.
- بهینه سازی های خیلی زیاد در fs module اتفاق افتاده.
- اضافه کردن معادل __dirname و __filename که در CJS وجود داشت در ماژول های ESM
import.meta.dirname // ESM
__dirname //CJS

import.meta.filename // ESM
__filename //CJS

قدیما برای بدست اوردن filename و dirname باید با استفاده از import.meta.url اینکار میکردی که زیاد جالب نبود.
به عنوان مثال معادل import.meta.dirname قبل از این ورژن این شکل بود.
import path from "node:path";
import url from "node:url";

const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); // Before 20.11 LTS
// import.meta.dirname 20.11 LTS
const __filename = url.fileURLToPath(import.meta.url); // Before 20.11 LTS
// import.meta.filename 20.11 LTS

console.log(__filename);
console.log(__dirname);

#NodeJS
#Update
👍17
Node Master
سلام و ارادت دوستان. نکته امروز رو با یک سوال شروع میکنیم. بنظرتون چرا باید از Object.freeze بیشتر استفاده کنیم؟ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
این شاید یک static method کوچیک باشه ولی فلسفه پشتش نیاز به توضیح زیادی داره. به این مثال توجه کنید.
const channel = Object.freeze({ name: "NodeMaster" });
channel.name = "IDK"; // TypeError

خیلی ساده هست با کمک Object.freeze من object مورد نظر رو به readonly تبدیل میکنم و شما نمیتونید این رو عوض کنید. ساده بنظر میاد اما اصلا چرا به همچین چیزی نیاز داریم؟ در کل اکوسیستم این رفتار رو به شکل ها و سطوح مختلف میبینید که پایین چنتا مثال زدم.

- در زبان #RustLang تمامی variable ها به صورت پیشفرض immutable هستند و شما باید به صراحت اعلام کنید که یک variable mutable هست.
- یکی از اصول زبان های functional تاکید بر immutable بودن object ها دارد.
- یک best practise وجود داره که میگه همیشه از const استفاده کنید مگر واقعا نیاز داشته باشید که این کار رو نکنید.

پشت تمامی این داستان ها میرسیم به یک جمله معروف که میگه "mutability is evil". تمام نکات بالا برمیگرده به همین جمله معروف اما سوال پیش میاد که چرا برای این موضوع اینقدر پیچدگی داریم؟ اصلا چرا؟
جواب این هست که immutable بودن object ها به ما کمک میکند تا side effect ها را به حداقل برسونیم. این نکته به این معنی نیست که side effect ها چیز بدی هست. نکته این هست که بدون side effect کلا نوشتن برنامه مفید غیرممکنه ولی اگر کمترش کنیم بهمون میتونه کمک کنه. حالا چنتا سوال خیلی مهم پیش میاد برامون.

- داستان side effect چی هست و چرا باید کمترش کنیم؟
- داستان immutable و mutable چیست؟
- چطور کمتر کردن side effect بهمون کمک میکنه؟
- کجاها side effect میتونه فاجعه بار باشه؟
- ربط mutability با side effect چیه؟

جواب دادن به هرکدوم از این سوالات وقت زیادی میخواد که باهم این ها رو در آینده نگاه میکنیم. این نکته رو یادتون باشه که دونستن این نکات خیلی میتونه بهمون کمک کنه که software engineer بهتری باشیم. از چیز های کوچیک سطحی رد نشیم و سعی کنیم چشمامون رو عادت بدیم که دقیق نگاه کنیم.

#Tip
👍14
Node Master
بزارید ادامه این بحث رو با توضیح کوتاهی از Process شروع کنیم. Process چیست؟ در حقیقت Process یک instace از یک برنامه در حال اجرا که معمولا روی RAM جا دارد. برنامه در حال اجرا روی سیستم عامل برای اجرا دستورات خود نیاز به منابعی از قبیل حافظه و cpu time دارد.…
امروز در گروه کانال بچه ها راجع به concurrency در #NodeJS یکم صحبت کردن من هم از این فرصت استفاده میکنم توضیحاتی بدم.
این جمله رو زیاد شنیدیم #NodeJS به صورت Single thread و async هست. این جمله یک نقص بزرگ داره و آدم رو به اشتباه میندازه. کامل تر این شکل میشه که بخش آخر رو بگیم #NodeJS در حقیقت Async I/O است. این I/O خیلی مهم هست. در برنامه نویسی هر task به دو دسته تقسیم میشه که میشه به چشم bottleneck نگاه کرد
- کار های I/O base (Input/Output) : منظور از این مدل کار ها گرفتن یا فرستادن اطلاعات به کلاینت مثل فرستادن http request دریافت http response یا همون network یا کار با file system و ...
- کار های CPU Intensive ( به صورت عادی باعث بلاک شدن event loop و یا کند شدن میشوند. ) : تبدیل فرمت عکس از jpg به png یا پرداش ویدیو یا tls termintion یا فرایند فشرده سازی http response تولید شده با استفاده از gzip. حتی for loop ساده !
ما concurrency مدل های مختلفی داریم که مثال
- Async IO
- multithreading
- multiprocessing
برای کار های از نوع IO بهترین مدل asyic i/o هست برای کار های cpu intesive دو مدل دیگ. مدل hybrid و ترکیبی اینها هم وجود داره که خیلی پیشرفته هستن و زیاد هم استفاده میشن. نمونه خیلی معروف مدل Hybrid که انقلاب بود و هست Nginx.
در بهترین حالت این هست که ما با #NodeJS کار CPU intensive انجام ندیم اما گاهی مجبوریم. حالا با استفاده از "node:child_process" و "node:worker_thread" میتونیم کمک خیلی زیادی به Node کنیم.
در مثال پایین با یک کار فیک CPU intensive به طور کل event loop رو بلاک میکنیم و بعد با worker thread برنامه رو سریع تر میکنیم. اول با تعریف یک کار cpu intensive شروع میکنیم
function cpuBlockingTask() {
for (let i = 0; i < 5e5; ++i) console.log(i);
}

کد خیلی ساده هست با for تا 500.000 هزار میشماریم لاگ میگیریم. این به این معنی هست هربار در برنامه node خودتون دارید loop میزنید در حقیقت دارید به Node خیانت میکنین. به هیچ عنوان روی آرایه های بزرگ از متد های foreach, map ,every و ... استفاده نکنید.
بعد با http ماژول یک وب سرور ساده مینویسیم
import http from "node:http";

function cpuBlockingTask() {
for (let i = 0; i < 5e5; ++i) console.log(i);
}
http
.createServer((req, res) => {
cpuBlockingTask(); // Block event loop
res.end("Done"); // Send response after loop
})
.listen(3000, () => console.log("Server is listning on port", 3000));

روی پورت 3000 یک وب سرور داریم که بعد از انجام دادن کار cpuBlockingTask یک 200 با متن Done میفرسته. سرور رو ران کنید.
یک ابزار هست به اسم AutoCannon برای Load test های ساده استفاده میشه. حجم زیادی از ریکوست رو میفرستیم سمت سرور.
https://www.npmjs.com/package/autocannon
توپ رو شلیک میکنیم سمت سرور با حالت پیشفرض که داخل داکیومنت نوشته البته یک flag هم ست میکنیم تا درخواست های موفق رو بشماریم.
autocannon --renderStatusCodes localhost:3000

نتیجه در سیستم من‌ : فقط ۳ ریکوست موفق با تنظیمات پیشفرض

بخش اول ❇️
ادامه پست بعدی ❇️
👍7
Node Master
امروز در گروه کانال بچه ها راجع به concurrency در #NodeJS یکم صحبت کردن من هم از این فرصت استفاده میکنم توضیحاتی بدم. این جمله رو زیاد شنیدیم #NodeJS به صورت Single thread و async هست. این جمله یک نقص بزرگ داره و آدم رو به اشتباه میندازه. کامل تر این شکل میشه…
حالا با worker thread به Node کمک میکنیم.
import http from "node:http";
import { fileURLToPath } from "node:url";
import { Worker, isMainThread, parentPort } from "node:worker_threads";

const __filename = fileURLToPath(import.meta.url);

if (isMainThread) {
// This code will run by main thread
http
.createServer((req, res) => {
const worker = new Worker(__filename, { stdout: true });
worker.on("exit", () => {
res.end("Done");
});
worker.postMessage(null);
})
.listen(3000, () => console.log("Server is listning on port", 3000));
} else {
// This code will run by workers
function cpuBlockingTask() {
for (let i = 0; i < 5e5; ++i) console.log(i);
}

parentPort.on("message", () => {
cpuBlockingTask(); // Run Blocking Task on worker thread
process.exit(); // exit worker thread after task
});
}

خیلی وارد جزیات نمیشم اول با isMainThread تشخیص میدیم آیا داخل main thread برنامه هستیم یا خیر. در thread اصلی وب سرور رو run میکنیم و کار های سخت رو میدیم به worker ها که در else block هست. نکته جذاب اینجا هست که ارتباط بین thread ها با استفاده به یک چیزی شبیه به چنل ها در #GoLang هست. برای هر ریکوستی که به سمت سرور میاد یک worker ایجاد میکنیم و وقتی کارش تموم شد done رو میفرستیم سمت کلاینت. چون thread ها با message ها مختلف با هم صحبت میکنن ما با worker.postMessage میگیم که کارمون رو انجام بده. بعد شما وقتی process.exit در worker thread انجام میدی اون thread خارج میشه و برنامه اصلی کار میکنه و اینطور میتونیم به thread اصلی بگیم که من کارم تموم شد response رو بفرست. خیلی وارد جزیات فلن نمیشیم و برنامه رو اجرا میکنیم با کامند بالا با استفاده از AutoCannon
نتیجه در سیستم من‌ : ۶۰ ریکوست موفق با تنظیمات پیشفرض.

همینطور که میبینید با کدی که خیلی خوب نیست 20 برابر در این مثال ساده تونستیم pref رو ببریم بالاتر. حالا نکاتی که باید در نظر بگرید درمورد کد.
- این کد اصلا خوب نیست به دلیل این که در scale زیاد اگر برای هر ریکوست یک native thread باز کنیم نه تنها باعث سریع تر شدن نمیشه بلکه از یک حدی برنامه شروع به خزیدن روی زمین میکنه.
- به صورت کلی concurrency در برنامه نویسی یک تخصص سخت هست یعنی شما میتونی اینقدر عمیق بشی در این مبحث که با noscript شغلی Concurrency Expert یا Concurrency Specialist داشته باشی.
- برای concurrency هم یک سری دیزاین پترن خیلی مهم وجود داره مثل worker pool که میتونید راجع بهشون بخونید و این ادامه نکته دوم هست.
👍19
2 روز پیش نسخه 21.6 #NodeJS منتشر شد. واقعا سرعت آپدیت #NodeJS خیلی بالا هست. از مهم ترین ویژگی هایی که اضاف شده به این نسخه.
- به permission system یک flag جدید اضافه شده که در صورت import کردن native module ها باید به صورت explicit اجازه بدین.
node --experimental-permission --allow-addons

- حالا در این نسخه فلگ --allow-fs-* به راحتی میتونید از relative path استفاده کنید.
node --experimental-permission --allow-fs-read=./index.js

- یک فلگ جدید اضافه شده به اسم --build-snapshot-config. این flag کمکی هست برای build-snapshot. این flag خیلی پر استفاده برای برنامه های روزمره نیست ولی خب در آینده درمورد این flag صحبت خواهیم کرد.

https://nodejs.org/en/blog/release/v21.6.0
👍7
امروز درمورد Duck Typing صحبت میکنیم. این موضوع مربوط به رفتار زبان های dynamic type میباشد. البته این تکنیک در زبان هایی static type هم در حالت های خاصی استفاده میشود. برای درک این موضوع با مثال در #Python شروع میکنیم.
class Duck:
def fly(self):
print("quak quak !")

class Airplane:
def fly(self):
print("boom boom !")

#Duck Test
def fly_test(vehicle):
vehicle.fly()

flyable = [Duck() , Airplane()]
for f in flyable:
fly_test(f)

یک جمله خیلی معروف و کلیدی در این مورد وجود داره که باتوجه به اون مثال بالا رو توضیح میدیم."if it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck."
به این معنی هست "اگر شبیه به اردک شنا میکنه کواک میکنه پس احتملا اردک هست."
در زبان های dynamic type مفهومی به اسم interface نداریم و اگر یک class یک method رو تغریف کرده باشه شما بدون نیاز به type میتونید اون method رو به راحتی call کنید. الان در کد بالا هیچ نشانه ای از type نیست و فانکشن fly_test بدون داشتن دانشی از این که ایا arg ورودی fly method دارد یا خیر این متد رو call میکنه. به این کار میگن duck testing. در کل بگم به هیچ عنوان fly_test براش مهم نیست vehicle چی هست فقط براش مهم هست که fly وجود داشته باشد.
حالا سوال پیش میاد که اگر این متد نبود چی؟ الان در این مثال اگر اگر متد fly نباشه روی یکی از این کلاس ها خب runtime error داریم و برنامه crash میکنه. دو دیدگاه برای جلوگیری از این مدل runtime error ها داریم که در پست بعدی برسی میکنیم هردو رو.
نکته جالب دیگه این هست که Airplane و Duck این دو کلاس هیچ رابطه ای با هم ندارند و صرفا فقط به صورت قراردادی هردو یک fly method رو implement کردن. در #TypeScript از Duck Testing زیاد استفاده میشه برای داشتن کد TypeSafe در حقیقت تکنیک Type Predict به نوعی Duck Test میتونه محسوب بشه.

این مقدمه ای برای این بحث بود. در حقیقت برای داشتن همچین مدل رفتاری مدل های فکری مختلفی در زبان های مختلف هست. در زبان #Java ما از inerface ها و abstract class ها استفاده میکنیم در #GoLang شما یک نوع دیگه از Duck Typing رو میبینید که بهش میگن Structural Typing و interface های golang بهمون کمک میکنن در #TypeScript هم Structural Typing به شدت مرسوم هست و مثال خواهیم زد، در پایتون که Duck Typing رو دیدید ولی نکته جالب اینجا هست که Structural Typing و abstract class ها هم در پایتون خیلی بهمون کمک میکنن ولی خب کمتر کسی از وجود این ها خبر داره.
این نکته هم بگم که هیچ کدوم از این راه حل ها نسبت به دیگری برتری خاصی ندارند صرفا نوع تفکره بیشتر البته البته زبان های Static و TypeSafe میتونن develop رو راحت تر کنن در این مورد. این که کدوم تکنیک در کدوم زبان استفاده میشه مهم هست چون که به عنوان مثال Duck Typing در java خیلی مرسوم نیست و استفاده ازش سخت تره اما در یک حالت های خاصی خیلی میتونه در این زبان کمک کنه.
#Tip
👍11