Melfex 𓏺 فرشاد عسکری
64 subscribers
16 photos
3 files
19 links
SOON

• YouTube : youtube.com/@EduFarshad
• GitHub : github.com/Melfex
• Twitter / X : Twitter.com/@ItFrshd
• Insta : Instagram.com/askari_farshad

📧 Contact me : @FarshadXD
Download Telegram
اگه تا حالا واسه یه API مکانیزم Retry نوشتید، احتمالا اولین چیزی که به ذهنتون رسیده این بوده که «اگه ریکوئست Fail شد، دوباره همون لحظه ارسالش کنم»

مشکل از همین‌جا شروع می‌شه. فرض کنید یه سرویس به خاطر فشار زیاد، موقتا از دسترس خارج شده. اگه هزاران کلاینت دقیقا همون لحظه دوباره Retry کنن، فشار بیشتری به همون سرویس وارد می‌کنن و عملا زمان بازیابیش طولانی‌تر می‌شه.

راه‌حل؟! مفهومی به اسم Exponential Backoff. به جای اینکه بعد از هر ارور فورا ریکوئست رو تکرار کنید، هر بار مدت بیشتری صبر می‌کنید؛ مثلا ۱ ثانیه، بعد ۲ ثانیه، بعد ۴ ثانیه، بعد ۸ ثانیه و..

اما هنوز یه مشکل باقی می‌مونه؛ اگه همه‌ی کلاینت‌ها دقیقاً با همین الگو Retry کنن، باز هم همزمان به سرور اتک می‌زنن.

اینجاست که مفهوم Jitter وارد بازی می‌شه. به هر Retry یه مقدار تأخیر رندوم اضافه می‌کنه تا ریکوئست‌‌ها بین کلاینت‌ها پخش بشن و همزمان به سرور نرسن.


⌨• #DevEdu@Melfex
❤2👍2
اگه برای تست پروژه‌هاتون تا حالا مجبور شدید یه PostgreSQL، Redis یا RabbitMQ روی سیستم نصب کنید، احتمالا با این سناریو هم آشنا هستید: «روی سیستم من کار می‌کنه». یکی از دلایل اصلی این اتفاق، تفاوت محیط توسعه با محیطیه که تست‌ها داخلش اجرا می‌شن.

وقتشه با Testcontainers آشنا بشید. Testcontainers یه ماژول و کتابخونه اوپن‌سورسه که بهتون اجازه می‌ده موقع اجرای تست‌ها، سرویس‌های واقعی مثل PostgreSQL، Redis، RabbitMQ، Kafka و ده‌ها سرویس دیگه رو داخل داکر بالا بیارید؛ اون هم به‌صورت کاملا خودکار و موقت.

• تست روی سرویس واقعی: به جای ماک کردن دیتابیس یا Redis، تست‌هاتون مستقیما روی همون سرویسی اجرا می‌شن که قراره توی پروداکشن ازش استفاده کنید.

• ایزوله و قابل تکرار: هر بار اجرای تست، کانتینرهای جدید ساخته می‌شن و بعد از اتمام تست‌ها هم حذف می‌شن. در نتیجه هیچ دیتای باقی‌مونده یا تنظیمات قبلی روی نتیجه تست تأثیر نمی‌ذاره.

• سازگار با CI/CD: چون همه‌چیز خودکار بالا میاد، اجرای تست‌ها روی گیت‌هاب Actions یا هر سیستم CI دیگه‌ای هم دقیقا مثل سیستم توسعه‌دهنده هست.

📦 github.com/testcontainers


⌨• #DevEdu@Melfex
🔥3
چهار هزار هفته.pdf
24.2 MB
احتمالا اسم این کتاب رو بارها شنیدید؛ اما با توجه به چیزهایی که تا امروز درباره‌ش شنیده بودم، به نظرم چیزی که باعث شده این‌قدر ماندگار بشه، فقط محبوبیتش نیست، بلکه نگاه متفاوتش به مفهوم «زمان» و «زندگی» هست. برخلاف خیلی از کتاب‌های توسعه فردی که مدام از بهره‌وری بیشتر، مدیریت زمان و انجام دادن کارهای بیشتر حرف می‌زنن، این کتاب از یه زاویه کاملا متفاوت به موضوع نگاه می‌کنه.

طبق روال معمول، می‌تونید کوت و پاراگراف‌هایی که از نظر من ارزش بیشتری دارن رو با هشتگ #چهار_هزار_هفته دنبال کنید.

در آخر، اگه امکانش براتون فراهمه، نسخه اصلی و قانونی کتاب رو تهیه کنید. من هم نسخه قانونی کتاب رو خریدم.


📚• #FReading@Melfex | #چهار_هزار_هفته
❤‍🔥3🤔1
این احساس که باید از زمان محدود خود نهایت استفاده را کنیم، ریشه در این ایده دارد که زمان چیزی است که باید از آن استفاده کنیم.
بهتر است کاری انجام دهیم که ارزش انجام دادن داشته باشد و اجازه دهیم به پایان برسد، تا اینکه مدام درگیرِ جبرانِ کمبودهای زندگی و مدیریتِ بی‌پایانِ کارها باشیم.



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

