Geeking Around – Telegram
#frontend_dev

https://100dayscss.com/

توی مسیر یادگیری، شاید مهم ترین چیز consistency باشه. اینکه یه کار رو مدام تکرار کنین، مدام سراغش برید خودتون رو به چالش بکشید. این جور چلنج ها که باید تقریباً هر روز یه حرکتی بزنین‌ خیلی کمک کننده‌س.

پ.ن. البته جالبه که این حرف رو کسی میزنه که خودش دائم هی Advent of code شرکت میکنه و همش روز ۲ یا ۳ دیگه ادامه‌ش نمیده:)))))🤦🏻‍♂️🤦🏻‍♂️
https://github.com/epicmet/advent-of-code/
#frontend_dev

تا حالا براتون سوال نشده که وقتی توی وب با fetch API به یه JSON API ریکوئست میزنیم، چرا باید دوباره await کنیمش؟
const response = await fetch("my.web.com");
const data = await response.json();


اگر نمیدونین چرا، تا حالا عمیق به ریکوئستی که میزنین و اتفاقای که under the hood میوفته دقت نکردین. حتماً این ویدیو رو نگاه کنین، دیدتون رو باز تر میکنه.

https://youtu.be/Ki64Cnyf_cA?si=fqL4KhQX-0UXsZIo
👍1🙏1
https://github.com/ErikMcClure/bad-licenses

یه لایسنس مسخره گذاشته بودم چند وقت پیش، الان چنتا بهتر از اون پیدا کردم:))))
یکی‌شون اینطوریه که "تو وقتی میتونی سورس‌کد رو تغییر بدی که رنک overwatchت از رنک maintainer ها بیشتر باشه":)))))))))
🤣1
#learning_resource

https://fmhy.net/

Largest collection of free stuff on internet

پ.ن. سایت soft۹۸ و git_ir رو هم توشون پیدا کردم:))
👍2😁1
https://dagger.io/blog/replaced-react-with-go

اینم شایان فرستاد، خوندم جالب بود. کد فرانت‌شونو بردن روی یه کد بیس golang که هم TUI و هم وب‌شونو باهاش هندل کنن. جالب بود یه نگاهی بندازین.

یه جایی خیلی وقت پیش خونده بودم اسپاتی‌فای هم برای اپلیکیشن های desktopش و وب‌ش برای اینکه یه شکل باشن و UI ثابت باشه، اومده بودن design systemشونو همچین حرکتی زده بودن. سرچ کنین پیداش میکنین مقاله‌شو.
👍1
What do the best programmers have in common?

https://endler.dev/2025/best-programmers/

Don’t go to Stack Overflow, don’t ask the LLM, don’t guess, just go straight to the source. Oftentimes, it’s surprisingly accessible and well-written.
احتمالاً پیش اومده براتون که پسورد یه سایتی یا اپلیکشینی که استفاده میکنین رو فراموش کرده باشید و بخواین Reset password کنین. ولی وقتی پسورد جدید رو میزنین، یه همچین پیامی میگیرید:
Your new password is too similar to your current password. Please try another password.


من اصلاً بهش توجه‌ای نمیکردم که چطور پیاده سازی میشه همچین چیزی. تا اینکه یه روز توی توییتر دیدم یکی پرسیده مگه پسورد رو Hash نمیکنین؟ پس چطور میتونین بفهمید پسورد جدید شبیه پسورد قدیدیمه Hash شده‌س؟!

ما وقتی پسورد یوزر هارو توی دیتابیس ذخیره میکنیم، نباید به صورت Plain text ذخیره کنیم. اگر به هر صورتی هک بکشیم، اینطوری کل اطلاعات یوزر های ما با یک نگاه بر باد میره. به این هم توجه کنین اکثر آدم ها از یک پسورد برای همه چیز استفاده میکنن یا پسورد هاشون توی سایت های مختلفی که استفاده میکنن خیلی شبیه به هم دیگه‌س. پس خیلی بهتره که پسورد هارو Hash کنیم.
خود Hash کردن داستان زیاد داره. حتی با Hash کردن خالی، پسورد ها هنوز تا حدی قابل حدسه! (Rainbow attack table) حتی یه سری Vulnerability خیلی خفن و عجیب مثل Timing attack password hashing وجود دارن که باید حواسمون بهش باشه. داستانش طولانیه و اگر دوس داشتین میتونم توی یه پست دیگه راجب اونم بنویسم مفصل.

