tech-afternoon – Telegram
tech-afternoon
1.22K subscribers
174 photos
6 videos
6 files
166 links
تِک‌افترنون، رویدادی گاه‌به‌گاه است با موضوعات حول معماری و توسعه نرم‌افزار، این کانال هم برای اشتراک اخبار، آموزش، نکاتی حول مهندسی نرم‌افزار، دیتابیس‌، تکنولوژی و مدیریت تولید محصولات نر‌م‌افزاری خواهد بود.
youtube.com/@AminTechTalks/videos
امین مصباحی
Download Telegram
🥸 هر چیزی رو توی اینترنت دیدیم باور نکنیم، خصوصا اگر فنی «به نظر» اومد!

وقت ناهار اینو توی توییتر دیدم که به نظرم بودار 🦨 اومد. من راست بلدم و از سی خاطراتی دارم، ولی خودم رو نه راست‌نویس می‌دونم نه سی‌نویس، بلکه به قدر نیاز و هدف.

یه چالشی چند ساله مطرحه که با زبون‌های مختلف کوچک‌ترین hello world باینری رو چجوری می‌شه نوشت (مثلا جایگزینی printf با puts توی سی یا جایگزینی println با syscall_write توی راست و حذف لایبری‌های اضافه و بهبود لینکینگ و...

لذا نشستم کد راست رو بازنویسی کردم و با ۱۴ کیلوبایت جمع شد. ولی آیا اینکه منم یه توییت بزنم بگم دیدی کد راست (مینیمال راست) من از کد سی کوچیک‌تر شد، درسته؟ خیر! بلکه چرندی به چرندیات افزوده‌ام.

چرا؟ چون اونوقت باید کد مینیمال سی رو مقایسه کنیم که احتمالا باز نسبت به کد ۱۴ کیلوبایتی راست چیزی بین نصف تا یک‌سوم باید کوچیک‌تر شه.

ولی چرا باز هم سی کوچیک‌تر از راسته؟ مگه قرار نبود «عصر، عصر راست‌نویسی» باشه؟ 😁

- راست static linking داره
- راست runtime safety داره

من سورس کدم رو توی کامنت می‌گذارم. ولی اصلا نکته این مطلب اینا نبود! اینه که هر چیزی رو توی اینترنت یا از همکار و دوستمون دیدیم حتی اگر با عدد و رقم و کد آمیخته بود، تفکر انتقادیمون رو نسبت بهش حفظ کنیم 😊
👍7🔥6👏2
📎💡 توضیح ساده Read Your Own Writes Consistency یا (RYW) توی سیستم‌های توزیع‌شده

وقتی یه سیستم بزرگ داریم با تعداد زیاد کاربر یا درخواست همزمان، یکی از چالش‌های اصلی اینه که هر کاربر بتونه تغییراتی که خودش ایجاد کرده رو بلافاصله ببینه. مثلاً وقتی توی یه شبکه اجتماعی پست میذارید، انتظار دارید همون لحظه پستتون رو ببینید، نه اینکه چند ثانیه صبر کنید. به این قابلیت میگن Read Your Own Writes یا RYW (خیلی‌جاها own حذف می‌شه و در نتیجه read your writes می‌شه RYW).

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

⚙️راهکارها:

*️⃣استفاده از region-aware routing یعنی تمام درخواست‌های کاربر به یک منطقه مشخص هدایت بشه تا از تأخیرهای ناشی از تبادل داده بین مناطق مختلف جلوگیری بشه.

*️⃣استفاده از CRDTها (Conflict-Free Replicated Data Types) برای ادغام تغییرات هم به کار می‌رن تا توی مواقعی که چندین کاربر همزمان روی یه داده تغییر ایجاد می‌کنن، همگی به صورت یکپارچه به‌روز بشن

*️⃣استفاده از Session Token یعنی اطلاعاتی در مورد آخرین تغییراتی که کاربر ایجاد کرده رو نگه توی این توکن‌ها نگهداری کنیم.

یه روش دیگه که خیلی جالب عمل می‌کنه، استفاده از خواندن مبتنی برQuorum-Based Reads With Vector Clocks هست. توی این روش، وقتی می‌خوایم یه داده رو بخونیم، از چند سرور درخواست می‌دیم و آخرین نسخه رو بر اساس زمان‌بندی منطقی انتخاب می‌کنیم. همچنین تکنیک‌هایی مثل read repair وجود دارن که وقتی می‌بینیم داده‌ها به‌روز نیستن، به‌طور خودکار اون‌ها رو دوباره از دیتابیس اصلی می‌خونن و تازه می‌کنن. (برای این مورد باید پراکنده جغرافیایی وسیعی داشته باشیم تا توجیه پیدا کنه).

در نهایت، باید بگم که رسیدن به یه سیستم با Read Your Own Writes consistency توی مقیاس بزرگ نیازمند برنامه‌ریزی دقیق و نظارت مداوم هست. نمونه‌های موفق توی دنیای واقعی مثل پلتفرم‌های شبکه‌های اجتماعی، سایت‌های تجارت الکترونیک و ابزارهای همکاری آنلاین ثابت کردن که با استفاده از این تکنیک‌ها، می‌شه تجربه کاربری فوق‌العاده‌ای رو تضمین کرد. ولی برای سیستم‌هایی که مثلا توی یک کشور و حتی توی یک دیتاسنتر هستن اگر چالش RYW داشته باشیم، احتمالا و تکیه می‌کنم احتمالا یه مشکلی توی طراحی و پیاده‌سازی داریم...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍92🔥2👏1
‼️استانداردسازی خطاهای REST API با Problem Details (RFC 7807)

وقتی بحث طراحی REST API میاد وسط، خیلیا فقط به CRUD فکر می‌کنن و اینکه یه سری endpoint که دیتا می‌گیرن و کوئری پاسخ می‌دن. اینکه API کار کنه و خطا نده کافی نیست، اگر استاندارد نباشه مشکلاتی متعاقب خودش به بار میاره که مفصله. استانداردهای طراحی API کمک می‌کنن که APIها قابل پیش‌بینی، خوانا و سازگار باشن. برای همین هم REST API‌های اصولی، معمولاً از الگوهای استاندارد استفاده می‌کنن.

یکی از مشکلات رایج طراحی API، مدیریت و ارسال خطاهاست. خیلی از APIها به شکل‌های مختلف خطا برمی‌گردونن؛ یکی JSON میده، یکی XML، یکی فقط یه متن ساده، و بعضی‌ها هم فقط یه HTTP Status Code. اینجاست که RFC 7807 وارد می‌شه!

تعریف RFC 7807: استاندارد کردن جزئیات خطاها توی REST API

در حقیقت RFC 7807 استانداردیه که توش تعریف شده چطور APIها می‌تونن جزئیات خطاها (Problem Details) رو به صورت JSON یا XML برگردونن، به‌جای این که هر کی واسه خودش یه فرمتی اختراع کنه. فرمت پیشنهادی این شکلیه:
{
"type": "https://example.com/probs/out-of-credit",
"noscript": "You do not have enough credit.",
"status": 403,
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/transactions/67890"
}


اجزای کلیدی:

الف: type: یه URL که نشون میده این نوع خطا چیه (میشه مستندات مربوطه رو اینجا گذاشت)
ب: noscript: یه توضیح کوتاه و ثابت درباره‌ی نوع خطا
پ: status: همون HTTP Status Code که برمی‌گرده
ت: detail: توضیح دقیق‌تر در مورد این خطای خاص
ث: instance: آدرسی که خطا در اون رخ داده

مزایای استفاده از Problem Details

*️⃣استاندارد بودن: همه جا یه فرمت ثابت داریم -> نرم‌افزار مونیتورینگ لاگ براش فرقی نمی‌کنه API از کجا و چه زبونی اومده، جزئیات خطا رو درست تشخیص می‌ده
*️⃣توسعه‌پذیری: می‌تونیم فیلدهای سفارشی اضافه کنیم
*️⃣مستندسازی بهتر: فرمت مشخص باعث میشه مستندات بهتری داشته باشیم
*️⃣پشتیبانی فریم‌ورک‌ها: اکثر فریم‌ورک‌های مدرن ازش پشتیبانی می‌کنن
*️⃣قابلیت اتوماسیون: ابزارها می‌تونن به راحتی خطاها رو پردازش کنن

🔗 متن استاندارد

💬 نظر شما چیه؟ از Problem Details استفاده می‌کنید؟ اگر کد مثال می‌تونه کمک کنه: ⚙️

#API_Design
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍7
🥸 اندر احوالات تست‌نویسی، باب TUnit

پسری را به کارگه کدنویسی همی بردندی تا شیوه‌ی کُدگری پیشه کند، استاد بگفت: «بِکُد، سپس بِتِست!» شاگرد مدتی استاده، بُکید، خسته شد؛ لَختی درنگ کرد و از برای تستیدن پرسید:

«استاد رخصت می‌دهی تا با MSTest بِتِستَم؟»
استاد بدو گفت: «بِتِست!»

باز مدتی بِتِستید، خسته شد، گفت: «استاد، اجازت باشد تا این بار به NUnit بگرایم و بِتِستم؟»
استاد گفت: «بِتِست!»

باز مدتی بِتِستید، باز خسته شد، گفت: «استاد، دلم هوای XUnit کرده است، رخصت می‌دهی تا به آن بِتِستم؟»
استاد گفت: «بِتِست!»

دیگر نایی در تنش نمانده بود، گفت: «استاد! مرا زین همه آزمون، امان ده! باشد که آخرین بار به TUnit 🧪بِتِستم و آنگاه بیاسایم؟»
💎 استاد گفت: «تو بِتِست، بمیر و بِتِست!»

* بِتِست: فعل امر تست نوشتن
* بُکید: فعل ماضی کد نوشتن، سوم شخص مفرد


درسته که مهم، تست نوشتنه، حالا بسته به نیازمون unit، integration, e2e, behaviour, stress, یا...
حالا اگر روی این موضوع توافق داریم، ولو به «تو بِتِست، بمیر و بِتِست!» و کنجاوید بدونید TUnit آیا یه قرطی‌بازی جدیده و یه بابایی آخر هفته بیکار بوده یه چیزی نوشته و چهار روز دیگه هم ولش می‌کنه، یا اینکه نه! یه نیازی بوده که با وجود MSTest و NUnit و XUnit یه لایبری تست‌نویسی جدید به وجود اومد؟!

اگر سواله، بگید تا بیشتر در موردش بگم و یه مقایسه با اون ۳ تا پیرمرد داشته باشم...

ری‌اکشن برای توضیح بیشتر: ⚙️

💬 تجربه، نظر؟
Please open Telegram to view this post
VIEW IN TELEGRAM
17👍1
این روزها تقریبا یکسالگی TUnit است. یه کتابخونه جدید برای نوشتن Unit، Integration، Acceptance و هر جور تست دیگه‌ای توی دات‌نت. حدود ۱۹۱هزار دانلود NuGet داشته و توسعه‌اش فعلا خیلی فعاله و جزو گیت‌هاب ترند هست.

ولی چرا؟
خب می‌دونیم که NUnit عملا پورت شده‌ی JUnit جاوا است، و xUnit انشعابی بهبود یافته از NUnit.
خود NUnit که باقیمانده دوران SharpTestEx و Lin Unit و NUnitEx و NUnitAsp است که حتی ریپوهاشون هم هفت کفن پوسوندن، نزدیک به ۲۰ سال قدمت داره. درسته که همواره به‌روز شده و پوست‌اندازی داشته و امروز یه محصول بالغه؛ ولی مدت‌هاست تغییرات بزرگی نداره و فقط باگ و بوگ (بوگ به مفهوم باگچه، و باگ کوچک است) برطرف می‌کنه. (تاریخچه JUnit هم برمی‌گرده به یه پرواز بین زوریخ و آتلانتا در سال ۱۹۹۷! و الان نسل پنجم خودش رو تجربه می‌کنه)

واقعیت اینه که دنیای تست از نظر مفهوم و ساختار تغییرات انقلابی خاصی نداشته. لذا این لایبری‌ها هم فرصت داشتن تا بالغ و پایدار بشن.

چی‌ شد که TUnit متولد شد؟
اون لک‌لکی که TUnit رو توی گیت‌هاب git push کرد، و خودش هم می‌گه از NUnit و xUnit الهام گرفته، چند تا هدف داشت:
- یکی کدبیس مدرن از ابتدا
- بهبود سرعت اجرای تست

دقت کنید که این داستان «هیچ ربطی» به تیمی که هنوز توی بدیهیات تست‌نویسی گیر کرده و کاوریجش ۳۰ درصده نداره! بلکه برای تیمیه که می‌خواد از یک کتابخونه برای همه نوع تستش استفاده کنه، هزاران تست داره و سرعت اجرای تست‌ها می‌تونه تجربه توسعه‌دهنده و دواپس رو بهبود بده.
مثلا: TUnit از source generators تا جای امکان به جای reflection استفاده می‌کنه و AOT رو به خوبی پشتیبانی می‌کنه.

مثال دوم: کدبیس مدرنش به شما Hooks, Events روی کل Lifecycles تست می‌ده؛ یعنی قبل و بعد از ،TestDiscover ،TestSession، Assembly، Class، Test. مثلا شما با ایونت مطلع می‌شید تست شروع شد، تست وارد فلان مرحله شد و... این هم به درد تست‌نویس می‌خوره هم به‌درد اون بدبختی که پایپ‌لاین DevOps شما رو توسعه می‌ده.

مثال سوم: از بیخ به شما اجازه پاس دادن انواع داده برای تست رو میده. این به معنای ناتوانی xUnit نیست، بلکه پیاده‌سازی راحت‌تر و مدرن‌تره. وقتی شما سرعت 321.7 میلی‌ثانیه TUnit در مقابل ۱۴ ثانیه xUnit به کارتون میاد، که اولا «واقعنکی» (به معنی خیلی واقعی) تست می‌نویسید. دوم اینکه تعداد زیادی تست دارید و... البته این تفاوت زیاد، فقط در برخی موارد است چون TUnit قابلیت AOT دارد و در خیلی از موارد تفاوت حداقل هنوز اینقدرها نیست.

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

ریپو
مستندات
👍182
طراحی API و مفهوم Idempotency

معنی idempotent : شاید بشه «همانندپذیر» رو معادل خوبی براش دونست؛ توی ریاضی «عدد ۱ در عملیات ضرب» همانندپذیر هست، چون هر چند بار که یک در خودش ضرب شه، باز هم ۱ به دست میاد. ولی ۲ اینطور نیست چون ۲ اگر در خودش ضرب شه می‌شه ۴.
پس idempotent عملیاتی هست که چندین بار اجرا کردنش، نتیجه‌ای مشابه با یک بار اجرا کردنش داره.

یکی از دغدغه‌های اصلی توی سیستم‌هایی مثل پرداخت‌ یا عملیات حساس، اینه که وقتی کاربر چندبار یک درخواست رو می‌فرسته، سیستمو نباید چندبار اون رو پردازش کنه. به بیان ساده‌تر، API ما باید idempotent باشه؛ یعنی خروجی و اثرش هر بار یکسان باشه، حتی اگر درخواست رو چند بار ارسال کنیم (حالا چه سهوی، چه تعمدی و با قصد بد!) مثلا کاربر اگر API پرداخت رو چند بار فراخوانی کنه ممکنه چند بار وجه از حسابش کسر بشه یا مواردی از این دست.

روش‌های طراحی APIهای Idempotent

1️⃣ استفاده از Idempotency-Key
یکی از روش‌های رایج برای حل این مشکل استفاده از یک کلید منحصر به فرد به نام Idempotency-Key است. وقتی کاربر یک درخواست حساس (مثلاً پرداخت) رو ارسال می‌کنه، یک کلید یکتا همراه درخواست ارسال میشه. سرور وقتی درخواست رو دریافت می‌کنه، اول چک می‌کنه که آیا قبلاً درخواستی با اون کلید دریافت شده یا نه.
POST /payments
Headers: {
"Idempotency-Key": "abc123"
}
Body: {
"amount": 1000,
"currency": "IRR"
}


2️⃣ روش Optimistic Concurrency Control
استفاده از کنترل همزمانی خوشبینانه (Optimistic Concurrency Control). هر موجودیت (entity) یه نسخه یا شناسه تغییر (مثلاً ETag) داره. وقتی کاربر می‌خواد تغییراتی رو روی اون موجودیت اعمال کنه، نسخه موجودیت رو همراه درخواست می‌فرسته.
اگر نسخه‌ای که فرستاده شده با نسخه فعلی مطابقت داشته باشه، تغییر اعمال میشه؛ در غیر این صورت، یعنی کسی یا چیزی قبلاً تغییر ایجاد کرده و سرور خطا برمی‌گردونه.

PUT /orders/123
Headers: {
"If-Match": "v1"
}
Body: {
"status": "paid"
}

3️⃣ روش Conditional Requests
از Conditional Requests می‌شه استفاده کرد، یعنی با استفاده از هدرهای HTTP مثل If-None-Match یا If-Modified-Since وقتی کاربر درخواست می‌ده، سرور بررسی می‌کنه که آیا داده‌های موجود تغییر کرده یا نه.
اگر داده تغییر نکرده باشه، سرور یک پاسخ مشابه برمی‌گردونه بدون اینکه دوباره عملیات رو انجام بده. مثلا: فرض کن کاربر می‌خواد اطلاعات پروفایل خودش رو آپدیت کنه. همراه درخواست هدر If-Unmodified-Since ارسال میشه که نشان دهنده آخرین باریه که اطلاعات تغییر کرده‌اند. اگر اطلاعات بین اون زمان تغییر نکرده باشه، عملیات به درستی انجام میشه؛ در غیر این صورت، سرور خطا میده که نشان میده اطلاعات به‌روزرسانی نشده یا تغییر کرده.

💬 نظر؟ بحث؟ گپ بزنیم؟

#API_Design
Please open Telegram to view this post
VIEW IN TELEGRAM
👍175
🤪 در باب تفکیک انتقاد از هجمه!

ℹ️ این مطلب فنی نیست، رفرنس‌محور هم نیست، و تحلیل و نوشتار شخصی ( و طبیعتا محتمل‌به‌خطا) است!

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

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

حالا بیایم این شرایط و فضا رو که کم‌وبیش دیده‌ایم یه مقدار بشکافیم...

- خیلی از این بازخوردهای مجازی، جز تقویت خشم و هیجان فایده و یادگیری ندارن برامون. (حتی اگر خودمون متوجه نشیم، ناخواسته توی وجودمون خشم و هیجان و تعصب رو تقویت می‌کنن)

- خواستگاه تعداد زیادی از این بازخوردها، ولو اینکه خیلی موجه و منطقی به نظر بیان، باز هم خشم است!

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

- هیچ اظهار نظری، اعم از یک نظر اشتباه، ناقص یا حتی مضحک در مورد یک تکنولوژی؛ یا یک شیوه صحبت کردن یا یک تُپُق یا... اینقدر ناموسی و مهم نیست... چرا فکر نکنیم یک نفر از ۸ میلیارد جمعیت زمین یه نظری داده! چقدر موثره مگه؟! اگر من اومدم اینجا در مورد API Design یا ... یه مزخرفی گفتم، شما برو تحقیق کن درستش رو یاد بگیر، یا درستش رو جایی بنویس...

- این روزها و سال‌ها جامعه ما (و حتی جهان) این‌قدر آکنده از خشم و تفرقه است که ای کاش ما سهمی حتی در حد یک لایک یا کامنت ولو بامزه، در این حجم از نجاست خشم و نفرت نداشته باشیم

🌱 نقد سازنده در هر موضوعی ۴ تا مولفه‌ی «لاینفک» داره: ۱: پرداختن به موضوع به جای مصداق ۲: همراه داشتن راه‌حل منطقی ۳: پرهیز از تعصب و خشم و هیجان ۴: باور به حق آزاداندیشی، هر کسی آزاده تا هر باور و نظری داشته باشه، و در صورت ضرر به دیگران، قانون باید براش تصمیم بگیره و بس.

💬 اگر این مطلب رو خوندید، اولا متشکرم 😊 دوم اینکه خوشحال می‌شم نظرتون رو بدونم...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍84
✍️مرور چند روش رایج صفحه‌بندی (Pagination) در API Design

وقتی با داده‌های بزرگ سر و کار داریم، نمایش اطلاعات به صورت صفحه‌بندی شده خیلی مهم‌تر از حالت عادیه که دریافت داده از سمت سرور بار قابل توجهی نداره (چه سمت واکشی داده، چه سمت ارسال به سمت کلاینت)

و این خیلی مهم می‌شه که روش استاندارد و یکسانی داشته باشیم تا یکی شماره صفحه و تعداد رو توی GET نگیره یکی توی POST تا بتونیم هم جلو بار اضافی به سرور رو بگیریم هم کاربری یا توسعه‌دهنده‌ای که با API سر و کار داره دیوانه نشه!

1️⃣ روش Offset & Limit (یا Page & Size)

GET /users?limit=10&offset=20

این روش ساده و سرراسته، و امکان دسترسی مستقیم به صفحه دلخواه رو فراهم می‌کنه. ولی وقتی دیتاست خیلی بزرگ شه، مستعد درخواست‌های عمدی یا سهوی کند کننده است! یا اگر داده‌ها مرتب تغییر کنن، شما یا یه چیزی از قلم می‌ندازی یا تا بری صفحه ۲، دیتای صفحه ۱ افتاده توی صفحه ۲! (نرخ بالای تغییرات) کوئری‌اش هم اینجوریه:
-- SQL Server:
SELECT * FROM users
ORDER BY id
OFFSET 20 ROWS
FETCH NEXT 10 ROWS ONLY;

-- PostgreSQL:
SELECT * FROM users
ORDER BY id
LIMIT 10 OFFSET 20;

-- MongoDB:
db.users.find()
.sort({ id: 1 })
.skip(20)
.limit(10);


2️⃣ روش Cursor-based Pagination
توی این روش به جای استفاده از offset، از یک نشانگر (cursor) استفاده می‌کنیم که به عنوان مرجع برای ادامه‌ی داده‌ها عمل می‌کنه. معمولاً این cursor می‌تونه آخرین مقدار یک فیلد کلیدی مثل id یا تاریخ ایجاد باشه.
GET /users?limit=10&cursor=eyJpZCI6IDIwMH0=

این روش کارایی بهتری توی داده‌های بزرگ داره، یکی از دلایلش اینه که نیازی سورت کردن داده و بعدش رد کردن تعدادی رکورد نداره! بلکه مستقیم (با کمک ایندکس البته) می‌ره سراغ رکورد مورد نظر و تامام. اگر داده‌ها مرتب تغییر کنن، باز کاربر مسیر خودش رو پیمایش می‌کنه و داده‌های تکراری نمی‌بینه یا داده‌هایی رو از دست نمی‌ده.
ولی: پیچیدگی پیاده‌سازیش بیشتره. صفحه ۵ الزامان برای همه و در همه زمان‌ها یک داده‌ رو نشون نمی‌ده.
برای مقیاس بزرگ این روش مناسب‌تره، اون بار تحمیلی سورت و skip توی مقیاس بزرگ کمرشکنه!

3️⃣روش Seek-pagination (Keyset Pagination)
روش seek-pagination یا keyset pagination به روش cursor-based شباهت داره، ولی به صورت صریح از شرایط WHERE استفاده می‌کنه تا رکوردهایی که بعد از آخرین مقدار دیده شده قرار دارن رو برگردونه.
GET /orders?limit=10&last_id=1000

در اینجا فرض می‌کنیم که last_id نشان‌دهنده‌ی آخرین id دیده شده در صفحه قبلی هست. سرور از شرط WHERE id > 1000 استفاده می‌کنه تا رکوردهای بعدی رو برگردونه.

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


4️⃣روش Time-Based Pagination
GET /events?since=2023-10-01&until=2023-10-08


5️⃣روش Hypermedia (HATEOAS) Links
Link: </items?cursor=def456>; rel="next", </items?cursor=abc123>; rel="prev"


6️⃣روش Metadata in Responses
{
"data": [...],
"pagination": {
"total": 1000,
"next_cursor": "def456",
"has_more": true
}
}


💬 اولندش بحث؟ نظر؟ تجربه؟ دُوُمَندش ۴ و ۵ و ۶ رو توضیح ندادم که الکی مثلا کنجکاوی ایجاد کنم، هزاران و میلیان‌ها ری‌اکشن ⚙️ بدید که توضیح بدم و بگم چرا روش HATEOAS روش منطبق با REST principles ذیل discoverability است!! 😅 سِوُمَندش دون بپاشم برای پرداختن عمیق‌تر به اهمیت ایندکس و درک ساختاریش، بعد از یخورده مطلب حول طراحی API نوشتم...

#API_Design
Please open Telegram to view this post
VIEW IN TELEGRAM
34👍3🤓1
tech-afternoon
✍️مرور چند روش رایج صفحه‌بندی (Pagination) در API Design وقتی با داده‌های بزرگ سر و کار داریم، نمایش اطلاعات به صورت صفحه‌بندی شده خیلی مهم‌تر از حالت عادیه که دریافت داده از سمت سرور بار قابل توجهی نداره (چه سمت واکشی داده، چه سمت ارسال به سمت کلاینت) و…
✍️2️⃣ توضیح روش‌های ۴ تا ۶ صفحه‌بندی (Pagination) در API

4️⃣ روش Time-Based Pagination
وقتی داده‌هامون به ترتیب زمان ثبت می‌شن (مثلاً رویدادهای یک سیستم لاگ یا خبرنامه‌های زنده)، می‌تونیم با استفاده از پارامترهایی مثل since و until بازه‌ی زمانی دلخواهمون رو مشخص کنیم.
مثال:

GET /events?since=2025-01-01&until=2025-01-10

اینجا API رو طوری طراحی می‌کنیم که همه‌ی رویدادهایی که بین اول تا دهم ژانویه اتفاق افتاده رو برگردونه.

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

5️⃣ روش Hypermedia (HATEOAS) Links
روش HATEOAS (Hypermedia As The Engine Of Application State) یکی از اصول کلیدی REST هست. توی این روش، پاسخ‌های API شامل لینک‌هایی به صفحات بعدی یا قبلی هستند. این لینک‌ها معمولاً در هدر یا بدنه‌ی پاسخ قرار می‌گیرند و به کلاینت می‌گن «برای ادامه اینجا رو ببین» یا «صفحه قبلی اینجاست».
مثال:
Link: </items?cursor=def456>; rel="next", </items?cursor=abc123>; rel="prev"

توی این مثال، لینک‌های next و prev به کلاینت کمک می‌کنن بدون اینکه خودشون URL ها رو بسازن، به صفحات بعدی یا قبلی دسترسی پیدا کنن.

بزرگ‌ترین مزیتش علاوه بر استاندارد بودن، اینه که کلاینت‌ها نیازی به دونستن ساختار URL‌ها ندارن؛ API خودش مسیر بعدی رو بهشون میگه. در ضمن به راحتی می‌شه لینک‌های مختلف (مثلاً first، last، یا حتی لینک‌های مرتبط) رو اضافه کرد.از طرفی مدیریت و تولید این لینک‌ها به دقت نیاز داره تا همه‌ی روابط درست تعریف بشه؛ و استفاده از هدرهای HTTP اضافی ممکنه برای برخی کلاینت‌ها و ابزارها پیچیده باشه.


6️⃣ روش Metadata in Responses
توی این روش، به جای ارسال اطلاعات صفحه‌بندی در هدر، کل متادیتا (مثل تعداد کل رکوردها، cursor بعدی، و وضعیت وجود صفحه‌ی بعدی) رو توی بدنه‌ی پاسخ JSON می‌گنجونیم. این کار باعث می‌شه کلاینت به راحتی اطلاعات لازم رو از یک جا دریافت کنه.

{
"data": [...],
"pagination": {
"total": 1000,
"next_cursor": "def456",
"has_more": true
}
}

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

💬 نظر؟ بریم سراغ موضوع دیگه: 🤓
یا روی API Design ادامه بدیم: ⚙️

اگر روی API Design بمونیم:
- موضوع API Documentation و Discoverability
- استراتژی‌های مدیریت نسخه‌بندی API در طول زمان (API Evolution)
Please open Telegram to view this post
VIEW IN TELEGRAM
21🔥1
📎در باب API Documentation و Discoverability

بیاین فرض کنیم REST API ماه مثل منو رستورانه؛ API Documentation همون فهرستیه که جزئیات هر غذا (یا توی این مورد، هر endpoint) رو شرح می‌ده، مثلاً ورودی‌ها، خروجی‌ها، خطاهای احتمالی و ...

از طرفی، Discoverability یعنی این که چطور می‌تونیم به راحتی بفهمیم کدوم endpoint ها وجود دارن و چه امکاناتی رو فراهم می‌کنن. این باعث میشه که توسعه‌دهنده‌ سریع‌تر بتونه از API استفاده کنه و به روزرسانی‌ها رو در زمان مناسب متوجه بشه. این روز‌ها هم که به جز توی پروژه‌ها و تیم‌های کوچیک، افراد و حتی تیم‌هایی که API رو توسعه می‌دن و API رو مصرف می‌کنن؛ از هم جداست. پس باید به فکر اون بیچاره‌ای که می‌خواد API رو سمت خودش استفاده کنه هم باشیم؛ هم Documentation و هم Discoverability رو پاس بداریم (به فکر اعصاب افراد و وقت خودمون باشیم)

⚙️ مفهوم API Documentation؟
- راهنمای ورودی و خروجی: چه پارامترهایی نیاز دارین و خروجی چجوری خواهد بود. خصوصا وقتی آبجکت‌های پیجیده و بزرگ تبادل می‌شه، این موضوع مهم خواهد بود.
- مثال‌های کاربردی: نشون دادن نمونه درخواست و پاسخ.
- خطاها: توضیح اینکه چه خطاهایی ممکنه پیش بیاد و چطور می‌تونین اونا رو مدیریت کنین.


⚙️ مفهوم Discoverability (قابلیت کشف API)
وقتی از Discoverability صحبت می‌کنیم، منظورمون اینه که API هایمون به راحتی قابل دسترسی و شناسایی باشه. این یعنی:
- سازماندهی مناسب: ساختار واضح و منظم برای endpointها.
- استفاده از استانداردها: مثل OpenAPI Specification که باعث میشه ابزارهای مختلف بتونن مستندات شما رو بخونن و حتی تست کنند.
- امکانات جستجو: مثلاً داشبوردهایی که امکان فیلتر کردن و جستجو در مستندات رو فراهم می‌کنن.


نگاهی به اکوسیستم:

استاندارد OpenAPI Specification: یه استاندارد باز برای توصیف APIها که اکثر ابزارهای مدرن از اون استفاده می‌کنن. و تقریبا مهم‌ترین استاندارد این حوزه است.

ابزارهای Swagger UI / Swagger Editor: ابزاری برای نمایش مستندات API به صورت تعاملی (از OpenAPI به خوبی پشتیبانی می‌کنه)

ابزار Redoc: یه ابزار خوب برای ارائه مستندات API سازگار با OpenAPI به صورت آنلاین.

پلتفرم Postman: علاوه بر تست API، مستندات خوبی از APIها ایجاد می‌کنه، فضای مناسبی برای اشتراک API + Doc + Test + ... برای تیم‌ها و شرکت‌ها داره و کلا یک پلتفرم برای API سازمان است و محدود به یه تولز برای GET و POST نیست... پیشرو این داستانه و بعدتر Insomnia و ابزارهای مشابه هم با قوت و کاستی‌های خاص خودشون اومدن

* ابزارهایی مثل API Blueprint هم بودن که اهمیت یا استقبال زیادی نداشتن و به حاشیه رونده شدن.

برای گو: swaggo و go-swagger
برای پایتون: خود FastAPI به صورت ضمنی
برای دات‌نت: دقت کنید که دات‌نت در نسخه ۹ به بعد هم کمافی‌السابق OpenAPI رو پشتیبانی می‌کنه، بحث‌ها سر جایگزینی اون UI سابقی است که Swagger UI تولید می‌کرد. و جایگزین‌هایی برای تولید Swagger UI و Redoc و Scaler ارائه شده.

💬 نظر؟ تجربه؟ سوال؟

📌 درضمن، به‌زودی شیوه ارائه مطالب تغییر می‌کنه، توی وبلاگ خواهم نوشت که امکانات بهتری برای پیدا کردن مطالب و دسته‌بندی‌ها و تجربه مطالعه داره و اینجا اعلانش رو قرار خواهم داد. برای همین هم این کد کوچیک رو نوشتم تا از مطالب کانال تلگرامی خروجی Markdown بگیرم که سریع‌تر مطالب فعلی رو منتقل کنم... اگر ایده یا پیشنهاد یا نقدی دارید خوشحال می‌شم.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍113
✍️ مقایسه روش‌های نسخه‌بندی API

1️⃣روش URL Versioning
GET /v1/products HTTP/1.1
Host: api.example.com

ساده و واضح، نسخه‌بندی توی URL به راحتی قابل تشخیص و دیدنه. و پیاده‌سازیش خیلی ساده و مورد پشتیبانی اکثر فریم‌ورک‌هاست.

جاهایی که نرخ تغییرات زیاده، نگهداری و مدیریت دشوار می‌شه

2️⃣ روش Header Versioning
GET /products HTTP/1.1
Host: api.example.com
X-API-Version: 1


جداسازی نسخه‌بندی از URL، باعث می‌شه URL ثابت بمونه؛ و انعطاف‌پذیری بالاتر برای مدیریت نسخه‌بندی.
نیاز به تنظیمات اضافی در سمت کلاینت برای ارسال header. نیاز به دقت بیشتری برای مشاهده و شناسایی داره.

3️⃣ روش Media Type Versioning
GET /products HTTP/1.1
Host: api.example.com
Accept: application/vnd.myapi.v1+json

انطباق بالا با استانداردهای RESTful. و انعطاف‌پذیری توی انتخاب انواع خروجی (مثلاً تغییر application/xxx).
پیچیدگی توی تنظیم و پیکربندی. و ممکنه برای یه عده از برنامه‌نویس‌ها کمی گیج‌کننده باشه.
=======================
چطوری API هامون رو بدون نیاز به breaking changes توسعه بدیم؟

۱. روش Feature Flags
استفاده از feature flags این امکان رو میده که ویژگی‌های جدید رو به صورت تدریجی به کاربران عرضه کنیم و در صورت بروز مشکل، به سرعت اونها رو غیرفعال کنیم (توی محصولات بزرگ این روش خیلی مرسومه).

مثال:
زمان توسعه یک endpoint جدید، می‌تونید با اضافه کردن یک feature flag، به صورت تدریجی این ویژگی رو برای گروه‌های خاصی فعال کنید.

۲. روش API Gateway Transformations
با API Gateway می‌شه درخواست‌ها و پاسخ‌ها رو بین نسخه‌های مختلف API تغییر داد و این امکان رو می‌ده که نسخه‌های قدیمی API رو بدون مشکل پشتیبانی کنیم.

مثال:
فرض کنین نسخه‌ی جدید API ساختار پاسخ‌ها رو تغییر داده؛ با استفاده از API Gateway می‌تونیم داده‌های نسخه قدیمی رو به فرمت نسخه جدید تبدیل کنیم بدون اینکه نیاز به تغییر کدهای کلاینت داشته باشیم (البته خوبه این کار رو تا زمان ارتقاء نسخه‌های کلاینت دنبال کنیم و دایمی نباشه).

۳. روش Backward Compatibility
توسعه API به شیوه‌ای که تغییرات جدید باعث breaking change نسخه‌های قبلی نشه. برای این کار، معمولا:
- اضافه کردن فیلدهای جدید به داده‌های خروجی به جای تغییر یا حذف فیلدهای قدیمی.
- استفاده از ورژن‌بندی تدریجی (rollout) برای نسخه‌های جدید.

=======================

آقا/خانم... این داستان API یه موضوع حیاتیه. با استفاده از روش‌هایی مثل URL versioning، Header versioning و Media Type versioning می‌تونیم ساختار API رو بهینه کنیم. همچنین، به کمک تکنیک‌هایی مثل feature flags، API gateway transformations و حفظ backward compatibility، می‌تونیم تغییرات رو به صورت تدریجی اعمال کنیم بدون اینکه کاربران موجود با خطا مواجه بشن.

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

💬 سوال؟ نظر؟ تجربه؟

اگر موافقید تا اینجا API Design بس باشه، یه مدت تنوع بدیم...
Please open Telegram to view this post
VIEW IN TELEGRAM
👍106
This media is not supported in your browser
VIEW IN TELEGRAM
موضوع پست‌های بعدی رو حدس بزنید 😁
😁11🤣3
رویکرد جدید تست نرم‌افزار با ACH

متا یک رویکرد جدید (از جنبه‌هایی جدید) نسبت به تولید خودکار تست‌های نرم‌افزار اتخاذ کرده با ابزاری به اسم ACH.

🌱 این ACH چیه؟
توی متا، ابزاری به اسم Automated Compliance Hardening (ACH) داریم که توی تست نرم‌افزار کلی تحول ایجاد کرده. این سیستم، از مدل‌های زبان بزرگ (LLM) استفاده می‌کنه تا به روش «mutation-guided» تست‌هایی تولید کنه. به عبارت دیگه، ACH با وارد کردن خطاهای عمدی (که بهشون «mutants» می‌گیم) توی کد، دنبال این می‌گرده که آیا تست‌های موجود اون خطاها رو پیدا می‌کنن یا نه. مثلا، توی حوزه حریم خصوصی، ACH به صورت خودکار به دنبال اشکالات مرتبط با حریم خصوصی می‌گرده و مطمئن می‌شه که این خطاها به سیستم‌های ما راه پیدا نکنن. نتیجه؟ کدهای ما محکم‌تر می‌شن و ریسک حریم خصوصی کمتر می‌شه.

همچنین ACH تست‌های واحد (unit tests) می‌سازه که هدفشون شکار اون خطاهای مشخصه. جالب‌تر اینکه، ما فقط نیاز داریم به صورت متنی و ساده توضیح بدیم که دنبال چه نوع خطاهایی هستیم؛ حتی اگه توضیحاتمون ناقص یا حتی یه کم متناقض باشه، ACH باز هم تست‌هایی تولید می‌کنه که تضمین می‌کنه اون خطاها رو پیدا می‌کنن.

در گذشته، بیشتر روش‌های تست اتوماتیک فقط روی افزایش پوشش کد متمرکز بودن، ولی افزایش پوشش کد همیشه تضمین نمی‌کنه که خطاها رو پیدا کنیم. ACH از این سنت فاصله می‌گیره و به‌طور خاص خطاها رو هدف قرار می‌ده، البته غالباً باعث افزایش پوشش هم می‌شه. یه نکته خوب اینه که ACH بر پایه اصول Assured LLM-based Software Engineering ساخته شده، به این معنا که تضمین داره تست‌های تولید شده واقعاً اون خطاها رو شکار می‌کنن.

چطوری کار می‌کنه؟
تکنیک‌های mutation testing مدتهاست که استفاده می‌شدن؛ یعنی با ایجاد خطاهای عمدی (mutants) توی کد (البته به نحوی که از تولید نهایی دور بمونن) می‌خوایم ببینیم که آیا تست‌ها این تغییرات رو می‌گیرن یا نه. مشکل این روش‌ها این بود که این mutants اغلب واقع‌گرایانه نبودن و کماکان نیاز به نوشتن دستی تست‌ها توسط انسان وجود داشت.

ACH با استفاده از قابلیت‌های مدل‌های زبان بزرگ (LLM) به دو مشکل اصلی پایان می‌ده:

- تولید mutants‌هایی که واقعاً نمایانگر خطاهای واقعی باشن.
- تولید خودکار تست‌ها برای شکار اون خطاها.

مراحل کار ACH:

۱: توضیح خطا: شما توضیح می‌دی که دنبال چه نوع خطاهایی هستی.

۲: تولید خطاها: ACH براساس توضیحات، تعداد زیادی خطا تولید می‌کنه.

۳: تولید تست‌ها: سپس این خطاها رو به عنوان ورودی می‌گیره و تست‌هایی می‌سازه که مطمئن بشیم اون خطاها رو پیدا می‌کنن.

👁 چرا مهمه؟
فکر کنید متا با اون همه برنامه‌نویس و سیستم‌های مختلف، چطور باید مطمئن بشه که همه چیز درست کار می‌کنه و مخصوصاً مسائل مربوط به حریم خصوصی کاربرها رعایت میشه؟ (منظور از حریم خصوصی همونه که شما راجع به یه کوفتی حرف می‌زنید، ۲ دقیقه بعدش اینستاگرام، پست و تبلیغ در مورد اون کوفت نمایش می‌ده 😁) اینجاست که ACH میاد به کمک!!:

- با استفاده از LLM‌ها، می‌تونه خیلی سریع و دقیق باگ تولید کنه
- تست‌های متناسب با اون باگ‌ها رو می‌نویسه
- تضمین می‌کنه که تست‌ها واقعاً اون باگ‌ها رو پیدا می‌کنن

🥸 کجا استفاده شده؟
متا این سیستم رو روی پلتفرم‌های مختلفش مثل:
- فیسبوک
- اینستاگرام 🤬
- واتس‌اپ
- مسنجر

تست کرده و نتایج خیلی خوبی گرفته.

🚀 آینده چی میشه؟
تیم متا می‌خواد این تکنولوژی رو گسترش بده و به جاهای بیشتری ببره. هدفشون اینه که:
- ارزیابی ریسک‌ها رو ساده‌تر کنن
- فشار ذهنی روی برنامه‌نویس‌ها رو کم کنن
- یه اکوسیستم امن‌تر برای همه بسازن

خلاصه اینکه ACH نشون میده چطور هوش مصنوعی می‌تونه به کمک برنامه‌نویس‌ها بیاد و کارهای سخت و وقت‌گیر رو براشون آسون‌تر کنه. مقاله هم روش دادن که می‌تونید عمیق‌تر مطالعه کنید...

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

با اینکه ۲ تا موضوع توی همین کانال و کلا دنیای توسعه‌ نرم‌افزار فارسی زبان، خیلی نامحبوبه، یکی مستندسازی یکی تست، ولی اگر موافق باشین چند تا پست در موردش گپ بزنیم؟ (بزنیم: ⚙️ | نزنیم: 🤪، اگر نزنیم، شما بگید تا اگر بلد بودم بریم سراغش... 😉)
Please open Telegram to view this post
VIEW IN TELEGRAM
13
🐊 چرا تست نمی‌کنیم؟ آنچه در کتاب‌های آموزش تست گفته نمی‌شود!

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

ولی در عمل چی می‌شه؟
عهد کردم که دگر می نخورم در همه عمر

بجز از امشب و فردا شب و شبهای دگر


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

«تست، مقدم بر تکنیک، یه فرهنگه...»

این رو دقیقا از زمانیکه ALM رو شروع به تدریس کردم هم به عنوان اولین جمله هر بار صحبت در موردش ذکر کردم...

یعنی چی که تست یک فرهنگه؟
با مثال می‌گم: تا حالا شده یه مکانیک یا لوله‌کش یا برقکار، کاری رو براتون انجام بدن ولی بعد از رفتنشون ببینید مشکل حل نشده؟ تا حالا دیدید بعضی از همین مشاغل، قبل از اینکه کار رو بهتون تحویل بدن ده جور وارسی و تستش می‌کنن؟ (که احتمالا از این دست استادکارها کم دیدیم و همیشه از دیگران در مورد چنین افرادی پرس‌وجو می‌کنیم)

تا حالا چقدر در مورد ساختمان، خودرو، پروژه سدسازی! ریلی، جاده و... دیدیم و شنیدیم و خوندیم که بدون تست کامل و بر اساس اینکه ظاهر اون چیز به گمانشون درست بوده، رونمایی یا عرضه کردن و بعد داد همه دراومده یا حتی مصیبت به وجود آورده؟

نرم‌افزار هم فراتر از این‌ها نیست! ما هم بخشی از همین جامعه هستیم... بنا به «هر» دلیلی، امروز ما ایرانی‌ها، کمتر به کنترل کیفیت بها می‌دیم... چون برامون پیش‌فرض شده که عقوبتی نداره که... فوقش باگ پیدا می‌شه میریم حلش می‌کنیم... همین نگاه همه جا هست و فقط به خودمون نگیریم. مثلا فوقش این سیاست مالی در سطح کشور موجب دلار ۹۴ هزار تومنی می‌شه! فوقش این پراید کلی آدم رو به کشتن می‌ده... اساسا در فرهنگ ما بازبینی و تست کردن طرح، تست کردن اجرا، خالی از اهمیته.

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

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

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

*️⃣ این‌هایی که عرض کردم به معنی صفر و صد نیست، به معنی برتری نژادی نیست، بین همه ملیت‌ها آدم دقیق و آدم غیردقیق وجود داره، صحبتم سر شاخص بودن و زیاد دیده شدن یک سری عادات و فرهنگ‌ها بین ملیت‌های متفاوته و «تجربه شخصی من است و کاملا محتمل به خطا».

این‌ها رو گفتم تا به عنوان بخش نخست چند پستی که در مورد تست خواهم نوشت، متذکر شم، عادات و فرهنگی ما در زندگی روزمره، در جامعه خیلی روی رفتارهای کاری و تخصصی ما اثرگذاره. من تلاش خواهم کرد پیشنهاداتم رو قبل از اینکه در مورد Fact و Theory نویسی و E2E و Cucumber در BDD بنویسم، در مورد چگونگی ایجاد فرهنگ و عادت‌سازی تست بنویسم... اگر با این رویه موافق بودید: ⚙️ و مثل همیشه از نظرات و پیشنهاداتتون یاد می‌گیرم 😊

عکس هم مربوط به سال ۲۰۰۹ و در میان تایوانی‌هاست...
Please open Telegram to view this post
VIEW IN TELEGRAM
209👍5
🐊 تست نرم‌افزار، شروع...

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

🤓 چطوری شروع کنیم؟
آیا کسی که عادت به ورزش نداره، ولو اینکه دانش‌آموخته‌ی رشته تربیت‌بدنی باشه، می‌تونه با روزی ۵ کیلومتر دویدن شروع کنه؟ خیر. تست‌نویسی هم نیاز به مقدمات و آمادگی داره. خود تست‌نویسی، مقدمات و آمادگی، نیست! بلکه فکر کردن به چگونه تست کردن، مقدمه است.

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

لذا قبل از اینکه چیزی رو تولید کنیم اول فکر کنیم که چه احتمالاتی برای اون بخشی که می‌خوایم توسعه بدیم مترتبه؟ بعد از اینکه یک لیست تهیه کردیم (حالا توی ذهنمون یا به شکل بهترش روی کاغذ یه شکل باز هم بهترش روی نرم‌افزار) بشینیم اولویت بدیم که کدوم احتمال رخداد و سطح اثرگذاری بالاتری داره؛ و فرض کنیم قراره فقط ۳ یا ۵ تست بنویسیم و بابت هر ایرادی که پیدا بشه پولی بپردازیم یا سوزنی پشت دستمون بخوره یا فلفلی توی دهنمون بریزن یا بی‌حیثیتمون کنن (منظورم اینه که جدی بگیریمش 😁)

با تعداد تست کم، ولی مهم تمرین کنیم! بله؛ با ۱ یا ۳ یا ۵ تست نوشتن، درسته که شما به coverage متوسط هم نمی‌رسید، ولی درست مثل با یک بارفیکس شروع کردنه... اگه عادت شه، اون وقت به ۳ تا و ۵ تا و ۱۰ تا و... هم می‌رسه. دقت کنید دوباره می‌گم، خودمون رو گول نزنیم، تست مزخرف و بدیهی نوشتن نه یکیش ارزشمنده نه میلیان‌ها میلیانش... این دوره‌ای که قراره خودتون رو عادت بدید و فرهنگ‌سازی کنید، مهم‌ترین چیز، تمرین و ممارست است، سر جدتون شوآف و توهم TDD و... ۴۰ روز به تعویق بندازین.

تعداد تست کم، ولی با اهمیت و اولویت بالا (اگر بلدید ولی عادت به تست‌نویسی ندارید، پیشنهاد من بین ۳ تا ۵ تا است و بس. اگر علاوه بر عادت نداشتن، دانش هم ندارید، فقط ۱) سنگ بزرگ نشونه نزدنه.

ممارست، و تمرین و یادگیری مداوم، رمز پیشرفته.

تویوتا سال در دهه ۱۹۳۰ و ۱۹۴۰ با تولیدات ساده، بعضا الهام‌گرفته یا مهندسی معکوس و... از فورد و شورولت شروع کرد تا بتونه ۱۹۵۰ کار طراحی اولین خودرو تماما تویوتا رو ادامه بده و تا امروز دست از ممارست و بهبود «تدریجی، ولی مداوم» برنداشته. هر اصلاحی من‌جمله «تست‌محور نوشتن نرم‌افزار» از این قاعده خارج نیست...

* عکس: میز آقای Shoichiro Toyoda در موزه لومن، در شهر لاهه، هلند

مطلب بعدی: TDD چیه و چجوری شروع کنیم و ترمینولوژی‌اش؟

مطالب بعدترش: روش‌های شبیه‌سازی وابستگی‌ها؛ جاسازی تست در CI/CD، تست‌های E2E و ، Integration، تست‌های Behavior و کاربرد ابزارهای هوش‌مصنوعی در تست...

💬 اگه یادتون رفته، یادآوری کنم که نظر و پیشنهاد بدید 😁
Please open Telegram to view this post
VIEW IN TELEGRAM
👏1362
🐊 تست یعنی چی؟!

شاید با دیدن این تیتر بگید: «چه سوال بدیهی و ساده‌ای؟! چرا داره بدیهیات رو توضیح می‌ده!»

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

تست، یعنی «در صورت وقوع الف، حتما نتیجه‌ی ب باید حاصل بشه؛ نه یک کلمه بیشتر نه یک کلمه کمتر»

- این‌که کد رو اجرا کنیم و خطا نده؛ تست نیست.

- اینکه دیتا بفرستیم سمت دیتابیس و ذخیره بشه، باز هم تست نیست!
بیاید همینو تدقیق کنیم:
۱: من جدول دانش‌آموزان رو در دیتابیس دارم که ۱۰ عدد رکورد دارد.
۲: رکوردی با مقادیر [امین، مصباحی، ۱۰ ساله] درج می‌کنم.
۳: چک می‌کنم تا تعداد رکوردها حتما برابر با ۱۱ باشه، تعداد دانش‌آموزانی که امین مصباحی و ۱۰ ساله باشن حتما برابر با ۱ باشد.

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

تست نوشتن الزاما به معنی TDD یا Test Driven Development نیست! حالا بگیم TDD چیه تا بگیم چرا الزامی نیست.
وقتی قبل از اینکه خود کد نوشته بشه، اول تستش رو بنویسیم و بعد مراحلی رو طی کنیم، میشه TDD. اولین سوال: وقتی کد رو ننوشتم، تست چی؟ کشک چی؟ آها. یه مثال ساده، قراره تا متد CreateUser رو بنویسیم:
۱: می‌ریم توی تست‌دونی، یه تست می‌نویسیم به اسم CreateUser_ShouldCreateUser_WhenDataIsValid.
۲: داخل این تست مشخص می‌کنیم که اگه ورودی‌های معتبر داده بشه، خروجی باید یه آبجکت کاربر با اطلاعات دقیق ورودی باشه.
۳: حالا وقتی تست رو اجرا می‌کنیم، چون کد رو ننوشته‌ایم، تست شکست می‌خوره؛ این دقیقاً نشونه اینه که باید برگردیم و کد رو بنویسیم.

اینجاست که مفهوم TDD شکل می‌گیره: یعنی اول شکست، بعد کد رو می‌نویسیم تا اون تست شکست‌خورده پاس بشه، بعد توی گام سوم بهینه‌اش می‌کنیم. هدف از نوشتن تست قبل از کد اینه که به ما کمک کنه دقیقاً مشخص کنیم «انتظارمون» از عملکرد متد چیه. وقتی تست پاس بشه، دیگه مطمئنیم که کدمون دقیقاً همون رفتاری رو داره که می‌خوایم.

حالا برگردیم سر داستان اول، مگه ما همیشه از زمین خالی شروع می‌کنیم که اول تستش رو بنویسیم بعد کد رو؟ اصلا مگه TDD روش مناسب همه تیم‌هاست؟
جواب: TDD خیلی خوبه، ولی الزامی نیست، برای همه تیم‌ها هم شدنی نیست. تست نوشتن به معنی الزما TDD بودن نیست. یعنی شما می‌تونید اول کد نوشته باشید بعد تستش رو بنویسید، یا برای کدهایی که در گذشته نوشته شده تست بنویسید، حتی نه الزاما برای همه کدها، بلکه برای جاهایی که «مهم‌ و مستعد رفتار غیر مطلوب» است (الزاما نباید خطا یا Exception/Error رخ بده، بلگه «هر» رفتاری به جز «اونچه که ما انتظار داریم» یعنی مستعد رفتار نامطلوب؛ مثلا محاسبه فاکتور با ارقام اشتباه، Error نیست، بلکه رفتاری است که مطلوب ما نیست)

در پست بعد اصطلاحات تست رو توضیح می‌دم و بعدش می‌ریم سراغ کد.
اگر دوست داشتید تا کمی بیشتر بدونید شاید خوندن این مطلب بد نباشه تا تفاوت انواع رویه‌ها رو آشنا شید.

* ایمان عزیز محبت داشت و پیام داد تا توی تولید محتوای بخش تست مشارکت کنه، و من هم خیلی خوشحال شدم که بشه با مشارکت ایمان، موضوع تست رو بهتر پیش ببریم. لذا به گزینه‌هایی مثل جلسه ویدیویی مشترک، نوشتار پست‌های مربوط به تست و شاید منتورشیپ ۳ تا ۵ نفر به مدت یک ماه تا رسیدن به مهارت نسبی روی unit test و end-to-end test و... فکر کنیم 🥳


💬 مثل همیشه: نظر، پیشنهاد، سوال...
در ضمن توی کامنت بگید چه زبانی براتون کاربردی‌تره برای مثال‌های تست؟ (#C یا پایتون یا گو؟)
Please open Telegram to view this post
VIEW IN TELEGRAM
124👍1🔥1
روز مهندس….pdf
80.2 KB
⚙️ روز مهندس...
چند خطی رو در مورد روز مهندس نوشتم، اگر دوست داشتید بخونید 😊🙏🌱

این پست هم شاید بی‌ربط به امروز نباشه.
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍2
#موقت
ترمینولوژی تست که توی پست قبل قولش رو داده بودم در حال انجامه. شکل نهایی دو پوستر فارسی خواهد بود+ فرمت مارک‌دان به‌صورت کدباز؛ اولی ترمینولوژی عام تست، شامل توضیح کوتاه و یکی دو خطی هر مفهوم. دومی هم کاغذ تقلب برای xunit.
با اینکه به صورت کلی، نوشتن مطالب کانال، همیشه tech-midnight یا tech-before-sleep بوده 🌛(و schedule میشه که صبح منتشر شه) ولی هم انجامش کمی زمانبره و هم من این شب‌ها کمتر فرصت دارم برای پرداختن بهش، که امیدوارم به زودی فرصت بشه.

علی‌الحساب شاید برای مدتی، مطالب کوتاه‌تر و با تناوب کمتر داشته باشیم... 😉
ارادتمند
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍432
This media is not supported in your browser
VIEW IN TELEGRAM
چند روزی بیشتر از عرضه نسخه نهایی Aspire 9.1 نمی‌گذره، حالا بیاین ببینیم قراره توی vNext چی اضافه بشه 🚀😍

قابلیت جدید resource graph قراره بیاد که نقشه ارتباطات رو ببینیم و قطعا توی پروژه‌های بزرگ و مایکروسرویسی خیلی کمک می‌کنه...
😍62