شاید مسئله، مدیریت بهتر زمان نباشه؛ بلکه پذیرفتن این واقعیته که زمان ما محدوده و دقیقا به همین خاطر، هر «آره» گفتن، یعنی به چیز دیگه‌ای «نه» گفتن.

به نظرم آرامش، از انجام دادنِ کارهای بیشتر نمیاد؛ از انتخاب کردنِ کارهای مهم‌تر میاد.


📚• #FReading@Melfex | #چهار_هزار_هفته
❤2👏1
اگه با داکر کار می‌کنید، احتمالا با این سناریو آشنا هستین که: واسه‌ دیدن وضعیت کانتینرها، بررسی لاگ‌ها یا اجرای یه کامند ساده، مدام بین کامندها جابه‌جا می‌شین.

از طرفی ابزارهای گرافیکی مدیریت داکر همیشه برای هر سناریویی مناسب نیستن؛ مخصوصا وقتی روی سرورهای ریموت یا محیط‌های کم‌منبع کار می‌کنید و دنبال یک راه‌حل سریع و سبک هستید.


اینجاست که Lazydocker می‌تونه تجربه‌ی کار با داکر رو راحت‌تر کنه. لیزی‌داکر یه ابزار TUI هست که با گولنگ نوشته شده و محیط داکر و داکر Compose شما رو مستقیما داخل ترمینال به یه داشبورد تعاملی تبدیل می‌کنه.

• مدیریت در یک محیط واحد؛ می‌تونید وضعیت کانتینرها، ایمیج‌ها، والیوم‌ها و سرویس‌های داکر Compose رو بدون نیاز به اجرای چندین کامند مختلف مشاهده و مدیریت کنید.

• لاگ و Shell سریع؛ با چند حرکت ساده می‌تونید لاگ‌های لایو کانتینرها رو ببینید، وارد شل یک کانتینر بشید و کارتون رو انجام بدین.

• نمایش مصرف منابع؛ امکان مشاهده‌ی مصرف CPU و RAM کانتینرها به‌صورت گرافیکی داخل ترمینال وجود داره.


📦 github.com/jesseduffield/lazydocker


⌨• #DevEdu@Melfex
👍2❤‍🔥1🔥1🥰1
مشکل ما با زمان، کمبود آن نیست؛ مشکل این است که باور داریم باید از پسِ همه‌ی کارها بربیاییم. بهره‌وریِ مدرن به ما یاد داده که "فقط یک ترفندِ دیگر" می‌تواند همه‌چیز را درست کند؛ اما حقیقت این است که هرچه سریع‌تر پیش می‌رویم، فهرستِ کارهایی که "باید انجام بدهیم" بلندتر می‌شود. تا زمانی که نپذیریم محدودیت، بخشی جدایی‌ناپذیر از زندگی است، این احساسِ "عقب ماندن" هیچ‌وقت رهایمان نمی‌کند


شاید بزرگ‌ترین فریب دنیای امروز این باشه که ارزش ما رو با میزان بهره‌وریمون گره زده. انگار هرچی کارهای بیشتری انجام بدیم، آدم موفق‌تر و خوشحال‌تری هستیم؛ اما واقعیت اینه که فهرست کارها هیچ‌وقت تموم نمی‌شن.

به‌نظرم نقطه‌ی رهایی، پیدا کردن یه ترفند جدید واسه مدیریت زمان نیست؛ بلکه پذیرفتن این واقعیته که قرار نیست همه‌چیز رو انجام بدیم. وقتی این محدودیت رو بپذیریم، دیگه مدام خودمون رو با یه لیست بی‌انتها قضاوت نمی‌کنیم و می‌تونیم انرژیمون رو روی همون چندتا کاری بذاریم که واقعا واسمون اهمیت دارن.


📚• #FReading@Melfex | #چهار_هزار_هفته
❤3🔥1💘11
اگه از دیدن TUIهایی مثل Lazydocker لذت بردید، ولی فکر می‌کردید ساختن همچین اپ‌هایی فقط با گولنگ یا راست ممکنه، وقتشه نظرتون عوض بشه.


یه فریم‌ورک پایتونی به نام Textual هست که بهتون اجازه می‌ده اپلیکیشن‌های ترمینالی کاملا تعاملی، با انیمیشن روان، پشتیبانی از موس و حتی ۱۶.۷ میلیون رنگ بسازید؛ اون هم با پایتون.

• استایل‌دهی مثل وب؛ Textual یه سیستم CSS داره که می‌تونید باهاش Layout، رنگ، Border و حتی حالت‌های مختلف Widgetها رو کنترل کنید؛ بدون اینکه استایل رو با لاجیک پایتون قاطی کنید.

• ویژگی‌های Reactive؛ کافیه یه متغیر رو reactive تعریف کنید تا با تغییر مقدارش، Textual به‌صورت خودکار UI رو رفرش کنه؛ الگویی که برای توسعه‌دهنده‌های فرانت‌اند خیلی آشناست.