اما علی‌الحساب باید چنتا نکته راجب Hashing functions بدونیم تا بهتر قضیه رو متوجه بشیم.
- یکی از ویژگی های یک Hashing function اینه که باید یک طرفه باشه. ینی وقتی من بهش A رو میدم و اون فانکشن بهم B رو برگردونه، راهی نباید باشه که من از B به A برسم.
- اندازه output که توسط Hashing function برمیگرده باید مستقل از input باشه و همیشه باید ثابت باشه. فرقی نداره که input ما چقدره.
- با کوچیک ترین تغییر input، مقدار output باید کاملاً متفاوت باشه. برای مثال:
hash("abcd") -> "JPtLwmkTrHfnH"
hash("abdc") -> "VqdmWPHCZAPdN"


حالا که همه‌ی اینارو میدونیم، به این فکر میکنیم که چطور وقتی پیام
Your new password is too similar to your current password. Please try another password.

رو میگیریم باید تعجب کنیم! مقدار Hash شده‌ی پسورد سابق ما، قابل مقایسه با پسورد جدید نیست. (چون همونطور که گفتیم با کوچیک ترین تغییر input، باید output کاملاً عوض بشه). پس تنها راهی که میتونیم مقایسه‌شون کنیم اینه که پسورد رو plain ذخیره کنیم! درسته؟ خیر:))) چنتا راه هست که این کارو به صورت امن انجام بدیم.

یه راه حلی برای مثال Facebook انجام میده اینه:
۱. شما پسورد اکانتتون برای مثال "first" هست.
۲. اقدام به عوض کردن پسوردتون میکنین و پسورد جدید رو "First2" وارد میکنین.
۳. اینجا Facebook میاد از پسورد جدید که وارد کردید، یه سری پسورد مشابه میسازه. برای مثال:
"first2", "FIRST2", "Ffirst23", ...

۴. برای هر کدوم از این پسورد هایی که ساخته خودش، Hash شون رو حساب میکنه و با Hash پسورد فعلی مقایسه‌شون میکنه.
۵. اگر پسورد جدید شما خیلی مشابه پسورد فعلی باشه، امکان داره اون الگوریتم ساخت پسورد های مشابه، پسورد سابق شمارو بسازه! توی این مثال، احتمال خیلی زیاد از "First2" میشه به "first" رسید و وقتی Hash میشه میبینیم مقدارش توی دیتابیس هست. پس در نتیجه پسورد جدید خیلی مشابه پسورد سابق هست.

یک راه دیگه Fuzzy Hashing هست. کاربرد اصلیش با Hash function هایی که ما تا الان راجبشون حرف زدیم متفاوته. از Fuzzy hashing (یا Similarity hashing) برای پیدا کردن Malware یا حتی برای تکنیک های data loss prevention استفاده میشه. ولی اینجام به کارمون میاد.
یکی از راه های ساختن این الگوریتم Context triggered piecewise hashing هستش. به زبون ساده، قسمت های مختلف input رو میشکونن و هر قسمت رو hash میکنن و بعد همه‌ی تیکه های مختلف hash شده رو بهم میچسبونن. برای مثال بیایم "first" رو به "f", "i" و ... تقسیم کنیم و هر قسمت رو hash کنیم. بحثش خیلی مفصل تره و احتمالاً توی آینده بیشتر راجب بنویسم.

👾 @geekingaround
3👍1
دولوپر ها توی ۱۰ رتبه‌ی برتر از نظر خودکشی توی مشاغل هستن. ۸۳٪ دولوپر ها Burn out رو تجربه میکنن.

یکی از ویدیو های چنل HealthyGamerGG رو میدیم که راجب Burn out کردن Software engineer ها صحبت میکرد. لینک‌شو توی پست میزارم، پیشنهاد میکنم حتماً خود ویدیو و چنل‌شو ببنین. ولی خب برداشت خودم و خلاصه‌ای از چیزی که فهیمدم هم میزارم، امیدوارم به دردتون بخوره.

تمام مشاغل دنیا مشکلات و سختی هایی دارن. کسانی که توی محیط بالینی کار میکنن و با مریض سرکار دارن، خیلی اوقات جون خودشون توی خطر هست.
یا یه کسی که پیک موتوری کار میکنه، هر لحظه از کارش خطر تصادف و مشکلاتی که موتور میتونه داشته باشه رو به جون میخره.
حتی اگر شما صاحب کار خودتون باشید، بازم حجم استرس و مسئولیت زیادی رو به دوش میکشید. هیچ شغل یا کاری نیست که مشکل یا سختی نداشته باشه.

خیلی از ما دولوپر ها هم میدونیم نسبت به اکثریت جامعه و اکثریت هم‌سن و سال هامون بیشتر درآمد داریم (حتی توی این وضعیت بد اقتصادی). پس چرا اینقدر آمار Burn out زیاده؟ ما که پول خوبی در میاریم و میدونیم بالاخره هر شغلی سختی های خودشو داره.

یکی از نکاتش اینه که Scope of work و Timeline اکثریت شغل ها مشخصه و تغییر توشون کمه. ولی برای ما نه. هر لحظه ممکنه اتفاقی بیوفته و ما مجبور باشیم تا آخر فلان روز، فلان فیچر و فلان ریلیز رو بدیم.
این ۲ تا مشکل داره. اول اینکه این تغییر های ناگهانی خیلی بیشتر از چیزی که بتونین فکرشو بکنین روی شما تاثیر میزارن. دوم اینکه به اصطلاحی که Dr. K (صاحب چنل ویدیویی که گذاشتم) میگه ما Set up for failure میشیم. به این معنی که اگر ما نرسیم اون کارو انجام بدیم، ما مقصریم. کسی نمیره بگرده بگه خب CEO یا فلان PM درست زمان بندی نکرد، همه‌ی انگشت های تقصیر به سمت دولوپر جماعته. اما از اون طرف اگر موفق بشیم، حالا انتظارات رو بالا بردیم:))) حالا سری بعدی که از این اتفاقات بیوفته، دیگه انتظار از ما اینه که مثل سری قبل کارو به همون نحو عالی و در زمان تعیین شده تحویل بدیم!
مشکلات این چنینی زیاده، برای مثال کار ریموت باعث میشه مرز بین خونه و کار از بین بره. فارغ از تاثیری که روی ناخودآگاه ذهن‌مون میزاره، کارفرمای ما انتظاراتش از ما بیشتره چون حتی اونم متوجه نیست الان خونه‌ایم یا سرکاریم.
یا مثلاً یکی از چیزای دیگه که اشاره کردن، همکارای رو مخ هست:)))) اونم به این خاطر میگفت که اکثر آدم های توی Tech، یکم از لحاظ اجتماعی سخت ارتباط میگیرن.

همه‌ی اینا جمع میشه و جمع میشه باعث Burn out یا نارضایتی از کار میشه.
حالا ملتی که ما باشیم، در مواجهه با اینجور مشکلات چیکار میکنیم؟ کاری که اکثر مردم دنیا در مواجهه با هر مشکلی میکنن. حذف صورت مسئله.
بهترین مثالی که برای حذف صورت مسئله میشه زد، اینه که فرض کنین پنجره‌ی خونه‌تون بازه و یه بویی میاد از بیرون و شمارو اذیت میکنه. شما هر ۲ ساعت یه بار باید یه قرص سردرد بخورید که به زندگی عادی تون برسید. در صورتی که کار درست اینه که اون پنجره‌ی لعنتی رو ببندید:)))

راه حل دولوپر ها در مواجهه با این نوع استرس ها، یه چیزی هست که توی اصطلاحات Gaming بهش میگن zerging. توی دنیای بازی، وقتی شما تمام تمرکزتون رو میزارین که به حریف ضربه بزنین یا ریسورس بدست بیارید بدون اینکه خودتون رو Heal کنین، اصطلاحاً دارین zerging انجام میدید. خیلی از دولوپر ها وقتی یه چالش خیلی سخت با تایم‌لاین کوتاه میخورن، تلاش میکنن هرچه سریع تر اونو انجام بدن تا فقط تموم شه. فکر میکنن وقتی تموم شه استرس و مشکلشون تموم میشه. ولی همه‌مون میدونیم وقتی موفق بشه چه اتفاقی میوفته. (شاید) آقا یا خانوم رئیس بهش یه آفرین بگه، بعدش یه کار سخت تر بهش میده چون تونسته خودشو ثابت کنه!
یه سری دیگه از دولوپر ها میان با کاری دیگه Procrastinate میکنن. مثلاً به جای اینکه به اون تسک سخت برسن، میرن کد ریویو انجام میدن، کارای جزئی با اهمیت پایین تر رو انجام میدن. خود من این کارو زیاد کردم متاسفانه.
یه سری دیگه هم خب رو میان به دراگ و های شدن و اینا:))))