• ترمینال یا مرورگر؛ جالب‌ترین بخشش اینه که می‌تونید همون اپلیکیشن رو داخل ترمینال اجرا کنید یا با textual serve توی مرورگر در دسترس قرار بدید.

اگه دوست دارید چیزی فراتر از print و لاگ‌های ساده توی ترمینال بسازید، Textual می‌تونه یکی از جذاب‌ترین گزینه‌های اکوسیستم پایتون برای ساخت TUI باشه.

🐱 github.com/Textualize/textual


🔨• #DevEdu@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
422
یکی از رایج‌ترین اشتباهاتی که توی کدهای async می‌بینم رو امروز می‌خوام باهم مرور کنیم؛ لوپ زدن روی یه لیست و await کردن هر آیتم به‌صورت جداگانه.

❗️ قبل:
async def notify_users(user_ids: list[int]):
for user_id in user_ids:
await bot.send_message(
user_id,
"بروزرسانی جدید منتشر شد!"
)

این کد از نظر سینتکس هیچ ایرادی نداره؛ اما پراسس‌/عملیات‌ها عملا سریالی اجرا می‌شن. چون هر coroutine رو قبل از رفتن سراغ کاربر بعدی await می‌کنیم، iteration بعدی تا تموم شدن عملیات قبلی شروع نمی‌شه. واسه‌ی ۱۰۰۰ یوزر یعنی ۱۰۰۰ ریکوئست شبکه که یکی‌یکی منتظر هم می‌مونن.


💡 اولین راه‌حلی که معمولا به ذهن می‌رسه:
async def notify_users(user_ids: list[int]):
await asyncio.gather(*[
bot.send_message(
uid,
"بروزرسانی جدید منتشر شد!"
)
for uid in user_ids
])

سریع‌تره، ولی حالا مشکل برعکس شده؛ همه‌ی ریکوئست‌ها بدون هیچ محدودیتی شلیک می‌شن. یادتونه توی پست آنتی‌اسپم درباره‌ی FloodWait تلگرام صحبت کردیم؟ این‌جا خود بات می‌تونه تبدیل بشه به همون چیزی که ازش فرار می‌کردیم. 😂


💡 راه‌حل بعدی، محدود کردن تعداد پراسس هم‌زمانه:
sem = asyncio.Semaphore(20)

async def send_one(uid: int):
async with sem:
await bot.send_message(uid, "بروزرسانی جدید منتشر شد!")

اما این‌جا یه تفاوت مهم وجود داره:
Concurrency Limit ≠ Rate Limit

توی این حالت، Semaphore(20) فقط می‌گه حداکثر ۲۰ عملیات هم‌زمان داشته باش؛ نمی‌گه در هر ثانیه حداکثر چند ریکوئست ارسال کنی. مثلا اگه ریکوئست‌ها خیلی سریع تموم بشن، به محض آزاد شدن هر slot، عملیات بعدی می‌تونه شروع بشه و توی یه بازه‌ی کوتاه تعداد زیادی ریکوئست ارسال بشه.


اینجا بود که توی broadcaster.py پروژه‌ی Telegram-MSG-Bridge خودم، به‌جای Semaphore از یه مدل ساده‌تر برای Broadcast استفاده کردم:
for start in range(0, len(recipients), self._per_second):
batch = recipients[
start : start + self._per_second
]

outcomes = await asyncio.gather(
*(
self._send_one(
uid,
from_chat_id,
message_id
)
for uid in batch
)
)

sent += sum(outcomes)

if start + self._per_second < len(recipients):
await asyncio.sleep(1.0)

اینجا یوزرها batch به batch پردازش می‌شن؛ مثلا ۲۰ تا هم‌زمان ارسال می‌شن، منتظر می‌مونیم کل batch تموم بشه، یک ثانیه صبر می‌کنیم و بعد می‌ریم سراغ batch بعدی.

این روش هم مثل Rate Limiterهای واقعی دقیق نیست؛ چون زمان هر batch به کندترین ریکوئست همون batch بستگی داره. اما واسه‌ی یه broadcaster ساده، در عوض پیاده‌سازی خیلی راحت‌تری داره و رفتار نرخ ارسال رو قابل پیش‌بینی‌تر می‌کنه.


یه بخش دیگه‌ی این کد هم به نظرم مهم‌تر از خود batching هست:
except TelegramRetryAfter as error:
await asyncio.sleep(error.retry_after)

try:
await self._bot.copy_message(...)
return True
except TelegramAPIError:
return False

اینجا دیگه لازم نیست حدس بزنیم چقدر باید صبر کنیم؛ خود Telegram API مقدار retry_after رو برمی‌گردونه و ما دقیقا به همون اندازه صبر می‌کنیم. البته این کد عمدا فقط یه بار retry می‌کنه. اگه ریکوئست دوم هم دوباره با ارور API مواجه بشه، اون کاربر failed حساب می‌شه؛ چون واسه‌ی یه broadcaster ساده، جلوگیری از retry-loop بی‌نهایت مهم‌تر از تلاش نامحدود واسه‌ی یه پیام خاصه.