ولی خب اینا راه حل های خوبی نیست. اینا به ما ضربه میزنه، شوق زندگی رو رسماً ازمون میگیره. باعث میشه دائماً از خودمون و زندگی‌مون بدمون بیاد. و کل هدف زندگی که اینه یکم خوش بگذرونیم بخندیم رو میبره زیر سوال از نظر من. پس چیکار کنیم؟
👍2
توی قدم اول باید خودمون رو بشناسیم. این چنلی که فرستادم پر از مطالب خودشناسی عه، دنبالش کنین، به جای doom scrolling یا خوندن کتاب های زرد، کتاب های خودشناسی خوب بخونین (خیلی دوس دارم معرفی کنم، ولی متاسفانه خودمم زیاد نمیشناسم).
اگر خودمون رو بشناسیم، میتونیم بفهمیم کی دقیقاً دچار استرس میشیم. خیلیییی هاتون فکر میکنین میدونین کی استرس میگیرین، یا حتی فکر میکنین از قبل از Burn out شدن میتونین جلوشو بگیرین یا حداقل پیش بینیش کنین. و اکثرتون اشتباه میکنین.
اگر خودمون بهتر بشناسیم، میفهمیم استرس گرفتیم میفهمیم فشار کاری‌مون داره جمع میشه و باعث میشه از خودمون غافل بشیم. اینطور میتونیم جلوی Zerging رو بگیریم. اینطور میتونیم وقت بیشتری برای سلامت روان‌مون بزاریم. ایگنور نکنین، سعی نکنین با چسب زخم همه‌ی دردهاتون رو بپوشونین، برای خودتون وقت بزارین.

یه راه دیگه که توی این ویدیو بهش اشاره شد و منم تجربه‌ش کردم، حرف زدنه. خیلی اوقات توی محیط کاری مخصوصاً وقتایی که کمی محیط گرم و صمیمی میشه، حرف نزدن بین افراد ضربه میزنه. ماها باید یاد بگیریم انتقاد پذیر باشیم و به درستی و بدون بی احترامی انتقاد کنیم. صحبت کنیم و نزاریم چیزی توی دلمون بمونه. اگر توی اسپرینت قبل اتفاقی افتاده که خیلی رفته روی مخ ما و بهمون استرس داده، باید بیانش کنیم. تا وقتی امتحانش نکنین، نمیدونین چقدر تاثیر داره.

امیدوارم مفید باشه براتون. پیشنهاد میکنم این ویدیو و چنل‌شو حتماً یه نگاهی بندازین. ضرر نمیکنین.

Links:
- https://www.youtube.com/@HealthyGamerGG

👾 @geekingaround
👍1
به تیکه کد زیر توجه کنین:

type Charge = {
mobile: string;
amount: number;
type: "direct" | "special";
};

type Internet = {
mobile: string;
product_id: number;
};

function fn(input: Charge | Internet) {
// ...
}


فرض کنید این کد مربوط به اطلاعات بسته‌ی اینترنتی و بسته‌ی شارژ تلفن همراه عه و این فانکشن fn یه جایی از اَپی هست که مینویسید.
مثلاً میتونه کال‌بک خرید توی یه پروژه‌ی سمت سرور باشه یا اینکه یه کامپوننت سمت فرانت باشه که میخواد یه چیزی رندر کنه. در هر صورت، تایپ ورودی این فاکشن میتونه هم بسته‌ی اینترنتی باشه هم شارژ باشه.

همونطور که بهتر از من میدونین، تایپ های Typenoscript فقط تا موقع transpile با ما هستن و موقع run-time نداریمشون.
برای مثال اصلاً یه همچین امکانی نداریم ما:
typeof input === Charge


توی بدنه‌ی فانشکن، Typenoscript فقط به شما میگه من مطمئنم روی input مقدار input.mobile‍ وجود داره (چون این property توی جفت تایپ ها مشترک هست). ولی دیگه بقیه‌شو نمیدونه. مطمئن نیست موقع run-time، وقتی که کد ما داره ران میشه، پارامتر ورودی از کدوم تایپ هست. پس نمیتونه کمک خاصی به ما بکنه.
پس باید چه کنیم؟ اینبار ما باید به Typenoscript کمک کنیم!