و شاید مهم‌ترین چیزی که از این مثال می‌شه برداشت کرد اینه:
ایسینک بودن به‌تنهایی یعنی کانکارنسی؛ نه لزوماً Rate Limiting.



👨‍💻• #CodeSmell@Melfexzq
221
یکی از خطرناک‌ترین حس‌ها توی مسیر یادگیری برنامه‌نویسی، حسیه که شاید کمتر درباره‌ش حرف زده می‌شه: توهمِ فهمیدن.

یه مفهوم جدید یاد می‌گیرید؛ یه مقاله می‌خونید، یه ویدیو می‌بینید یا کد یه نفر دیگه رو بررسی می‌کنید. همه‌چیز منطقی به نظر می‌رسه. هر خط رو متوجه می‌شید و در آخر با خودتون می‌گید: «آها، فهمیدم.»

اما مشکل اینجاست که مغز ما بین «آشنا بودن» و «بلد بودن» تفاوت زیادی قائل نمی‌شه. وقتی چیزی رو دوباره می‌بینه، سریع حس آشنایی ایجاد می‌کنه و همین حس گاهی با یادگیری واقعی اشتباه گرفته می‌شه.

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

به نظرم یکی از بهترین روش‌ها برای سنجیدن یادگیری، همین لحظه‌ست: منبع رو ببندید و تلاش کنید چیزی که یاد گرفتید رو بدون کمک دوباره بسازید. نه برای اینکه خودتون رو امتحان کنید، بلکه برای اینکه بفهمید دقیقا کجای مسیر هستید.

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

پس دفعه‌ی بعد که حس کردید یک مفهوم رو کامل یاد گرفتید، اول از همه بسنجید این حس رو.


👤• #FromFarshad@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
1311
AliiReza 13
مگه هدف async این نیست که وقتی کروتین اجرا میشه تا وقتی جوابش نرسیده برنامه منتظرش نمی‌مونه و می‌ره سراغ پروسه بعدی؟ پس چرا اینجا میگی ارسال پیام بعدی باید برای ارسال پیام قبلی صبر کنه؟
نکته همینه: async به‌تنهایی باعث concurrent شدن همه‌ی عملیات/پراسس نمی‌شه. توی asyncio باید چند کار واقعا برای اجرا به Event loop سپرده شده باشن تا وقتی یکی منتظر I/O می‌مونه، ایونت لوپ بتونه سراغ کار دیگه‌ای بره.

این کد رو ببینید:
for user_id in user_ids:
await bot.send_message(user_id, "...")

وقتی به await یوزر اول می‌رسیم، هنوز اصلا به iteration بعدی نرسیدیم؛ یعنی عملیات مربوط به کاربر دوم هنوز شروع یا schedule نشده. بنابراین تا عملیات اول کامل نشه، لوپ سراغ یوزر بعدی نمی‌ره.

در واقع چیزی شبیه این اتفاق می‌افته:
await task1()
await task2()

اما اگر کارها رو از قبل به‌عنوان تسک زمان‌بندی کنیم:
t1 = asyncio.create_task(task1())
t2 = asyncio.create_task(task2())

await t1
await t2

اینجا هر دو تا تسک واسه‌ی اجرا به ایونت لوپ سپرده شدن. بنابراین وقتی task1 منتظر I/O می‌مونه، ایونت لوپ می‌تونه توی همین فاصله task2 رو هم پیش ببره. واسه‌ی همین سناریو asyncio.gather هم خیلی کاربردیه؛ وقتی coroutineها رو بهش می‌دیم، اون‌ها رو به‌صورت تسک زمان‌بندی می‌کنه و منتظر می‌مونه تا همه کامل بشن.


پس یه سوءتفاهم رایج اینه که فکر کنیم await یعنی: "صبر کن، بعد برو سراغ کار بعدی". در حالی که دقیق‌ترش اینه که await یعنی: "این coroutine توی این نقطه منتظر بمونه؛ اگ ایونت لوپ کار دیگه‌ای واسه‌ی اجرا داشته باشه، می‌تونه توی همین فاصله اون رو پیش ببره" و این دقیقا دلیل تفاوت بین این دو تا حالته:
await task1()
await task2()

و:
t1 = asyncio.create_task(task1())
t2 = asyncio.create_task(task2())

await t1
await t2

اولی عملیات دوم رو تا رسیدن نوبتش اصلا شروع نکرده؛ دومی هر دو عملیات رو از قبل schedule کرده.


اگه بخوام کل ماجرا رو توی یه جمله خلاصه و سرتون رو درد نیارم:
ایسینک به شما امکان concurrency می‌ده؛ اما این شمایید که باید مشخص کنید چه کارهایی هم‌زمان در اختیار Event Loop قرار بگیرن.



💡• #AskFarshad@Melfex
231
به سال‌هایی که تازه حرفه‌ای شده بودم حسودیم می‌شه. نه ستاپ درستی داشتم، نه سیستم درست‌حسابی، نه دانش و تجربه‌ی الانم. یه سیستم ذغالی، یه مانیتور قدیمی و اینترنتی که بیشتر از نصف وقت قطع بود. ولی با همه‌ی این‌ها، می‌شد ساعت‌ها پشتش نشست و کار کرد؛ می‌شد دو، سه ساعت بدون اینکه ذهنت هر پنج دقیقه بگه «یه سر بریم ببینیم چه خبره»، فقط کد زد و جلو رفت.

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