یک راهی که شاید تا الان دیده باشید اینه:
function fn(input: Charge | Internet) {
if ((input as any).product_id) {
const internet = input as Internet;
internet.product_id
// ...
}
}

به زبان ساده اولش به Typenoscript میگم یه دیقه بیخیال تایپ بشو (as any) بعدش میگم اگر property ای به اسم product_id بود داخلش، ینی از نوع Internet هست (as Internet).

ولی خب یه روش بهتر و تمیز تر از این وجود داره که بهش میگن
User defined type guards

اگر بخوایم اینجا از تایپ‌گارد استفاده کنیم این شکلی میشه:
function isInternet(x: unknown): x is Internet {
return (
typeof x === "object" &&
x !== null &&
"product_id" in x &&
typeof x.product_id === "number"
);
}

function fn(input: Charge | Internet) {
if (isInternet(input)) {
input.product_id;
// ...
}
}

توی فانکشن isInternet داریم میگیم تایپ پارامتر ورودی unknown هست (میتونه هر چیزی دیگه‌ای باشه) ولی اگر این فانکشن true برگردونه، به Typenoscript میفهمونیم تایپش از نوع Internet عه (x is Internet).

حالا هم Typenoscript میفهمه و میتونه کمک‌مون کنه (توی بدنه‌ی بلاک if میتونه بهمون intellisense بده) هم اینکه توی run-time کد ما Type safe هست و ناخواسته ارور null pointer معروف Javanoscript رو نمیخوریم:
Can not read the property of undefined

میخوای بیشتر یاد بگیری و عمیق تر بشی؟
بشین Official Documentation تایپ‌اسکریپت رو بخون.

https://www.typenoscriptlang.org/docs/handbook/2/narrowing.html

این قسمت از Doc خیلی مفصل تر و کلی تر از مطلبی که من نوشتم، راجب Type narrowing هست.
پیشنهاد میکنم وقت بزارید، مطالعه کنید و بلافاصله برید بر اساس چیزی که یاد گرفتین تمرین کنین و کد بزنین.

👾 @geekingaround
👍21
توی تایپ‌اسکریپت، وقتایی که با اروری که بهتون میده زیاد موافقش نیستین یا فقط میخواین خفه بشه:))) میتونین خط قبل از اونجایی که خطا میده، از یه سری directive خاص استفاده کنیم.
مثل این دوستمون:

// @ts-ignore


به طور کلی استفاده ازش (توی محیط production) یکم عجیبه و پیشنهادش نمیکنم.
ما باید به جای جنگیدن با ارور های تایپ‌اسکریپت، سعی کنیم کد Type safe بنویسیم. نه اینکه به تایپ‌اسکریپت بگیم داداش، من خودم میدونم این درسته، بیخیال خط بعدی شو و ارور نده.

برای مثال به جای اینکه این کارو بکنیم:
const activityPoints = {
like: 5,
comment: 10,
share: 15,
};

function fn(activity: string) {
// @ts-ignore
const points = activityPoints[activity];
}


بهتره بیایم کد Type safe بنویسیم:
const activityPoints = {
like: 5,
comment: 10,
share: 15,
};

function fn(activity: keyof typeof activityPoints) {
const points = activityPoints[activity];
}


اینطوری کدمون ترتمیز و خوانا تر هست.
و از همه مهم تر، امن تره! توی کد قبلی شما میتونستین هر string ای به فاکنشکن‌تون بدید، یه موقع هایی مقداری میدادید که توی اون آبجکت وجود نداره و نهایتاً مقدار points میشه undefined. ولی توی حالت دوم، فانکشن ما فقط string هایی قبول میکنه که به عنوان کلید توی آبجکت مدنظرمون وجود داشته باشن.
این باعث میشه ما کار بیشتری انجام بدیم، قبل از کال کردن فانکشن‌مون باید مطمئن بشیم کلیدمون توی آبجکت وجود داشته باشه (میتونیم از اپراتور in استفاده کنیم. و کلی تکنیک type narrowing که توی پست های قبل اشاره کردم بهش).
اما نهایتاً این کار باعث میشه باگ خیلی کمتری ایجاد کنیم و کد امن تر و Type safe تری بنویسیم.