امروز اما همه‌چیز بهتره؛ سیستم بهتره، ابزارها بهتر شدن، دانش و تجربه‌م بیشتره، AI و هزاران کتابخونه و سرویس وجود دارن که اون موقع حتی تصورشون رو هم نمی‌کردم. ولی خودم؟! بیشتر از یه ربع نمی‌تونم واقعا توی کار فرو برم.

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

امروز حتی شروع کردن یه کار ساده هم داستان خودش رو داره. اینترنت امروز کار می‌کنه؟! این سرویس باز می‌شه؟ VPN جواب می‌ده؟ این پکیج دانلود می‌شه؟! اون API در دسترسه؟! و مسئله فقط زمانی نیست که از دست می‌ره. هر بار که اتصال می‌پره یا برای ساده‌ترین چیز مجبور می‌شی دنبال راه جایگزین بگردی، رشته‌ی فکرت هم پاره می‌شه. برنامه‌نویسی فقط به سیستم و اینترنت نیاز نداره؛ به یه محیط نسبتا پایدار برای فکر کردن هم نیاز داره.

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

یه گوشه‌ی ذهنت داره کد می‌زنه و یه گوشه‌ی دیگه مدام داره حساب می‌کنه: «اصلا آخرش چی؟!» بعد از خودمون می‌پرسیم چرا مثل قبل تمرکز ندارم یا چرا دیگه اون آدم سابق نیستم؟! شاید چون اون آدم سابق، مجبور نبود هر روز این‌همه چیز رو هم‌زمان با خودش حمل کنه.

من حتی فکر نمی‌کنم AI یا سوشال‌مدیا مقصر اصلی باشن. این‌ها می‌تونن حواس‌پرتی رو بیشتر کنن، اما حتی اگه گوشی رو هم ازت بگیرن، هنوز بی‌ثباتی، فشار اقتصادی و آینده‌ی مبهم سر جاشونه.

آدم برای ساختن، به یه حداقلی از امنیت و ثبات نیاز داره؛ نه زندگی لوکس، نه رفاه عجیب. فقط اینکه مطمئن باشه انرژی‌ای که امروز برای ساختن آینده می‌ذاره، فردا معنایی خواهد داشت.

من هنوز همون آدمی‌ام که می‌تونه ساعت‌ها کد بزنه. می‌دونم، چون قبلاً انجامش دادم؛ با سخت‌افزار بدتر، امکانات کمتر و دانش خیلی کمتر. پس شاید لازم نیست بیشتر خودم رو سرزنش کنم. شاید اول باید بفهمم چرا این‌قدر خسته‌ام.

من دلم برای اون لپ‌تاپ ذغالی تنگ نشده؛ دلم برای ذهنی تنگ شده که پشت اون لپ‌تاپ می‌نشست. ذهنی که فقط یه پروژه داشت، یه مسئله داشت، یه هدف داشت و واسه‌ی چند ساعت لازم نبود به صدها چیز دیگه فکر کنه.

هیچ عادلانه نیست. نمی‌دونم قراره چطور تموم بشه. فقط امیدوارم حداقل این‌طوری ادامه پیدا نکنه. یا کامل تموم بشیم، یا این حال‌وروز کثافت زودتر از بین بره :)


👤 • #FromFarshad@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
3432
اگه یه اپلیکیشن Python روی سرور کند بشه، اولین کاری که معمولا می‌کنیم اینه که می‌ریم سراغ کد و شروع می‌کنیم به حدس زدن اینکه مشکل کجاست. اما اگه اپلیکیشن همین الان روی پروداکشن در حال اجرا باشه چی؟! نمی‌خوایم کد رو تغییر بدیم یا برای Profiling دوباره دیپلوش کنیم.


اینجاست که py-spy جالب می‌شه. یه Profiler واسه‌‌ی پایتونه که می‌تونه به یه پراسس در حال اجرا وصل بشه و نشونتون بده اپلیکیشن بیشتر وقتش رو کجا داره می‌گذرونه؛ بدون اینکه لازم باشه کد اپلیکیشن رو تغییر بدید یا دوباره رانش کنید.

• پروفایلینگ لایو؛ با py-spy top می‌تونید مثل دستور/کامند top ببینید کدوم فانکشن‌ها بیشترین زمان رو مصرف می‌کنن.

• گراف Flame؛ با py-spy record می‌تونید از ران اپلیکشین یه گزاف بگیرید و راحت‌تر هاتسپات‌های اپلیکشین رو پیدا کنید.

• بررسی استاک پراسس‌ها؛ با py-spy dump می‌تونید استاک فعلی تردهای پایتون رو ببینید و بفهمید اپلیکیشن دقیقا کجا متوقف شده.

نکته‌ی جالبش اینه که خود py-spy با Rust نوشته شده و خارج از پراسس اصلی اپلیکیشن اجرا می‌شه؛ واسه‌ی همین با هدف Profiling اپ‌های واقعی و حتی پروداکشن طراحی شده.

🐱 github.com/benfred/py-spy


🔨• #DevEdu@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
522
یه مسیر جدید رو شروع کردم؛ AI Engineering.

مدتی بود که می‌خواستم جدی‌تر وارد دنیای هوش مصنوعی بشم، اما این بار تصمیم گرفتم به‌جای اینکه مستقیم برم سراغ ابزارها و ترندهای روز، از پایه شروع کنم و مفاهیم رو درست بفهمم.

فعلا دارم چیزهایی مثل "NLP"، "LLM"، "LMM" و تفاوت بین این مفاهیم پایه رو یاد می‌گیرم. شاید واسه کسی که مدت‌ها توی این حوزه کار کرده، این‌ها خیلی ابتدایی به نظر برسن؛ ولی واسه‌ی من قرار نیست چیزی رو فقط به خاطر اینکه «بلدم» رد کنم. و هدفم اینه که تا سال آینده حداقل به یه سطح مطلوبی از جونیوری برسم.

از امروز هم می‌خوام یادگیریم رو مثل یه دفترچه‌ی عمومی جلو ببرم؛ چیزهایی که هر روز یاد می‌گیرم، نکته‌هایی که برام جالبن و چیزهایی که حین مسیر می‌فهمم رو اینجا می‌نویسم. شاید بعضی‌هاشون خیلی ساده باشن، ولی فکر می‌کنم ثبت کردن مسیر یادگیری، خودش بخشی از یادگیریه.

بریم ببینیم سال بعد کجای این مسیر ایستادم :)


🧠 • #AIEngineering@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
521
یکی از پایه‌ای ترین چیزهایی که توی این مسیر دارم یاد می‌گیرم، اینه که بین اصطلاحاتی که هر روز می‌شنویم دقیقا چه رابطه‌ای وجود داره. مثلا NLP و LLM خیلی وقت‌ها کنار هم استفاده می‌شن، اما اصلا یه چیز نیستن.

ان‌ال‌پی (Natural Language Processing) یه حوزه از هوش مصنوعیه که روی تعامل کامپیوتر با زبان انسان تمرکز داره؛ یعنی مسئله‌هایی مثل ترجمه، تحلیل احساسات، استخراج اطلاعات، خلاصه‌سازی و پاسخ به سؤال، همگی می‌تونن توی حوزه‌ی NLP قرار بگیرن.

اما Language Model یه مدل آماری/محاسباتیه که با زبان کار می‌کنه؛ به‌طور ساده، یاد می‌گیره با توجه به یه توالی از توکن‌ها، درباره‌ی ادامه‌ی احتمالی اون توالی پیش‌بینی انجام بده.

ال‌ال‌ام (Large Language Model) هم در واقع یه Language Model توی مقیاس بزرگه؛ مدلی که معمولا با تعداد بسیار زیادی پارامتر و حجم عظیمی از داده (عمدتا هم از اینترنت‌) آموزش داده شده و می‌تونه طیف گسترده‌ای از وظایف زبانی رو انجام بده.

این تفاوت مهمه؛ چون وقتی از ChatGPT، Claude یا Gemini صحبت می‌کنیم، صرفا درباره‌ی «NLP» حرف نمی‌زنیم. داریم درباره‌ی سیستم‌هایی صحبت می‌کنیم که از مدل‌های زبانی بزرگ، در کنار اجزای مختلف دیگه، واسه‌ی انجام وظایف پیچیده استفاده می‌کنن.

از طرف دیگه، LLM رو هم داریم؛ مدل‌هایی که فقط به متن محدود نیستن و می‌تونن با چند نوع داده، مثل متن، تصویر یا صدا، کار کنن.



🧠 • #AIEngineering@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
421
وقتی کار با گیت جدی‌تر می‌شه، بعضی کارها توی CLI کمی دردسر پیدا می‌کنن؛ مثلا وقتی بخوای فقط چند خط از یه فایل رو Stage کنی، یه Interactive Rebase انجام بدی یا بخشی از تغییراتت رو Stash کنی. اینجاست که Lazygit واقعا کاربردی می‌شه.

لیزی‌گیت یه رابط کاربری ترمینالی (TUI) واسه‌‌ی گیت‌ هست که بیشتر کارهای روزمره و حتی بعضی عملیات پیشرفته‌ی گیت رو از داخل یه محیط تعاملی در اختیارتون می‌ذاره.

• استیج کردن خط‌به‌خط؛ وارد فایل می‌شید و فقط همون خطوطی که می‌خواید رو استیج می‌کنید.

• ریبیس تعاملی؛ واسه‌ی Squash کردن، حذف یا جابه‌جا کردن کامیت‌مسیج‌ها، به‌جای درگیر شدن مستقیم با git rebase -i، عملیات رو از داخل خود محیط انجام می‌دید.

• مدیریت Stash و کانفلیکت؛ تغییرات رو می‌تونید از داخل محیط مدیریت کنید و هنگام مرج کانفلیکت هم تغییرات و گزینه‌های مربوط به حل کانفلیکت رو یک‌جا ببینید.