شاید تنها کاربرد خوب این نوع directive ها موقع ری‌فکتور های بزرگ باشه. برای مثال موقع انتقال یه کدبیس از JS به TS، یا تغییر framework یه سرویس.
توی این موارد اگر از همون اول بخوایم همه‌جاشو Type safe کنیم حقیقتاً خیلی اذیت میشیم. باید آروم آروم پیش بریم.
و خب میدونیم و مطمئن هستیم کدمون کار میکنه، پس اینجور موقع ها (حین ری‌فکتور) اشکال نداره ازش استفاده کنیم. تا کارمون پیش بره و بعد از اینکه کامل انتقال انجام شد و کدمون Type safe شد، پاکشون کنیم.

اما اینجا هم پیشنهاد میدم به جای ts-ignore از این یکی directive استفاده کنین:
// @ts-expect-error


این یکی به تایپ‌اسکریپت میگه یه اروری خط بعد هست، ولی تو بیخیالش شو. تفاوتش با ts-ignore اینه که اگر خط بعدیش اروری وجود نداشته باشه، تایپ‌اسکریپت به خود وجود این directive گیر میده و میگه اروری اصلاً وجود نداره که من بخوام بیخیالش بشم.

خوبیش اینه که اگر شما حین ری‌فکتور کردنتون اون ارور رو برطرف کرده باشید، اونجا تایپ اسکریپت بهتون میگه خط بعدی اصلاً اروری وجود نداره و مجبورتون میکنه اون directive رو پاک کنین.
در مقابلش اگر از ts-ignore استفاده میکردید این اتفاق نمیوفتاد. چون ts-ignore به تایپ‌اسکریپت میگه کلاً بیخیال خط بعد شو و اصلاً چکش نکن. تایپ‌اسکریپت هم کاری نداره که اصلاً خط بعد اروری وجود داره یا نداره. کلاً بیخیال خط بعدی میشه.

👾 @geekingaround
4
امیدوارم برای هیچ‌کدوم‌تون اتفاق بدی نیوفته...❤️
مراقب خودتون و خانواده‌تون باشید❤️
4
سلام بچه ها، امیدوارم حالتون خوب و تنتون سلامت باشه.🤍
یکم محتوا درست کردن توی قالب تلگرام داره سخت میشه. هی فارسی و انگلیسی داره قاطی میشه، توی گوشی بعضی اوقات تیکه کد ها خوب نمیوفته و خوانایی خوبی نداره.
سر همین دارم چیزای مختلف رو امتحان میکنم ببینم چی بهتر جواب میده.
یه مدت از @telegraph استفاده کنیم ببینیم چطور جواب میده. اگر فیدبکی داشتین خوشحال میشم بهم بگید. 🤝
👍2
چرا
bun install
خیلی خیلی سریع تر از سایر پکیج منجر های اکوسیستم JS هست؟ (۱۷ برابر سریع تر از yarn هست!)

https://bun.com/blog/behind-the-scenes-of-bun-install

با خوندنش به عملکرد کلی پکیج منجر ها هم یه دید خوبی پیدا میکنین، متن خیلی خوب و روونی داره.

👾@geekingaround
👍1
متد Array.prototype.reduce یکم فهمش برای کسایی که تازه شروع میکنن سخته. به تجربه‌ی من بهترین کار برای فهم یه چیزی امتحان کردن و کار کردن باهاش هست. ولی به طور کلی میتونین reduce رو معادل یه for of در نظر بگیرید

const val = array.reduce((acc, cur) => update(acc, cur), initialValue);

// Is equivalent to:
let val = initialValue;
for (const cur of array) {
val = update(val, cur);
}


نکته‌ی قابل توجه این هست که reduce برای اهداف Functional programming paradigm توی JS اضافه شده. و برای کار با immutable data باید استفاده بشه. ولی یه موقع هایی ما به این نکته توجه نمیکنیم.

بیاین تصور کنیم یک لیست از یک سری اسم داریم و میخوایم تعداد تکرارشونو بشماریم.

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];


اگر به ذهن‌مون برسه از reduce استفاده کنیم، به طور کلی دو تا راه داریم.

توی یک حالت هر سری ریزالت‌مونو به عنوان یک آبجکت بسازیم و به iteration بعدی بدیمش.
const countedNames = names.reduce((allNames, name) => {
const currCount = Object.hasOwn(allNames, name) ? allNames[name] : 0;
return {
...allNames,
[name]: currCount + 1,
};
}, {});