چیزی که من توی لیزی‌گیت دوست دارم اینه که قرار نیست گبت رو ازتون پنهان کنه؛ همون گیت خودتونه، فقط یه رابط تعاملی و سریع روی اون قرار گرفته.

🐱 github.com/jesseduffield/lazygit


🔨• #DevEdu@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
411
Melfex 𓏺 فرشاد عسکری
یکی از پایه‌ای ترین چیزهایی که توی این مسیر دارم یاد می‌گیرم، اینه که بین اصطلاحاتی که هر روز می‌شنویم دقیقا چه رابطه‌ای وجود داره. مثلا NLP و LLM خیلی وقت‌ها کنار هم استفاده می‌شن، اما اصلا یه چیز نیستن. ان‌ال‌پی (Natural Language Processing) یه حوزه از…
توی ادامه‌ی مسیر یادگیری رسیدم به یه جای خیلی جذاب؛ اینکه این مدل‌های زبانی بزرگ (LLM) واقعا اون پشت چطوری کار می‌کنن.

- اولین چیزی که شاید یکم عجیب و البته جالب به نظر برسه، اینه که توی هسته‌ی بسیاری از LLMهای مولد، یه مسئله‌ی خیلی ساده داریم: پیش‌بینی توکن بعدی (Next Token Prediction). یعنی مدل وقتی قراره متنی تولید کنه، بر اساس چیزهایی که تا اون لحظه در اختیارشه، احتمال توکن‌های بعدی رو محاسبه می‌کنه و یکی رو انتخاب می‌کنه؛ بعد همین فرایند دوباره و دوباره تکرار می‌شه تا پاسخ ساخته بشه.

- اما اینجا یه مفهوم خیلی پایه داریم به اسم توکن. متن قبل از اینکه وارد مدل بشه، به واحدهایی به اسم توکن تبدیل می‌شه؛ این واحدها لزوما یه کلمه‌ی کامل نیستن و می‌تونن بخشی از یه کلمه، یه کلمه یا حتی یه علامت نگارشی باشن. درک این موضوع مهمه، چون هر مدل ظرفیت محدودی واسه‌ی تعداد توکن‌هایی که می‌تونه توی یه ریکوئست در اختیار داشته باشه داره؛ چیزی که بهش Context Window می‌گیم. از طرف دیگه، مصرف منابع و هزینه‌ی استفاده از بسیاری از سرویس‌های LLM هم بر اساس تعداد توکن‌های ورودی و خروجی محاسبه می‌شه (همچنین ممکنه واسه‌ی هر مدل فرق کنه).

- یه نکته‌ی جالب دیگه، توهمِ داشتن حافظه‌ست. خود مدل به‌صورت ذاتی چیزی از ریکوئست و جت‌های قبلی رو نگه نمی‌داره؛ یعنی اگه ما بخوایم یه سیستم مکالمه‌ای/چت داشته باشیم که «حرف‌های قبلی» رو در نظر بگیره، باید این اطلاعات و دیتا رو به شکلی دوباره در اختیار مدل قرار بدیم. اینجاست که ساختار پیام‌ها و رول‌ها وارد ماجرا می‌شن. توی یه ساختار رایج، پیام‌ها با نقش‌هایی مثل این مشخص می‌شن:
۱. سیستم (System) : دستورالعمل‌ها و قواعدی که برای رفتار مدل تعیین می‌کنیم، می‌شه گفت همون پرامپت اولیه‌س که به مدل می‌دیم.
۲. یوزر (User) : پیام یا ریکوئست از طرف یوزر.
۳. اسیستنت (Assistant): جواب‌هایی که مدل قبلا تولید کرده.
پس اگه بخوایم یه چت چندمرحله‌ای داشته باشیم، معمولا هیستوری مکالمه رو همراه با ریکوئست جدید داخل کانتکست می‌ذاریم تا مدل بتونه بر اساس اون پاسخ تولید کنه.

خلاصه هرچی بیشتر وارد این مفاهیم می‌شم، بیشتر برام جالبه که پشت چیزی که از بیرون شبیه «چت با یه موجود هوشمند» به نظر می‌رسه، چه حجم زیادی از مفاهیم ریاضی، آماری و مهندسی وجود داره.


🧠 • #AIEngineering@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
521
AghayedeYekDalghak.pdf
3.4 MB
این بار رفتم سراغ «عقاید یک دلقک» اثر هاینریش بُل؛ یکی از آثار شناخته‌شده‌ی ادبیات آلمان که سال ۱۹۶۳ منتشر شده.

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

فعلاً تازه شروعش کردم و نمی‌خوام زودتر از خوندنش درباره‌ش قضاوت کنم. طبق روال معمول، پاراگراف‌ها و بخش‌هایی که از نظرم ارزش بیشتری دارن رو با هشتگ #عقاید_یک_دلقک اینجا به اشتراک می‌ذارم.