که این حالت خیلی ممکنه توی performance اپ ما تاثیر داشته باشه. هر سری ما داریم کل آبجک رو کپی میکنیم و یک آبجکت جدید میسازیم که میتونه توی بدترین حالت روی O(n^2) ران بشه! (n تعداد المنت های توی لیست‌مون هست)
به این مقاله یه سر بزنین تا ببینین چقدر تاثیر زیادی میتونه داشته باشه توجه به همین نکته‌ی ساده!

یک راه دیگه اینه که مستقیم با property های آبجکتی که روی هر iteration داره ران میشه کار کنیم.
const countedNames = names.reduce((allNames, name) => {
const currCount = allNames[name] ?? 0;
allNames[name] = currCount + 1;
return allNames;
}, Object.create(null));

مشکل این حالت چیه؟ ما داریم رسماً دیتا رو mutate میکنیم. ینی اصول Functional programming رو رعایت نکردیم و داریم تلاش میکنیم حتماً از reduce استفاده کنیم. قیمه هارو داریم میریزیم تو ماستا:))
بهتره اصلاً تبدیلش کنیم به یه for of لوپ ساده، هم خوانا تره، هم قیمه هارو نمیریزیم توی ماستا

const names = ["Alice", "Bob", "Tiff", "Bruce", "Alice"];
const countedNames = Object.create(null);
for (const name of names) {
const currCount = countedNames[name] ?? 0;
countedNames[name] = currCount + 1;
}


منبع

👾@geekingaround
1🔥1
میدونستین ۵۳ درصد از کاربران موبایل، وب‌سایت هایی که بیشتر از ۳ ثانیه لودشون طول بکشه رو ترک میکنن؟
خب چیکار کنیم لود اولیه وب‌سایت‌مون سریع باشه و حتی یوزر هایی که از نت 2G استفاده میکنن بتونن تجربه‌ی خوبی داشته باشن؟ حجم فایل های وب‌سایت‌مون رو زیر 14kB نگه داریم!
چرا؟ مقاله‌ی زیر رو بخونین تا متوجه بشین.

https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/

دید خیلی خوبی از اینکه TCP چطور کار میکنه بهتون میده. حتماً پیشنهاد میکنم بخونینش.

پ.ن: زیاد چیز عجیب غریبی نیست که با کوچیک تر شدن حجم فایل ها، سرعتِ لود شدن وب‌سایت میره بالا:))
و شاید بگین که یه همچین چیزی توی نیازمندی هایی که باهاش طرفیم نمیگنجه! درست میگین ولی نیازی نیست کلِ کلِ وب‌سایتی که مینویسیم نهایتش زیر 14kB حجم داشته باشه. نکته‌ی مهم این هست که باید حواسمون به Initial loading وب‌سایت‌مون و فایل هایی که توی ریسپانس اولیه میفرستیم سمت کلاینت باشه و سعی کنیم زیر این حد 14kB نگهش داریم. حالا بعد از لود اولیه بریم ریکوئست بزنیم Asset های مختلفی که بهشون نیاز داریم رو از سرور بگیریم.
نه اینکه همون اول کار کلِ باندل JS رو سمت یوزر بفرستیم.

👾@geekingaround
👍5❤‍🔥2🔥1
چند وقت پیش یه باگی رو روی یکی از سیستم هامون پیدا کردیم.
ما اندپویتی داشتیم که یک سرویس خارجی اونو کال میکرد. وقتی با همچین payloadای کال میشدیم، به مشکل میخوردیم.

{
"RefId": 15231529159309216
}


مشکلی که وجود داشت، توی API Schema validation مون یه همچین خطایی داشتیم:
"Value for 'RefId' must be a safe number"
لازم به ذکره حتی اگر ولیدیشن این فیلد بخصوص رو ایگنور میکردیم هم بازم توی ادامه‌ی مراحل به مشکل میخوردیم.

قبل از اینکه برم سراغ راه حل و چیزایی که براش خوندم، بریم یکم راجب خود این مشکل Max Safe Integer و BigInt توی Javanoscript صحبت کنیم.

همونطور که میدونین، تایپ number توی JS به صورت یک primitive تعریف میشه که هم برای integer ها و هم برای floating point number ها استفاده میشه.
در واقع پیاده‌سازی number ها بر اساس Double-precision floating-point format هستش که ۶۴ بیت به هر number اختصاص میده ولی به این صورت تقسیم‌شون میکنه

Sign bit: 1 bit
Exponent: 11 bits
Significand precision: 53 bits (52 explicitly stored)

این یعنی بزرگ‌ترین عددی که میشه به صورت safe ذخیره کرد، این هست:

Number.MAX_SAFE_INTEGER; // 9007199254740991


حالا اگر بخوایم با عدد هایی بزرگ تر از این (یا اعداد کوچیک تر از Number.MIN_SAFE_INTEGER) سرکار داشته باشیم چی؟ مثلاً توی موردی که خود من بهش برخوردم، با یه API خارجی سر و کار داریم که مثلاً با Python یا Java نوشته شده و خیلی راحت میتونه با عداد ۶۴ بیتی کار کنه.
یا مثلاً میخوایم از distributed ID generation مثل Snowflake استفاده کنیم که معمولاً نیاز به اعداد ۶۴ بیتی دارن.

برای اینجور کار ها یه primitive دیگه اضافه شد به JS به اسم bigint

const bigNumber = BigInt("15231529159309216");


اگر میخواین راجب خود bigint بخونین و ببینین چه تفاوت های (مخصوصاً توی operator ها) با number معمولی داره، حتماً داکیومنتش توی MDN رو چک کنین.

ولی داستانی که وجود داره، هنوز خوب اصطلاحاً integrate نشده.
اگر از Joi برای Schema validation استفاده کنین، به صورت Builtin چیزی برای BigInt نداره
موقع کار کردن با Mongoose به یه سری مشکل خوردم باهاش، یه جاهایی مجبور بودم BigInt رو دستی تبدیل کنم به یه سری class wrapper هایی که توی bson وجود داشتن
و از همه مهم تر، موقع کار کردن با JSON بسیار داستان وجود داره!
👍1
برگردیم به داستانی که اول تعریف کردم

{
"RefId": 15231529159309216
}


شاید در نگاه اول فکر بکنین وقتی اندپویت شما با این دیتا کال میشه،‌ میتونین اینطوری هندلش کنین:

const body = JSON.parse(req.body); // This usually is done by something like "body-parser" package
body.RefId = BigInt(body.RefId);


وقتی وقتی JSON.parse‍ توی JSON یک عدد میبینه، اونو تبدیل میکنه به number این یعنی ما همین الانش مقدار زیادی از precision مون رو از دست دادیم و تبدیل number به BigInt در اینجا بی معنی میشه.

یک راه اینه که تایپ ورودی اندپوینت رو عوض کنیم و از فرستنده‌ی دیتا بیخوایم به صورت string بفرسته دیتا رو. اینطوری موقع parse کردن دیتای از دست نمیره و راحت میتونیم بدون از دست دادن precision یک string رو تبدیل به bigint کنیم.

توی مورد من این امکان نبود. پس بیشتر تحقیق کردم و خوندم. و به یک proposal توی tc39 رسیدم!
https://github.com/tc39/proposal-json-parse-with-source

جالبه که همین چند روز پیش به استیج ۴ رسید. خیلی خلاصه و جمع و جور بخوام بگم، موقع parse کردن JSON با متد JSON.parse به عنوان آرگیومنت دوم یه Callback function قبول میکنه به اسم reviver که میتونین راجبش بخونین که کارش چیه.
توی این پروپوزال تعریف کردن یک پارامتر سومی به اسم context بهش اضافه بشه که یک آبجکی هست که خودش یک property به اسم source داشته باشه. در صورتی که موقع parse کردن، دیتایی که بهش برخوردن جز primitive ها باشه، مقدار context.source رو با اصل اون دیتا پر کنن (که توی JS به صورت string قابل استفاده میشه).
اینطوری خیلی راحت و بدون دردسر میتونیم همچین حرکتی بزنیم:

const body =
JSON.parse(req.body, (key, value, context) => {
if (key === "RefId") {
return BigInt(context.source);
}
return value;
});


همین چند روز پیش به استیج ۴ رسیده به خاطر همین آخرین باری که من چک کردم هنوز تایپ هاش اوکی نشدن توی Typenoscript. ولی implmenationش توی NodeJS و اکثر Browser ها انجام شده.

برای برعکس این قضیه یعنی stringify کردن و response دادن به یک API با BigInt هم داستان های خاص خودشو داره. میتونین اینجا بیشتر مطالعه کنین راجبش.

👾 @geekingaround
👌6🔥2👍1👏1