📚• #FReading@Melfex | #عقاید_یک_دلقک
Please open Telegram to view this post
VIEW IN TELEGRAM
311
تا حالا شده یه API Key، توکن بات یا پسورد دیتابیس رو اشتباهی کامیت کنید؟! چیزی که الان زیاد دیده می‌شه همين اشتباهاست، خصوصا پروژه‌هایی که وایب کد می‌شن.

اینجاست که Gitleaks به کار میاد.

گیت‌لیکس یه ابزار اوپن‌سوزس هست که با گولنگ توسعه داده شده و واسه‌ی شناسایی اطلاعات حساس مثل ای‌پی‌آی کی‌ها، توکن‌ها و Credentialها داخل سورس‌کد و تاریخچه‌ی گیت استفاده می‌شه.

• اسکن تاریخچه‌ی گیت؛ می‌تونید کامیت‌های قبلی رو بررسی کنید و اطلاعات حساسی رو پیدا کنید که حتی از فایل‌های فعلی حذف شدن.

• جلوگیری از نشت دیتا؛ با استفاده از Pre-commit Hook می‌تونید قبل از ثبت تغییرات، فایل‌ها رو اسکن کنید.

• یکپارچگی با CI/CD؛ امکان اجرای خودکار اسکن‌ها داخل پیپ‌لاین وجود داره تا دیتای حساس قبل از انتشار شناسایی بشن.

🐱 github.com/gitleaks/gitleaks


🔨• #DevEdu@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
311
احتمالا دقت کردید که وقتی از چت‌بات هایی مثل ChatGpt یا Claude سوالی می‌پرسید، پاسخ و ریسپانس به‌جای اینکه یک‌جا نمایش داده بشه، به‌صورت تدریجی روی صفحه ظاهر می‌شه. اما تا حالا فکر کردید این استریم کردن اون پشت چطوری اتفاق می‌افته؟!

یکی از راهکارهای رایج برای این کار، تکنولوژی Server-Sent Events یا همون SSE هست که اتفاقا ای‌پی‌آی‌های رسمی اوپن‌ای‌آی و انتروپیک هم ازش پشتیبانی می‌کنن.

برخلاف وب‌سوکت که ارتباط دوطرفه فراهم می‌کنه، SSE واسه‌‌ی ارسال یک‌طرفه‌ی داده و دیتا از سرور به کلاینت طراحی شده؛ دقیقا چیزی که توی خیلی از سناریوهای استریم پاسخ LLM بهش نیاز داریم.

• مبتنی بر HTTP؛ نیازی به برقراری اتصال وبسوکت ندارید و می‌تونید ریسپانس‌ها رو روی یه HTTP ریسپانس استریم کنید.

• پشتیبانی نیتیو مرورگر؛ با API استاندارد "EventSource" می‌تونید ایونت‌ها رو دریافت کنید و حتی از قابلیت Auto-reconnect استفاده کنید.

• پیاده‌سازی ساده؛ واسه‌ی سناریوهایی مثل داشبوردهای مانیتورینگ، نوتیفیکیشن‌های لایو یا استریم پاسخ مدل‌های زبانی، لزوما نیازی به پیاده‌سازی ارتباط دوطرفه ندارید.

البته SSE همیشه جایگزین وبسوکت نیست؛ ضمن اینکه واسه‌ی استریم ریکوئست‌های پست یا مدیریت کانکشن مجدد، ممکنه به پیاده‌سازی بیشتری نیاز داشته باشید.

یه نکته‌ی جالب هم اینکه استفاده از SSE پشت ریورس‌ پروکسی‌هایی مثل Nginx نیازمند توجه به تنظیماتی مثل ریسپانس Buffering هست؛ وگرنه ممکنه داده‌ها به‌جای نمایش تدریجی، با تاخیر به کلاینت برسن.


🔨• #DevEdu@Melfex
Please open Telegram to view this post
VIEW IN TELEGRAM
221
Melfex 𓏺 فرشاد عسکری
AghayedeYekDalghak.pdf
هیچ کس در این دنیا ـ چون در بطن موقعیت خاص انسانی دیگر قرار ندارد ـ نمی تواند احساس صحیح و درستی در مورد بدی یا خوبی مسئله ای داشته باشد حالا خواه این مسئله به خوشبختی و بدبختی به عشق و یا افت هنری ارتباط داشته باشد. واقعیت امر این است که هر فردی همواره به نوعی خارج از وضعیت و شرایط انسانی دیگر قرار دارد.


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

ما معمولا نتیجه‌ی تصمیم‌های آدم‌ها رو می‌بینیم، نه تمام تجربه‌ها، ترس‌ها و شرایطی که به اون تصمیم منتهی شدن. چیزی که از بیرون غیرمنطقی به نظر می‌رسه، ممکنه برای کسی که درگیرشه معنای کاملاً متفاوتی داشته باشه.

شاید مسئله این نباشه که نباید قضاوت کنیم؛ بلکه باید بپذیریم فهمیدنِ موقعیت یه آدم، با تصور کردن خودمون به‌جای اون آدم یکی نیست.


📚• #FReading@Melfex | #عقاید_یک_دلقک
Please open Telegram to view this post
VIEW IN TELEGRAM
21