<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های حمیدرضا مهدوی‌پناه</title>
        <link>https://virgool.io/feed/@mahdavipanah</link>
        <description>مهندس نرم‌افزار هستم و به عنوان Senior Software Engineer مشغول به کارم. به جاوااسکریپت، پایتون، دیتابیس‌ها و طراحی و معماری نرم‌افزار علاقه زیادی دارم. وبلاگ‌هام: yavarjs.ir و hamidreza.tech</description>
        <language>fa</language>
        <pubDate>2026-04-14 18:37:42</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/2800/avatar/j41WPL.jpg?height=120&amp;width=120</url>
            <title>حمیدرضا مهدوی‌پناه</title>
            <link>https://virgool.io/@mahdavipanah</link>
        </image>

                    <item>
                <title>“من” در مقابل “تو” در رابط کاربری</title>
                <link>https://virgool.io/@mahdavipanah/%D9%85%D9%86-%D8%AF%D8%B1-%D9%85%D9%82%D8%A7%D8%A8%D9%84-%D8%AA%D9%88-%D8%AF%D8%B1-%D8%B1%D8%A7%D8%A8%D8%B7-%DA%A9%D8%A7%D8%B1%D8%A8%D8%B1%DB%8C-thd7dpm0t3el</link>
                <description>ترجمه‌ای از مقاله‌ اصلی: https://adamsilver.io/blog/your-vs-my-in-user-interfaces/وقتی می‌خواهیم به چیزهای کاربر اشاره کنیم، بهتر است کدام را بگوییم؟حساب من یا حساب شما؟سفارش‌های من یا سفارش‌های شما؟پرونده‌های من یا پرونده‌های شما؟در واقع خیلی وقت‌ها لازم نیست هیچ پیشوندی استفاده شود. مثلا:حسابسفارش‌هاپرونده‌هامثل آمازون که فقط می‌نویسد Account یا Orders چون مشخص است که منظور حساب و سفارش‌های کاربر است.مشکل “من”فرض کنید در منو نوشته باشد “پرونده‌های من” و “همه پرونده‌ها”. در ظاهر درست است.اما مشکل وقتی پیش می‌آید که جای دیگری بخواهیم به این صفحه اشاره کنیم.مثلا در یک ایمیل یا راهنمایی اگر بگوییم: «برو به پرونده‌های من»، عجیب به نظر می‌رسد. چون کاربر فکر می‌کند باید برود سراغ پرونده‌های منِ نویسنده، نه مال خودش.در حالی که اگر UI از کلمه “پرونده‌های شما” استفاده کرده باشد، پشتیبان یا راهنما هم به راحتی می‌تواند بگوید: «برو به پرونده‌های خودت».اما چه زمانی “من” درست است؟وقتی کاربر دارد با ما حرف می‌زند. مثلا در یک فرم:«آیا می‌خواهید عکس پروفایل خود را به اشتراک بگذارید؟»گزینه‌ها:بله، عکس پروفایل من را به اشتراک بگذارنه، عکس پروفایل من را به اشتراک نگذاراینجا اگر “تو” استفاده کنیم، عجیب می‌شود؛ چون به نظر می‌آید کاربر دارد به سیستم دستور می‌دهد عکس کسی دیگر را به اشتراک بگذارد.خلاصهوقتی ما با کاربر صحبت می‌کنیم → از “شما” استفاده کنیم.وقتی کاربر با ما صحبت می‌کند → از “من” استفاده کند.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Tue, 16 Sep 2025 15:41:49 +0330</pubDate>
            </item>
                    <item>
                <title>استقرار سریع و ساده اپلیکیشن NestJS روی Vercel</title>
                <link>https://virgool.io/yavarjs/%D8%A7%D8%B3%D8%AA%D9%82%D8%B1%D8%A7%D8%B1-%D8%B3%D8%B1%DB%8C%D8%B9-%D9%88-%D8%B3%D8%A7%D8%AF%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-nestjs-%D8%B1%D9%88%DB%8C-vercel-baapvdafggov</link>
                <description>بر اساس راهنمای رسمی Vercel و روش به‌روز🔔🔔🔔 بخاطر باگ‌های زیاد ویرگول در نمایش کد در مقاله، پیشنهاد میکنم مطلب رو از اینجا مطالعه کنید: لینک مقاله در وبلاگ yavarjs.irاین راهنما برای کسانی که از Express adapter استفاده می‌کنند مفید است. برای اپلیکیشن‌های NestJS که از Fastify adapter استفاده می‌کنند، لینک‌های زیر ممکن است کمک‌کننده باشد:Fastify Guide for Serverless on VercelFastify Examples on GitHub🚀 شما می‌توانید کد کامل مطرح‌شده در این مقاله را در این مخزن GitHub پیدا کنید: nestjs-on-vercelپشتیبانی Vercel از Express AppsVercel ویژگی مناسبی برای استقرار Express app ارائه می‌دهد که شامل مراحل زیر است:expose کردن شیء Express app در یک API.تعریف یک rewrite rule که تمام ترافیک ورودی را به این API هدایت کند.من برای استقرار NestJS از راهنمای رسمی Vercel برای Express استفاده کردم، به این صورت که شیء Express app زیربنایی NestJS را اکسپوز کردم.مرحله ۱ - ساخت یک اپلیکیشن NestJSاگر قبلاً یک اپ NestJS دارید، می‌توانید این مرحله را رد کنید.نصب NestJS و ایجاد اپ جدید:nest new my-appمرحله ۲ - نصب بسته‌های NPM موردنیازnpm install express @nestjs/platform-express
npm install -D @types/expressمرحله ۳ - ساخت فایل src/AppFactory.tsاین فایل به‌عنوان یک ماژول واحد عمل می‌کند که تمامی پیکربندی‌های ضروری اپلیکیشن NestJS را مدیریت کرده و هم NestJS app و هم شیء Express app زیربنایی آن را اکسپورت می‌کند.ساخت فایل AppFactory.ts در پوشه src:import { ExpressAdapter } from &amp;quot@nestjs/platform-express&amp;quotimport { NestFactory } from &amp;quot@nestjs/core&amp;quot
import express, { Request, Response } from &amp;quotexpress&amp;quot
import { Express } from &amp;quotexpress&amp;quot
import { INestApplication } from &amp;quot@nestjs/common&amp;quot
import { AppModule } from &amp;quot./app.module.js&amp;quot

export class AppFactory {
  static create(): {
    appPromise: Promise&lt;INestApplication&lt;any&gt;&gt;
    expressApp: Express
  } {
    const expressApp = express()
    const adapter = new ExpressAdapter(expressApp)
   const appPromise = NestFactory.create(AppModule, adapter)
    appPromise
      .then((app) =&gt; {
        app.enableCors({
          exposedHeaders: &amp;quot*&amp;quot,        })
        app.init()
      })
      .catch((err) =&gt; {
        throw err
      })
    expressApp.use((req: Request, res: Response, next) =&gt; {
      appPromise
        .then(async (app) =&gt; {
          await app.init()
         next()
    })
        .catch((err) =&gt; next(err))
    })
    return { appPromise, expressApp }
  }
}مرحله ۴ - ویرایش فایل src/main.tsبه‌طور پیش‌فرض، فایل src/main.ts نقطه ورودی اپلیکیشن است. این فایل را تغییر دهید تا تنها متد listen را فراخوانی کند:import { AppFactory } from &amp;quot./AppFactory.js&amp;quot

async function bootstrap() {
  const { appPromise } = AppFactory.create()
  const app = await appPromise

  await app.listen(process.env.PORT ?? 3000)
}
bootstrap()مرحله ۵ - افزودن فایل api/index.tsVercel به‌طور پیش‌فرض هر فانکشنی که در پوشه api قرار دارد را اجرا می‌کند. بنابراین، یک فایل در این پوشه ایجاد کنید که شیء Express app را اکسپورت کند:/**
 * This file exports Express instance for specifically for the deployment of the app on Vercel. */
import { AppFactory } from &amp;quot../src/AppFactory.js&amp;quot
export default AppFactory.create().expressAppمرحله ۶ - افزودن فایل vercel.jsonدر دایرکتوری روت پروژه یک فایل vercel.json ایجاد کنید تا Vercel را پیکربندی کنید:{  
  &amp;quotversion&amp;quot: 2,
&amp;quotbuildCommand&amp;quot: &amp;quotnpm run build&amp;quot,
  &amp;quotoutputDirectory&amp;quot: &amp;quot.&amp;quot,
  &amp;quotrewrites&amp;quot: [
    {
      &amp;quotsource&amp;quot: &amp;quot/(.*)&amp;quot,
      &amp;quotdestination&amp;quot: &amp;quot/api&amp;quot
    }
  ]
}مرحله ۷ - ایجاد پروژه روی Vercelتبریک 🎉! تقریباً تمام شد. حالا یک مخزن Git ایجاد کنید و کدتان را در آن push کنید. سپس وارد حساب Vercel خود شوید، یک پروژه جدید ایجاد کنید و مخزن Git را ایمپورت کنید. همچنین می‌توانید از مخزن GitHub مثال این مقاله استفاده کنید.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Wed, 27 Nov 2024 14:12:26 +0330</pubDate>
            </item>
                    <item>
                <title>مشکلات URL و URLSearchParams</title>
                <link>https://virgool.io/yavarjs/%D9%85%D8%B4%DA%A9%D9%84%D8%A7%D8%AA-url-%D9%88-urlsearchparams-l6haewt9ozmx</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: https://yavarjs.ir/posts/url-urlsearchparamsبررسی تفاوت‌های ریزی که حین کار با URLها باعث به وجود آمدن باگ‌های غیرمنتظره می‌شود.همه چیز از یک باگ شروع شدکار با URL‌ها در JavaScript و Node.js باید ساده باشد، اما یک باگ اخیر در پروژه ما، من را به دنیایی از جزئیات پیچیده در API‌های URL و URLSearchParams برد. در این پست، به بررسی این جزئیات و مشکلات احتمالی آن‌ها در کد و نحوه اجتناب از آن‌ها خواهیم پرداخت.مشکل: مدیریت URL با Axiosما این مشکل را هنگام تولید URL‌ها و اضافه کردن امضا‌های هش به آن‌ها پیدا کردیم. پارامترهای کوئری به طور یک‌پارچه percent-encode نمی‌شدند که منجر به رفتار غیرمنتظره و امضا‌های هش اشتباه می‌شد.واضح شد که تعامل بین اشیای URL و URLSearchParams نیاز به دقت بیشتری دارد.مشکل شماره 1: تفاوت بین URL.search و ()URLSearchParams.toStringاولین شگفتی تفاوت بین URL.search و ()URLSearchParams.toString بود.هنگام استفاده از searchParams. برای تغییر URL، دقت کنید، زیرا طبق مشخصات WHATWG ، شیء URLSearchParams از قوانین متفاوتی برای تعیین اینکه کدام کاراکترها باید percent-encode شوند استفاده می‌کند. به عنوان مثال، شیء URL کاراکتر تیلد ASCII (~) را percent-encode نمی‌کند، در حالی که URLSearchParams همیشه آن را encode می‌کند.// Example 1
const url = new URL(&amp;quothttps://example.com?param=foo bar&amp;quot)
console.log(url.search) // prints param=foo%20bar
console.log(url.searchParams.toString()) // prints ?param=foo+bar

// Example 2
const myURL = new URL(&amp;quothttps://example.org/abc?foo=~bar&amp;quot)
console.log(myURL.search) // prints ?foo=~bar
// Modify the URL via searchParams...
myURL.searchParams.sort()
console.log(myURL.search) // prints ?foo=%7Ebarدر پروژه ما، لازم بود به طور صریح ()url.search = url.searchParams.toString را دوباره اختصاص دهیم تا اطمینان حاصل شود که رشته کوئری به طور یکنواخت encode شده است.مشکل شماره 2: چالش علامت بعلاوهیکی دیگر از نکات ظریف این است که چگونه URLSearchParams با کاراکترهای + برخورد می‌کند. به طور پیش‌فرض، URLSearchParams کاراکتر + را به عنوان فضای خالی تفسیر می‌کند که ممکن است هنگام encode داده‌های باینری یا رشته‌های Base64 منجر به خرابی داده‌ها شود.const params = new URLSearchParams(&amp;quotbin=E+AXQB+A&amp;quot)
console.log(params.get(&amp;quotbin&amp;quot)) // &amp;quotE AXQB A&amp;quotیک راه حل این است که قبل از افزودن مقادیر به URLSearchParams از encodeURIComponent استفاده کنید:params.append(&amp;quotbin&amp;quot, encodeURIComponent(&amp;quotE+AXQB+A&amp;quot))جزئیات بیشتر در مستندات MDN موجود است.مشکل شماره 3: URLSearchParams.get در مقابل ()URLSearchParams.toStringیکی دیگر از جزئیات ظریف زمانی به وجود می‌آید که خروجی‌های URLSearchParams.get و URLSearchParams.toString را مقایسه می‌کنید. به عنوان مثال:const params = new URLSearchParams(&amp;quot?key=value&amp;key=other&amp;quot)
console.log(params.get(&amp;quotkey&amp;quot)) // &amp;quotvalue&amp;quot (اولین مورد)
console.log(params.toString()) // &amp;quotkey=value&amp;key=other&amp;quot (همه موارد سریالایز شده)در سناریوهای چند مقداری، get فقط اولین مقدار را برمی‌گرداند، در حالی که toString همه را سریالایز می‌کند.راه‌حل در کد مادر پروژه ما، مشکل را با اختصاص صریح search حل کردیم:url.search = url.searchParams.toString()
url.searchParams.set(
  &amp;quothash&amp;quot,
  cryptography.createSha256HmacBase64UrlSafe(url.href, SECRET_KEY ?? &amp;quot&amp;quot)
)این اطمینان حاصل کرد که تمام پارامترهای کوئری قبل از اضافه کردن مقدار hash به درستی encode شده بودند.ماژول querystring در Node.jsرابط کاربری WHATWG URLSearchParams و ماژول querystring هدف مشابهی دارند، اما هدف ماژول querystring عمومی‌تر است، زیرا امکان سفارشی‌سازی کاراکترهای جداکننده (&amp; و =) را فراهم می‌کند. از سوی دیگر، API URLSearchParams به طور خاص برای رشته‌های کوئری URL طراحی شده است.ماژول querystring از URLSearchParams کارآمدتر است اما یک API استاندارد نیست. از URLSearchParams زمانی استفاده کنید که عملکرد بحرانی نیست یا وقتی سازگاری با کد مرورگر مطلوب است.هنگام استفاده از URLSearchParams برخلاف ماژول querystring، کلیدهای تکراری به صورت آرایه مجاز نیستند. آرایه‌ها با استفاده از ()array.toString سریالایز می‌شوند که به سادگی همه عناصر آرایه را با کاما جدا می‌کند.const params = new URLSearchParams({
  user: &amp;quotabc&amp;quot,
  query: [&amp;quotfirst&amp;quot, &amp;quotsecond&amp;quot],
})
console.log(params.getAll(&amp;quotquery&amp;quot))
// Prints [ &#039;first,second&#039; ]
console.log(params.toString())
// Prints &#039;user=abc&amp;query=first%2Csecond&#039;با ماژول querystring، رشته کوئری &#x27;foo=bar&amp;abc=xyz&amp;abc=123&#x27; به این صورت پارس می‌شود:{
  &amp;quotfoo&amp;quot: &amp;quotbar&amp;quot,
  &amp;quotabc&amp;quot: [&amp;quotxyz&amp;quot, &amp;quot123&amp;quot]
}نکات کلیدیهنگام استفاده از URLSearchParams به نحوه مدیریت کاراکترهای خاص (مانند ~) و فضاهای خالی توجه کنید. در صورت نیاز از encodeURIComponent استفاده کنید.تفاوت بین URL.search، URLSearchParams.get و URLSearchParams.toString را برای جلوگیری از رفتار غیرمنتظره درک کنید.در Node.js از ماژول querystring استفاده کنید اگر می‌خواهید پارامترهای کوئری تکراری را به عنوان یک آرایه پارس کنید.منبع: Pitfalls of URL and URLSearchParams in JavaScript از وبلاگ Software Alchemist</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Fri, 22 Nov 2024 22:42:05 +0330</pubDate>
            </item>
                    <item>
                <title>رفع خطای MongoDB هنگام راه‌اندازی با Homebrew روی macOS</title>
                <link>https://virgool.io/@mahdavipanah/%D8%B1%D9%81%D8%B9-%D8%AE%D8%B7%D8%A7%DB%8C-mongodb-%D9%87%D9%86%DA%AF%D8%A7%D9%85-%D8%B1%D8%A7%D9%87-%D8%A7%D9%86%D8%AF%D8%A7%D8%B2%DB%8C-%D8%A8%D8%A7-homebrew-%D8%B1%D9%88%DB%8C-macos-kgvyposn0tzd</link>
                <description>چگونه سرویس mongodb-community را با Homebrew روی macOS با اصلاح دسترسی‌ها اجرا کنیملینک مطلب به انگلیسی در وبلاگ hamidreza.techمقدمههنگام نصب نسخه‌ی Community از MongoDB روی مک‌بوک خودم با استفاده از Homebrew (مستندات رسمی MongoDB)، با مشکلی مواجه شدم: سرویس mongodb-community به نظر می‌رسید که با موفقیت شروع به کار کرده، اما وقتی وضعیت آن را بررسی کردم به صورت خطا نمایش داده شد. اگر شما هم با همین مشکل مواجه هستید، این راهنما می‌تواند به شما کمک کند.مشکلپس از اجرای دستور زیر:brew services start mongodb-communityپیام تأیید دریافت کردم. با این حال، وقتی وضعیت سرویس را بررسی کردم:brew services listاین نتیجه نمایش داده شد:Name              Status  User Plist
mongodb-community errorفایل لاگ MongoDB (/usr/local/var/log/mongodb/mongo.log) شامل هشدارهایی بود:اجرای MongoDB به عنوان کاربر root:&quot;You are running this process as the root user, which is not recommended&quot;دریافت سیگنال توقف:&quot;Received signal&quot;,&quot;attr&quot;:{&quot;signal&quot;:15,&quot;error&quot;:&quot;Terminated: 15&quot;}}این هشدارها نشان می‌داد که MongoDB به عنوان کاربر root اجرا شده است، که این می‌تواند باعث مشکلات دسترسی و توقف سرویس شود.راه‌حلمشکل اصلی مربوط به مالکیت نادرست دایرکتوری‌های داده و لاگ MongoDB بود. در اینجا مراحل رفع این مشکل آمده است:مراحل:توقف سرویس MongoDB:brew services stop mongodb-communityمتوقف کردن فرآیندهای در حال اجرای MongoDB:pkill -f mongodتغییر مالکیت دایرکتوری‌های MongoDB:sudo chown -R $(whoami) /usr/local/var/mongodbsudo chown -R $(whoami) /usr/local/var/log/mongodbبررسی مالکیت دایرکتوری‌ها: ls -ld /usr/local/var/mongodbls -ld /usr/local/var/log/mongodbاطمینان حاصل کنید که نام کاربری شما به عنوان مالک نمایش داده شود.شروع سرویس MongoDB به عنوان کاربر خودتان:brew services start mongodb-communityبررسی وضعیت سرویس:brew services listاکنون سرویس باید به صورت started و تحت نام کاربری شما نمایش داده شود.تست اتصال به MongoDB:mongoshباید بتوانید به موفقیت به شل MongoDB متصل شوید.نتیجه‌گیریبا اصلاح دسترسی دایرکتوری‌ها و اطمینان از اجرای MongoDB تحت حساب کاربری خود (و نه به عنوان root)، می‌توانید خطای مرتبط با شروع سرویس mongodb-community با Homebrew روی macOS را برطرف کنید. به یاد داشته باشید که از استفاده از sudo با دستورات brew اجتناب کنید تا از مشکلات اینچنین جلوگیری شود.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Thu, 21 Nov 2024 23:34:57 +0330</pubDate>
            </item>
                    <item>
                <title>استفاده از @ و /* در کامنت‌های چندخطی جاوااسکریپت</title>
                <link>https://virgool.io/yavarjs/%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-%D9%88-%D8%AF%D8%B1-%DA%A9%D8%A7%D9%85%D9%86%D8%AA-%D9%87%D8%A7%DB%8C-%DA%86%D9%86%D8%AF%D8%AE%D8%B7%DB%8C-cxbelat230i8</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/special-symbols-multiline-commentsچجوری مشکل عدم امکان استفاده از علامت‌های خاص و رزرو‌ شده رو در کامنت‌های چندخطی (multiline comments) و JSDoc حل کنیم؟در حال اضافه کردن کامنت JSDoc به کدهام بودم که به یه مشکل اعصاب خوردن‌کن برخوردم. وقتی داشتم یک تیکه کد مثال رو توی کامنتم اضافه میکردم که داخلش از علامت /* استفاده میشد، کل بلوک کامنتم خراب میشد. دلیلش هم اینه که این علامت در جاوااسکریپت به عنوان تگ پایان کامنت‌های چندخطی استفاده میشه و وقتی داخل خود کامنت میخوای ازش استفاده کنی جاوااسکریپت فکر میکنه که داری بلوک کامنتت رو میبندی!این مشکل توی تیکه کد پایین قابل مشاهده‌است:/**
 * Checks whether two permission strings are semantically equal or not.
 *
 * @example
 * // returns true
 * equals(&#039;a/b/c/d/allow&#039;, &#039;a/b/c/*⁣/*/d/allow&#039;);
 *
 * @returns {boolean} True in case of equality and false otherwise.
*/
const equals = (first: string, second: string) =&gt; {
    // function&#039;s logic
    // ...

    return true; // or false
}این مشکل راه حل ساده و جالبی داره: باید یه کاراکتر جداکننده‌ی مخفی بین * و / قرار داده بشه! این کاراکتر یونیکد که اسمش هست Unicode invisible separator character باعث میشه که جاوااسکریپت علامت پایان کامنت رو تشخیص نده. این کاراکتر رو میتونید از اینجا کپی کنید.دقیقا مشابه همین مشکل وقتی به وجود میاد که بخواید از علامت @ داخل کامنت‌های JSDoc استفاده کنید. چون این علامت معنی خاصی برای JSDoc داره باعث خراب شدن داکیومنتی میشه که JSDoc تولید میکنه. به این تیکه کد یه نگاه بندازید:/**
 * A NestJS handler decorator that defines an access permission constraint and enforces it.
 *
 * @example
 * `⁣`⁣`ts
 * // the request only needs to be authenticated and doesn&#039;t need any specific permissions
 * @RequiresAccess()
 * Class MyController {}
 * `⁣`⁣`
 */
export const RequiresAccess = Reflector.createDecorator&lt;
  PermissionPathGen | PermissionPathGen[]
&gt;({
  transform(value) {
    return value == undefined ? MUST_BE_AUTHENTICATED : value
  },
})حل این مشکل هم مشابه قبلیه؛ کافیه یه کاراکتر جداکننده‌ی مخفی قبل از علامت @ قرار بدید.منبع: Using @ and */ symbols inside JS multiline comments از وبلاگ Software Alchemist</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 14 Apr 2024 23:56:38 +0330</pubDate>
            </item>
                    <item>
                <title>&#039;Everyday&#039; یا &#039;Every Day&#039;؟</title>
                <link>https://virgool.io/Novira/everyday-%DB%8C%D8%A7-every-day-r4gpwdv5rb6p</link>
                <description>این دو تا لغت از اشتباهات رایج در زبان انگلیسی هستن. خیلی ساده توضیح میدم که چجوری ازشون درست استفاده کنیم.انتخاب بین everyday (یه کلمه‌ای) و every day (دو کلمه‌ای) به جایی که ازش استفاده میشه مربوطه. Everyday (یه کلمه‌ای) ‌صفته ‌و معناش چیزیه که روزانه ازش استفاده یا دیده میشه ‌و بعضی وقتا هم به معنی ‌عادی (ordinary) به کار میره. مثال: The phone calls were an everyday occurrence : تماس‌های تلفنی یه رخداد هرروزی بودن.Every day (دو کلمه‌ای) ‌قیده و معناش هر روز یا هر روز کاری هفته (هر روز به جز آخر هفته) است. مثال: They go to the coffee shop every day : اونا هرروز میرن کافی‌شاپ.یه ترفند برای این که این دو تا رو از هم تشخیص بدی اینه که ببینی آیا میشه یه کلمه‌ی دیگه بین every و day قرار بدی یا نه؛ مثلا:  every single day. اگه ممکنه، پس باید از ترکیب دو کلمه‌ای (قیدی) استفاده کنی.لینک منبع</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sat, 30 Oct 2021 17:28:56 +0330</pubDate>
            </item>
                    <item>
                <title>جهان مدرن، جهان پیوستگی‌ها</title>
                <link>https://virgool.io/@mahdavipanah/%D8%AC%D9%87%D8%A7%D9%86-%D9%85%D8%AF%D8%B1%D9%86-%D8%AC%D9%87%D8%A7%D9%86-%D9%BE%DB%8C%D9%88%D8%B3%D8%AA%DA%AF%DB%8C-%D9%87%D8%A7-e5ghoyi9qr1a</link>
                <description>در دورانی که انسان هر روزش به جستجوی خوراک و شکار میگذشت، پیوستگی تنها بین چند ده نفری که یک گروه انسانی را تشکیل میدادند تعریف میشد. سپس این گروه پیوستگی کوتاه‌مدت و منقطعی (اگرچه بسیار حیاتی) با طبیعت اطرافش و زیست‌بوم منطقه‌ای که در آن سیر میکرد را میساخت. اگرچه انسان گونه‌ای اجتماعی بود و از همان ابتدا به یکدیگر نیاز داشت اما سبک زندگی انسان پیشاتاریخ نسبت به اعضای گونه‌ی خود گسسته بود و طبیعت به مانند دیکتاتوری ابدی و ازلی قوانین زندگی و روابط و فاصله‌ها را تعیین میکرد.در جهان مدرن، از همان صبح که بیدار میشویم، از آبی که با آن دست و صورتمان را میشوییم، تا صبحانه‌ای که میخوریم و حتی گاه تا هوایی که تنفس میکنیم، به سیستم‌های زیرساخت شهری جامعه‌ی مدرن وابسته است. سامانه‌های اساسی مثل برق‌رسانی، آب‌رسانی، سوخت‌رسانی، ارتباطات موبایل (شبکه سلولی) و ... . هرکدام از این سیستم‌ها به صورت شبکه‌ای عظیم، خود به دیگر سامانه‌ها متصل هستند و به شکلی پیچیده در هم تنیده‌اند. به طور مثال، شبکه‌ی حمل و نقل پیش‌نیاز تمام سیستم‌های مذکور است و خود نیز به طوری جدانشدنی به تمامی آن‌ها وابسته است.در نهایت، همه‌ی زیرساخت‌های یک جامعه‌ی مدرن وابسته به انسان‌هایی مختصص است که در حال روغن‌کاری چرخ‌دهنده‌های این شبکه‌ی عظیم از زیرساخت‌های مهم و حیاتی برای زندگی روزمره‌اند. کافی است تصویر کنید که چه میشود اگر یک روز شبکه‌ی حمل و نقل شهری به دلیل نبود سوخت از کار بیافتد. یا خیلی سخت نیست تصور قطع براق برای مدتی طولانی و اثرات روانی و فیزیکی آن در زندگی انسان شهری قرن بیست و یکم. خرابی هر کدام از این سامانه‌ها همچون قطعات یک دومینوی غول‌آسا می‌توانند آغازی برای پایان زندگی انسان شهری شوند.اگر صدهزار سال پیش، هرکدام از ما تنها به چند نفر از اعضای قبیله‌ی خود برای شکار و تامین امنیت نیازمند بودیم، اگر همه‌ی آن‌ها میمردند بازهم شانسی برای بقا داشتیم. اما امروز به میلیون‌ها نفر وابسته‌ایم؛ میلیون‌ها نفری که هرکدام نقشی در یک شبکه‌ی عظیم ارتباطات بازی میکنند و با یکدیگر یک جامعه‌ی مدرن را تشکیل میدهند.در این بین، نهاد‌هایی وجود دارند که نقشی مهم را در تامین نیروی انسانی، پول و هماهنگی بین این سیستم‌ها بازی میکنند. نهاد‌هایی مثل دانشگاه که به شکل سنتی وظیفه‌ی تولید و آموزش دانش را به عهده دارد. یا نهادهای صنعتی که وظیفه‌ی ساخت ابزارها و بنیه‌ی زیرساخت‌های اساسی را به دوش میکشند. هماهنگی تمام این اجزای دنیای مدرن در یک جامعه، در بستری انجام میشود که برآیند تجربه‌ی تاریخی-سیاسی آن جامعه است. یعنی فارغ از نوع سیستم سیاسی حاکم در یک جامعه، اجزایی کلیدی وجود دارند که نحوه‌ی ارتباط و پیوستگی آن‌ها در هر شکل یک جامعه باهم فرق میکند.حال اگر کمی جزئی به کل این شبکه‌ی عظیم نگاه کنیم، در آخر میبینیم که قوانین حاکم بر سیستم‌های اساسی و نیز تنظیم کارکرد آن‌ها وابسته به تک‌تک افرادی است که آن سیستم‌ها به آن‌ها وابسته‌اند. اگر دانش تخصصی و زور بازوی افراد در یک جامعه، پیش‌نیاز کارکرد تک‌تک سیستم‌ها و نهاد‌ها و زیرساخت‌های مهم آن جامعه است، تجربه و دانش تاریخی، فرهنگی، اجتماعی، سیاسی و طرز جهان‌بینی این افراد، هماهنگ‌کننده‌ی این اجزای مهم است. و فهم اهمیت هماهنگی بین اجزا در یک شبکه‌ی پیچیده نیاز به توضیح ندارد. چه بسا شبکه‌هایی که با وجود ناکارآمدی و یا عدم بهینه بودن اجزای درونشان، به دلیل هماهنگی درست این اجزا، بسیار کارآمدترند تا شبکه‌هایی که هرکدام از بخش‌های آن بهینه‌اند اما هماهنگی درست و سالم با یکدیگر را ندارند.پس ما، نه تنها در زور بازو و کار تخصصی روزانه‌مان، بلکه حتی در طرز فکرمان به یکدیگر پیوسته‌ایم. آن‌چه من در تصورم از جامعه‌ای ایده‌آل میسازم، نه تنها بر تنظیم روابط و کارکرد زندگی شخصی‌ام، بلکه بر زندگی دیگر افراد جامعه‌ی من نیز تاثیرگذار است.و حتی ما با گذشتگان و آیندگان خود نیز پیوستگی داریم. چرا که دانش تاریخی ما بدون شک از تصمیم‌ها، سختی‌ها و آرمان‌های گذشتگانمان سرچشمه میگیرد و ما نیز خود پلکان آینده را میسازیم. آنگاه که خط اختراع شد، مفهوم زمان برای بسیاری از چیزها، همچون ایده‌ها و دانش، از بین رفت. شما با نوشتن یک کتاب، میتوانید هزاران سال بعد از مرگ نیز، بخش مهمی از جهان انسان‌ها را تحت تاثیر خود داشته باشید.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Tue, 14 Sep 2021 14:59:37 +0430</pubDate>
            </item>
                    <item>
                <title>از المپیاد زیست تا ++Turbo C - داستان برنامه‌نویس شدنم</title>
                <link>https://virgool.io/Novira/day-of-the-programmer-lhadmumbmgbk</link>
                <description>به مناسبت روز برنامه‌نویس و به دعوت داتین، میخوام داستان برنامه‌نویس شدنم رو واستون تعریف کنم.محیط خاطره‌انگیز ++Borland Turbo C! ورودی به دبیرستان تیزهوشان و آشنایی من با برنامه‌نویسیتابستون سال قبل از شروع دبیرستان بود و نتایج امتحانات تیزهوشان اومد و بر خلاف توقعم قبول شده بودم! من که سال پنجم دبستان روزی پنج شش ساعت درس میخوندم و نتونستم برای راهنمایی تیزهوشان قبول بشم، حالا با روزی صفر ساعت مطالعه، تونسته بودم جزو چهار پنج نفری باشم که از مدارس دیگه به دبیرستان‌های سمپاد راه پیدا میکنن!تمام بچه‌های تیزهوشان از راهنمایی با برنامه‌نویسی آشنا و به مفاهیم ابتدایی اون مسلط بودن. من که میدونستم قاطی شدن و رقابت با بچه‌های قدیمی تیزهوشان کار سختیه و باید حسابی وقت‌بذارم، و از اونجایی که از همون پنج شش سالگی که اولین کامپیوترمون رو خریدیم، دیوانه‌وار عاشق کامپیوتر، بازی و بعدترها وبلاگ‌نویسی بودم، از یکی از بچه‌های مدرسه کتاب آموزش ویژوال بیسیک دوره‌ی راهنمایی تیزهوشان رو امانت گرفتم و شروع کردم به خوندش. خیلی ساده بود. خیلی جذاب بود. به سرعت همش رو خوندم و یه جاهایی رو که نمیفهمیدم از بقیه بچه‌ها پرسیدم.همون سال اول دبیرستان برای درس برنامه‌نویسی، دبیری داشتیم جوان (که فامیلیش یادم نمیاد) که دانشجوی کامپیوتر بود و برای ما ++C درس میداد. هم مسلط بود و هم نحوه‌ی تدریسش خوب بود. سی‌پلاس‌پلاس را توی محیط Borland Turbo درس میداد و خب از اونجایی که برای DOS طراحی شده بود جذابیت زیادی نداشت و کار باهاش کسل‌کننده و دشوار بود. اکثر بچه‌ها به مفاهیم برنامه‌نویسی مسلط بودن و تمرینات رو ذهنی حل میکردن و سختی اجرای کامپایلر Borland رو به خودشون نمیدادن. اولین بار که خواستم ++Turbo C رو اجرا کنم چون کامپیوتر شخصی و لپ‌تاپم ۶۴بیتی بود (یا شایدم بخاطر یه مشکل دیگه) هرکار کردم اجرا نشد. بعد رفتم سراغ کامپیوتر شخصی قدیمیمون (با ۲۵۶ مگابایت رم!) که توی زیرزمین خونمون بود و داییم هر از چندگاهی روشنش میکرد و باهاش کار میکرد. فولدر کامپایلر Turbo رو باز کردم، روی آیکون اجراییش کلیک کردم و BOOOM! اجرا شد. با این که محیط کامپایلرش قدیمی و بدون امکانات خاصی بود، اما رنگ‌بندی آبی‌سفیدش حس خفنی داشت! و من که تازه داشتم با دنیای برنامه‌نویسی آشنا میشدم، این محیط بهم اعتماد به نفس میداد و حس میکردم دارم کار مهمی میکنم. و البته که حسم درست بود.وداع با زیست‌شناسییادمه که عاشق زیست‌شناسی بودم و حتی همون سال اول با صمیمی‌ترین دوستم (محمد) کلاس‌های المپیاد زیست شرکت میکردم و خیلی جدی کتاب کمپل رو میخوندم. آشناییم با برنامه‌نویسی و دبیر جوان، همه‌چیزو تغییر داد. تصمیم خودمو گرفته بودم. میخواستم برم رشته‌ی ریاضی-فیزیک. تابستون قبل از سال دوم دبیرستان توی یه کلاس سی‌شارپ شرکت کردم و استاد خوب اون کلاس‌ (مهندس طرفدار) ذهنیت برنامه‌نویسیم رو کامل کرد. سی‌شارپ زبان خیلی خوبی بود و بسیاری از مفاهیم مهم و کلیدی برنامه‌نویسی رو به بهترین شکل به من یاد داد.همون تابستون تصمیمم برای انتخاب ریاضی-فیزیک را با خونواده مطرح کردم و با مقاومت شدیدشون مواجه شدم. استدلالشون ساده بود: تو باهوشی (!) و چون پزشکی آینده‌ی بهتری داره، بنابراین باید دکتر بشی! به قول فرنگیا: BULLSHIT. از موضعم کوتاه نیومدم. کلی استرس کشیدم، کلی استدلال آوردم و در آخر پیروز شدم و رفتم رشته‌ی ریاضی-فیزیک.شروع عشق و حالحالا که رشتمو انتخاب کرده بودم و خیالم راحت بود، شروع کردم به یاد گرفتن و بازی کردن با ابزارها و زبان‌های برنامه‌نویسی مختلف. یادمه که سی‌شارپ رو میپرستیدم و اون اوایل با WPF و Blend ساعت‌های زیادی رو میگذروندم و به هرجایی که میشد سرک میکشیدم. WPF تکنولوژی قوی‌ای بود و با استفاده از چیزی به نام XAML (که خیلی شبیه به XML) بود میشد رابط‌های گرافیکی پیچیده با انمیشین‌های مختلفی درست کرد. آشنایی من با XAML و شباهتش با HTML و ساختار طراحی UI در وب، تکه‌ای از پازل علاقه‌مندی من به وب بود. دنیای جذاب و جالبی بود و خوشحالم که شروع برنامه‌نویسیم با سی‌شارپ بود. اگرچه بعدا باهاش قهر کردم!نمونه‌ی یه اپلیکیشن ساخته شده با WPFسال دوم دبیرستان، دبیر جوانمون در یک تصمیم انقلابی و عجیب، شروع کرد بهمون SQL یاد بده. باید اعتراف کنم که متد آموزشش عالی بود. با این که هیچکدوم از ما ایده‌ای درمورد دیتابیس نداشتیم، مفاهیم رو جوری برامون ساده میکرد که میتونستیم خیلی راحت کوئری‌های ساده‌ی SQL رو بفهمیم و بنویسیم. آشنایی زودهنگام من با SQL تکه‌ی مهم دیگه‌ای از پازل علاقه‌مندی من به وب بود.کم کم به دنیای وب علاقه‌مند شدم و شروع کردم به یادگیری HTML و PHP. خیلی برام سخت بود. مفاهیم ابتدایی وب رو نمیدونستم و کاملا گیج میزدم! نمیدوستم چی به چیه، سرور چیه، کلاینت چیه، این PHP چرا اینجوری اجرا میشه، چرا کدهای HTML رو باهاش قاطی میکنن! و خلاصه چندباری دنیای وب رو ول کردم و باز دوباره شروع کردم تا این که با کامل‌تر شدن ذهنیتم، PHP رو یاد گرفتم و عاشق وب شدم.سال سوم دبیرستان، من که تا دو سال قبلتر حتی یک خط کد نه دیده بودم و نه نوشته بودم، میتونستم به چندتا زبان (سی‌پلاس‌پلاس، ویژوال بیسیک، سی‌شارپ، PHP و جاوااسکریپت) کد بزنم. خیلی خوشحال بودم. اعتماد به نفس زیادی داشتم و از مسیری که انتخاب کرده‌بودم راضی بودم.توی همون سال، با دوستی آشنا شدم به نام حسین که موسس و برنامه‌نویس سایت واژه‌یاب بود. این شانس رو داشتم که بهم اعتماد کرد و اجازه داد روی بخش‌هایی از سایت واژه‌یاب کد بزنم و برای اولین بار بفهمم که کار روی یه پروژه‌ی واقعی چه حسی داره. دو نسخه‌ی متفاوت اپلیکیشن ویندوزی برای واژه‌یاب نوشتم و در مسیر طراحی این دوتا اپلیکیشن حسین اهمیت طراحی UI رو بهم یاد داد.لینوکس رو پیدا کردملینوکس میترکونه!یادم نیست چطوری ولی خیلی زود فهمیدم که دنیای لینوکس اهمیت زیادی داره. چون شروع برنامه‌نویسیم با سی‌شارپ و پلتفرم ویندوز بود، اوایل کمی مقاومت میکردم ولی بعدش که با PHP بیشتر دوست‌شدم، راه برای ورودم به دنیای لینوکس هموارتر شد.مثل خیلی‌ها اولین‌بار با Ubuntu شروع کردم. نصبش کردم، اجراش کردم و با این که میدونستم یاد گرفتنش برای من که تازه‌وارد بودم و از ابتدا با ویندوز کار میکردم، سخته، اما میدونستم که راه درستیه. و خدا میدونه که چقدر راه درستی بود!دو سال آخر دبیرستان، فکر و ذکرم لینوکس بود. سعی میکردم تمام چیزهایی که تا قبل از اون یادگرفته بودم رو یه جوری به دنیای لینوکس مربوط کنم. یادمه که اوایل دچار یه بحران فلسفی شده بودم! از اونجایی که توی ویندوز با ویژوال استادیو، یه دنیای کامل و متحد از امکانات و ابزارها در اختیارم بود، توی لینوکس باید چیزهای مختلفی رو کنارهم میذاشتم و جدا جدا یاد میگرفتم. بنابراین در ابتدا این فکر مدام درگیرم میکرد که آیا پلتفرم لینوکس انتخاب بهتریه یا برگردم به دنیای سی‌شارپ و ویندوز؟تاثیر آشناییم با لینوکس، بعدتر توی دانشگاه خودشو نشون داد. دنیای لینوکس نه تنها نگاه منو به برنامه‌نویسی و علوم کامپیوتر تغییر داد، بلکه به فلسفه، سیاست و تاریخ هم علاقه‌مندم کرد.دانشگاهسه سال از وقتی که تصمیم گرفته بودم برم رشته‌ی ریاضی-فیزیک میگذشت. کلی چیز جدید یاد گرفته بودم و هر روز بیشتر از دیروز به این نتیجه میرسیدم که راهی که انتخاب کردم راه درستیه. سال کنکور خیلی کم درس خوندم. نتایج کنکور اومد و راضی بودم. مطمئنم بودم که میتونم توی یه دانشگاهی در جایی از خاک این کشور رشته‌ی کامپیوتر بخونم و همین برام کافی بود :)در کل کمتر از ۴۰ تا انتخاب رشته کردم که از بهترین دانشگاه‌های تهران شروع میشد و تا دانشگاه قم تموم میشد. فقط مهندسی نرم‌افزار و IT رو انتخاب کردم. حتی سخت‌افزار هم نزدم! انتخاب یکی مونده به آخر که دانشگاه دولتی شهر محل زندگیم (کاشان) بود قبول شدم.توصیه‌هایی به برنامه‌نویسای جوانمن هنوز خودمو توی دنیای برنامه‌نویسی و علوم کامپیوتر یه شاگرد میدونم. توی سیر و سیاحتی که توی ۱۰ سال آشناییم با این دنیای جذاب و رو به آینده داشتم، نکاتی رو یاد گرفتم که دوس‌دارم با برنامه‌نویسای جوان‌تر از خودم به اشتراک بذارم:زبان انگلیسی رو یاد بگیر: حقیقت اینه که دنیای علوم کامپیوتر دنیایی جهانیه و زبان این دنیا زبان انگلیسیه. بنابراین مهم‌ترین پیش‌نیاز برای پیشرفت به عنوان یه برنامه‌نویس (شما بخونید مهندس نرم‌افزار، دانشمند داده و ...) تسلط حداقلی به زبان انگلیسیه.مفاهیم اولیه و کلیدی رو بیاموز: اگرچه غرق شدن در مفاهیم میتونه خودش یه معضل باشه، اما نمیشه بدون دونستن نحوه‌ی کارکرد سیستم‌های مختلف و معماری اونها، با روش درست باهاشون کار کرد. بنابراین به نظر من در کنار یاد گرفتن ابزارهای کاربردی، مهمه که آدم نحوه‌ی کار اون ابزارها رو هم بدونه، حتی اگه خیلی ابتدایی و ناچیز.تا میتونی چرخ‌ها را دوباره اختراع کن: بهترین توصیه‌ی من برای افزایش مهارت برنامه‌نویسی، اینه که سعی کن ابزارها، کتابخانه‌ها و اپلیکیشن‌هایی که دور و برت میبینی رو پیاده‌سازی کنی. این معناش این نیست که توی پروژه‌های مهم و واقعی، از کتابخانه‌ها و فریمورکهای بقیه استفاده نکنی و همش رو خودت بنویسی! معنیش اینه که یکی از بهترین تمرین‌ها برای برنامه‌نویسی، پیاده‌سازی کدهاییه که قبلا نوشته شده و ورودی‌ها و خروجی‌هاش مشخصه و تمرینت اینه که اون سیستم رو با زبان برنامه‌نویسی‌ای که میخوای یادبگیری پیاده‌سازی کنی.با لینوکس دوست باش: قرار نیست همه‌ی برنامه‌نویسا فقط با لینوکس کار کنن و متعصبانه از بقیه‌ی پلتفرم‌ها دوری کنن. اما مهمه که با هر تکنولوژی‌ و پلتفرمی که کار میکنی، با لینوکس هم آشنا باشی و فلسفه‌ی طراحی اون رو بدونی. چون بخوای یا نخوای، دنیای گنو/لینوکس بخش مهمی از علوم کامپیوتره.کنجکاو باش و قانع نشو: هیچوقت به چیزهایی که بلدی قانع نباش و همیشه بخشی از زمان روزانت رو به یادگرفتن اختصاص بده. هم یاد گرفتن چیزهای جدید و هم جزئیات عمیق‌تر درمورد چیزهایی که بلدی.از متفاوت بودن نترس: دنیای مهندسی، دنیای خلاقیته و اگرچه در هر برهه زمانی یه سری راه استاندارد برای انجام یه کار مشخص وجود داره ولی همون راه‌های استاندارد یه زمانی جدید و غیرمتعارف بوده. آزمون و خطا بهترین معلم و خلاق‌ترین مهندسه.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Mon, 13 Sep 2021 13:22:31 +0430</pubDate>
            </item>
                    <item>
                <title>کمربند سیاهِ Async Await در Node.js</title>
                <link>https://virgool.io/yavarjs/mastering-async-await-rsotdpvg6tbo</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/mastering-async-awaitدر این نوشته یاد میگیری که چجوری اپلیکیشن‌های Node.jsای که با callback یا Promise نوشتی رو با توابع async ساده‌ترشون کنی.اگه قبلا یه نگاهی به الگوی async/await و promiseها در جاوااسکریپت انداختی ولی هنوز کامل بهشون مسلط نیستی و یا این که فقط نیاز داری تا مرورشون کنی، هدف این نوشته کمک به توئه.تابع‌های async چی هستن؟توابع async به طور پیش‌فرض در Node در دسترسند و با کلمه‌ی کلیدی async علامت‌گذاری میشن. این توابع حتی اگه به طور صریح در بدنشون مشخص نکنی، همیشه یه promise برمیگردونن. در ضمن، فعلا کلمه‌ی کلیدی await فقط در داخل توابع async قابل استفاده‌اس و نمیشه در دامنه سراسری (global scope) ازش استفاده کرد.داخل یه تابع async میتونی منتظر یه Promise بمونی و یا این که در صورت مردود شدنش (rejected) میتونی خطاش رو دستگیر کنی (catch).پس اگه یه کدی داری که با promiseها پیاده‌سازی شده:function handler (req, res) {
  return request(&#039;https://user-handler-service&#039;)
    .catch((err) =&gt; {
      logger.error(&#039;Http error&#039;, err);
      error.logged = true;
      throw err;
    })
    .then((response) =&gt; Mongo.findOne({ user: response.body.user }))
    .catch((err) =&gt; {
      !error.logged &amp;&amp; logger.error(&#039;Mongo error&#039;, err);
      error.logged = true;
      throw err;
    })
    .then((document) =&gt; executeLogic(req, res, document))
    .catch((err) =&gt; {
      !error.logged &amp;&amp; console.error(err);
      res.status(500).send();
    });
}میتونی با ‍‍async/await شبیه به یه کد همگام (synchronous) بنویسیش:async function handler (req, res) {
  let response;
  try {
    response = await request(&#039;https://user-handler-service&#039;)  ;
  } catch (err) {
    logger.error(&#039;Http error&#039;, err);
    return res.status(500).send();
  }

  let document;
  try {
    document = await Mongo.findOne({ user: response.body.user });
  } catch (err) {
    logger.error(&#039;Mongo error&#039;, err);
    return res.status(500).send();
  }

  executeLogic(document, req, res);
}در حال حاضر در Node اگه در یه promise خطایی رخ بده که بهش رسیدگی نشده، Node فقط بهت هشدار میده، پس بنابراین نیازی نیست تا خودتو توی دردسر ساختن یه listener بندازی. هرچند چون این اتفاق نشون‌دهنده‌ی یه حالت نامشخصه، توصیه میشه تا اپلیکیشن رو ببندی و کرش کنی؛ دقیقا شبیه به حالتی که یه خطای catch نشده در جایی از کد رخ میده. این کارو میتونی یا با استفاده از پرچم unhandled-rejections=strict-- در کامند‌لاین انجام بدی یا با پیاده‌سازی چیزی شبیه به این:process.on(&#039;unhandledRejection&#039;, (err) =&gt; { 
  console.error(err);
  process.exit(1);
})قراره تا قابلیت خارج شدن اتوماتیک از پروسه، در نسخه‌های آینده‌ی Node اضافه بشه. این که کدت رو از قبل برای اینکار آماده کنی زحمت زیادی نداره ولی خوبیش اینه که وقتی خواستی نسخه‌ها رو آپدیت کنی دیگه نگران این موضوع نیستی.الگوها با توابع asyncاز اونجایی که رسیدگی به عملیات ناهمگام (asynchronous) با استفاده از Promiseها و یا callbackها نیاز به الگوهای پیچیده‌ای داره، وقتی که بتونی این عملیات رو جوری پیاده‌سازی کنی که انگار همگام هستن، کار خیلی برات ساده‌تره.از نسخه‌ی 10.0.0 نود جی‌اس، پشتیبانی از async iterators و حلقه‌ی مرتبطش یعنی for-await اضافه شده. این امکانات زمانی بدردت میخورن که میخوای روی مقداری که یه iterator method برمیگردونه و از قبل مشخص نیستن، حرکت کنی (حلقه بزنی) و کاری رو انجام بدی و حالت نهایی این تکرار (iteration) هم مشخص نیست - معمولا این حالت حین کار با streamها پیش میاد.تلاش مجدد با عقب‌نشینی نمایی (exponential backoff)پیاده‌سازی الگوریتم تلاش مجدد با Promiseها خیلی بدترکیبه:function request(url) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout&#40;(&#41; =&gt; {
      reject(`Network error when trying to reach ${url}`);
    }, 500);
  });
}

function requestWithRetry(url, retryCount, currentTries = 1) {
  return new Promise((resolve, reject) =&gt; {
    if (currentTries &lt;= retryCount) {
      const timeout = (Math.pow(2, currentTries) - 1) * 100;
      request(url)
        .then(resolve)
        .catch((error) =&gt; {
          setTimeout&#40;(&#41; =&gt; {
            console.log(&#039;Error: &#039;, error);
            console.log(`Waiting ${timeout} ms`);
            requestWithRetry(url, retryCount, currentTries + 1);
          }, timeout);
        });
    } else {
      console.log(&#039;No retries left, giving up.&#039;);
      reject(&#039;No retries left, giving up.&#039;);
    }
  });
}

requestWithRetry(&#039;http://localhost:3000&#039;)
  .then((res) =&gt; {
    console.log(res)
  })
  .catch(err =&gt; {
    console.error(err)
  });این پیاده‌سازی کاری که میخوایمو میکنه اما میتونیم بازنویسیش کنیم و با async/await خیلی راحت‌تر کارو انجام بدیم:function wait (timeout) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; {
      resolve()
    }, timeout);
  });
}

async function requestWithRetry (url) {
  const MAX_RETRIES = 10;
  for (let i = 0; i &lt;= MAX_RETRIES; i++) {
    try {
      return await request(url);
    } catch (err) {
      const timeout = Math.pow(2, i);
      console.log(&#039;Waiting&#039;, timeout, &#039;ms&#039;);
      await wait(timeout);
      console.log(&#039;Retrying&#039;, err.message, i);
    }
  }
}خیلی بیشتر به دل میشینه، نه؟مقادیر میانی (intermediate values)با این که مثال پیش‌رو به اندازه‌ی قبلی ترسناک نیست، اما اگه حالتی داشته باشی که ۳ تابع ناهمگام مختلف به شکلی که در زیر توضیح میدم، بهم وابسته باشن، مجبوری تا از بین چندتا راه‌حل زشت و بدترکیب یکیشونو انتخاب کنی.تابع functionA یه Promise برمیگردونه که سپس functionB به مقدارش نیاز داره و بعد از اون functionC به مقدار نهایی Promiseهای جفت تابع functionA و functionB نیاز داره.راه حل ۱: درخت کریسمس then.function executeAsyncTask () {
  return functionA()
    .then((valueA) =&gt; {
      return functionB(valueA)
        .then((valueB) =&gt; {          
          return functionC(valueA, valueB)
        })
    })
}توی این راه حل، برای انجام functionC مقدار valueA رو از کلوژر (closure) سومین then میگیری و مقدار valueB رو از Promise قبلش که انجام شده. نمیتونی این درخت کریسمس رو مسطح کنی چون در اون صورت کلوژر رو گم میکنی و valueA در دسترس functionC نخواهد بود.راه حل ۲: حرکت به یه اسکوپ (scope) بالاترfunction executeAsyncTask () {
  let valueA
  return functionA()
    .then((v) =&gt; {
      valueA = v
      return functionB(valueA)
    })
    .then((valueB) =&gt; {
      return functionC(valueA, valueB)
    })
}توی مثال درخت کریسمس شبیه به همین مثال، از یه اسکوپ بالاتر برای دسترسی به valueA استفاده کردیم. اما تفاوت این مثال اینه که متغیر valueA رو خارج از اسکوپ then. تعریف کردیم تا بتونیم مقدار نهایی اولین Promise رو بهش انتساب بدیم.این مثال قطعا کار میکنه و زنجیره‌ی then. هم مسطح شده و از نظر معنایی هم درسته. با این وجود اگه از valueA در جاهای دیگه از تابع استفاده کنی، راه برای پیدا شدن باگ‌های جدید باز میشه. علاوه بر این، مجبوری برای یه مقدار یکسان از دوتا اسم مختلف استفاده کنی - valueA و v.راه حل ۳: آرایه‌ی غیر ضروریfunction executeAsyncTask () {
  return functionA()
    .then(valueA =&gt; {
      return Promise.all([valueA, functionB(valueA)])
    })
    .then(([valueA, valueB]) =&gt; {
      return functionC(valueA, valueB)
    })
}جز این که میخوای درخت رو مسطح کنی، هیچ دلیلی نداره که valueA رو همراه با Promiseای که functionB برمیگردونه داخل یه آرایه پاس بدیم. مقدار این دو عنصر آرایه ممکنه از دو جنس کاملا مختلف باشن و بنابراین جالب نیست که توی یه آرایه‌ی واحد قرار بگیرن.راه حل ۴: یه تابع کمکی بنویسconst converge = (...promises) =&gt; (...args) =&gt; {
  let [head, ...tail] = promises
  if (tail.length) {
    return head(...args)
      .then((value) =&gt; converge(...tail)(...args.concat([value])))
  } else {
    return head(...args)
  }
}

functionA(2)
  .then((valueA) =&gt; converge(functionB, functionC)(valueA))البته که میتونی یه تابع کمکی بنویسی تا این آش شله قلمکار رو درست کنی. اما از نظر خوانایی خیلی ضعیفه و بنابراین ممکنه درکش برای کسایی که توی برنامه‌نویسی functional موهاشون سفید نشده، سخت باشه.با استفاده از async/await به طور معجزه‌آسایی مشکلاتمون ناپدید میشه:async function executeAsyncTask () {
  const valueA = await functionA();
  const valueB = await functionB(valueA);
  return function3(valueA, valueB);
}چندین درخواست موازی با async/awaitاین مثال شبیه قبلیه. فرض کن میخوای چند کار ناهمگام مختلف رو در یک لحظه شروع کنی و از مقادیر برگشتیشون تو جاهای مختلف استفاده کنی:async function executeParallelAsyncTasks () {
  const [ valueA, valueB, valueC ] = await Promise.all([ functionA(), functionB(), functionC() ]);
  doSomethingWith(valueA);
  doSomethingElseWith(valueB);
  doAnotherThingWith(valueC);
}متدهای iteration آرایهاگرچه رفتارشون خیلی غیرمنتظرست ولی میتونی map ،filter و reduce رو با توابع async استفاده کنی. تلاش کن حدس بزنی که خروجی اسکریپت‌های زیر چیه:‍‍۱. mapfunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].map(async (value) =&gt; {
    const v = await asyncThing(value);
    return v * 2;
  });
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));‍‍۲. filterfunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].filter(async (value) =&gt; {
    const v = await asyncThing(value);
    return v % 2 === 0;
  });
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));‍‍۳. reducefunction asyncThing (value) {
  return new Promise((resolve) =&gt; {
    setTimeout&#40;(&#41; =&gt; resolve(value), 100);
  });
}

async function main () {
  return [1,2,3,4].reduce(async (acc, value) =&gt; {
    return await acc + await asyncThing(value);
  }, Promise.resolve(0));
}

main()
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));راه حل‌ها:۱.[ Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; }, Promise { &lt;pending&gt; } ]۲.[ 4 ,3 ,2 ,1 ]۳. 10اگه خروجی هرکدوم از promiseهایی که map برمیگردونه رو چاپ کنی، میبینی که نتیجه‌ای که مورد انتظاره میده: [ 8 ,6 ,4 ,2 ]. تنها مشکل اینه که هرکدوم از این مقادیر توسط AsyncFunction توی یه Promise بسته‌بندی شدن.پس اگه میخوای مقادیرتو بگیری، باید آرایه‌ی برگشتی رو به Promise.all پاس بدی:main()
  .then(v =&gt; Promise.all(v))
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));بدون async/await باید اول منتظر تموم شدن promiseها میموندی و بعد روی مقادیرشون map رو اجرا میکردی:function main () {
  return Promise.all([1,2,3,4].map((value) =&gt; asyncThing(value)));
}

main()
  .then(values =&gt; values.map((value) =&gt; value * 2))
  .then(v =&gt; console.log(v))
  .catch(err =&gt; console.error(err));روش دوم یکم واضح‌تره، نه؟روشی که از async/await استفاده میکنه زمانی که برای هر مقدار promise نیازه تا کارهای همگام طولانی بکنی و در عین حال کارهای ناهمگام هم طولانی‌اند، میتونه بدردت بخوره.با این روش، به محض این که اولین مقدار رو بدست بیاری، میتونی محاسبتش رو شروع کنی و مجبور نیسی برای شروع محاسباتت منتظر بقیه‌ی Promiseها بمونی تا تکمیل بشن. اگرچه خروجی نهایی مقادیر توی Promiseها پیچیده شدن، اما این Promiseها خیلی سریع تکمیل میشن و در نهایت کل فرآیند سریع‌تر از زمانیه که بخوای به طور متوالی انجامش بدی.داستان filter چیه؟ مطمئنا یه چیزی این وسط اشتباهه…خب، درست حدس زدی: اگرچه مقادیر برگشتی از این قراره: [ false, true, false, true ] اما هرکدومشون توی یه Promise پیچیده شدن، و از اونجایی که هر Promise یه مقدار اصطلاحا truthy هست (یعنی زمانیه که به شکل بولین ببینیمش، مقدارش true میشه)، تمام مقادیر آرایه برمیگردن و هیچکدوم فیلتر نمیشن. متاسفانه تنها کاری که برای رفع این مشکل از دستت برمیاد اینه که اول منتظر بشی تا مقادیر Promiseها برگردن و بعد فیلترشون کنی.متد reduce خیلی سرراسته. اگرچه یادت باشه که باید مقدار اولیه رو داخل Promise.resolve بپیچی، و همچنین مقدار متغیر تجمعی هم به صورت Promise برمیگرده و بنابراین نیازه تا براش از await استفاده کنی.بازنویسی اپلیکیشن‌های برپایه‌ی callbackتوابع async به طور پیشفرض یه Promise برمیگردونن، بنابراین میتونی هر تابعی که برپایه‌ی callback هست رو جوری بازنویسی کنی که از Promiseها استفاده کنه و سپس مقدار بازگشتیش رو با await بگیری. توی Node.js برای تبدیل یه تابع برپایه‌ی callback به یه تابع برپایه‌ی Promise میتونی از تابع util.promisify استفاده کنی.بازنویسی اپلیکیشن‌های برپایه‌ی Promiseزنجیره‌های ساده‌ی then. رو خیلی سرراست میشه با استفاده از async/await بازنویسی کرد.function asyncTask () {
  return functionA()
    .then((valueA) =&gt; functionB(valueA))
    .then((valueB) =&gt; functionC(valueB))
    .then((valueC) =&gt; functionD(valueC))
    .catch((err) =&gt; logger.error(err))
}تبدیل میشه به:async function asyncTask () {
  try {
    const valueA = await functionA();
    const valueB = await functionB(valueA);
    const valueC = await functionC(valueB);
    return await functionD(valueC);
  } catch (err) {
    logger.error(err);
  }
}اپلیکیشن‌های Node.js رو با async/await بازنویسی کن اگه:مفاهیم قدیمی و باحالی مثل شرط‌های if-else و حلقه‌های for/while رو دوس داری.باور داری که بلوک‌های try-catch راه درست رسیدگی به خطاهاست.همونطور که باهم دیدیم، استفاده از async/await هم خوانایی کدهارو بیشتر میکنه و هم نوشتنشون رو ساده‌تر میکنه و در بسیاری از کارها مناسب‌تر از زنجیره‌های ()Promise.then هست. اما اگه به شور و اشتیاقی که در چند سال اخیر برای برنامه‌نویسی فانکشنال بوجود اومده دچار شدی، شاید بهتر باشه که از خیر این قابلیت جاوااسکریپت بگذری.منبع: Rewriting Node.js apps with async/await از وبلاگ RisingStack</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 02 May 2021 17:40:26 +0430</pubDate>
            </item>
                    <item>
                <title>تنظیم Docker برای یه وب‌اپ Node.js</title>
                <link>https://virgool.io/yavarjs/dockerizing-nodejs-mqd4ijcjbcom</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/dockerizing-nodejsهدف این نوشته معرفی یه مثاله برای این که چجوری یه اپلیکیشن Node.js رو به یه کانتینر Docker تبدیل کنی. این راهنما برای زمان توسعه اپ هست و نه برای استقرار اپ برای production. همچنین فرض میکنم که یه نسخه‌ی نصب شده از داکر روی سیستمت هست و یه دانش ابتدایی از ساختار یه اپلیکیشن Node.js داری.در بخش اول این راهنما یه وب‌اپلیکیشن ساده رو با Node.js میسازی و سپس یه image داکر برای اون اپلکیشن درست میکنی و در آخر هم یه کانتینر رو از روی اون image اجرا میکنی.داکر این امکان رو بهت میده که یه اپلیکیشن رو با محیطش (environment) و تمام وابستگی‌هاش (dependencies) به یه جعبه تبدیل کنی که اسمش هست «کانتینر» (container). معمولا یه کانتینر از یه اپلکیشن تشکیل شده که روی یه سیستم‌عامل لینوکس خیلی سبک و ساده در حال اجراست. یه image یه نقشه و طرح برای کانتینره و یه کانتینر یه نمونه در حال اجرا از یه image هست.ساخت اپ Node.jsدر ابتدا یه فولدر بساز که تمام فایلها قراره اونجا زندگی کنن. توی این فولدر یه فایل package.json بساز که توضیحاتیه درمورد اپ و وابستگی‌هاش:{
  &amp;quotname&amp;quot: &amp;quotdocker_web_app&amp;quot,
  &amp;quotversion&amp;quot: &amp;quot1.0.0&amp;quot,
  &amp;quotdescription&amp;quot: &amp;quotNode.js on Docker&amp;quot,
  &amp;quotauthor&amp;quot: &amp;quotFirst Last &lt;first.last@example.com&gt;&amp;quot,
  &amp;quotmain&amp;quot: &amp;quotserver.js&amp;quot,
  &amp;quotscripts&amp;quot: {
    &amp;quotstart&amp;quot: &amp;quotnode server.js&amp;quot
  },
  &amp;quotdependencies&amp;quot: {
    &amp;quotexpress&amp;quot: &amp;quot^4.16.1&amp;quot
  }
}دستور npm install رو اجرا کن. اگه از نسخه‌ی ۵ به بالای npm استفاده میکنی، این دستور یه فایل package-lock.json درست میکنه که بعدا کپی میشه به image داکرت.سپس یه فایل server.js بساز که یه وب‌اپ رو شامل میشه که از فریمورک Express.js استفاده میکنه:&#039;use strict&#039;;

const express = require(&#039;express&#039;);

// مقادیر ثابت
const PORT = 8080;
const HOST = &#039;0.0.0.0&#039;;

// اپ
const app = express();
app.get(&#039;/&#039;, (req, res) =&gt; {
  res.send(&#039;Hello World&#039;);
});

app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);توی مراحل بعدی، میبینی که چجوری میتونی این اپ رو با استفاده از ایمیج رسمی داکر، داخل یه کانتینر اجراش کنی. اول از همه نیاز داری تا یه Docker image برای اپلیکیشنت بسازی.ایجاد یه Dockerfileیه فایل خالی بساز که اسمش هست Dockerfile:touch Dockerfileاین فایل رو داخل ادیتور مورد علاقت باز کن.اولین کار اینه که ببینیم از چه ایمیجی کارمون رو شروع کنیم. اینجا از آخرین نسخه‌ی پشتیبانی بلندمدت (LTS) استفاده میکنیم که میشه نسخه‌ی ‍14 از node که در مخزن Docker Hub موجوده:FROM node:14سپس توی ایمیج یه فولدر بساز که داخلش کدهای اپلیکیشن رو قرار بدی، این فولدر قراره فولدر کاری (working directory) برای اپلیکیشنت باشه:# رو بساز app دایرکتوری
WORKDIR /usr/src/appایمیج (node:14) از قبل داخلش Node.js و NPM نصب شده و کار بعدی که نیازه بکنی اینه که وابستگی‌های اپلیکیشنت رو با npm نصب کنی. لطفا دقت کن که اگه داری از نسخه‌ی ۴ به پایین npm استفاده میکنی، فایل package-lock.json ساخته نمیشه.# وابستگی‌های اپ رو نصب کن
# از علامت ستاره استفاده شده تا هم فایل قفل و هم فایل عادی کپی بشه
COPY package*.json ./

RUN npm install
# اگه داری اپلیکیشن رو برای پروداکشن میسازی از دستور زیر استفاده کن
# RUN npm ci --only=productionدقت کن که به جای کپی کردن کل فولدر کاریمون، فقط فایل package.json رو کپی کردیم. این کار بهمون اجازه میده تا از مزیت لایه‌های قابل کش در داکر استفاده کنیم ( بیشتر بخوانید ). علاوه‌بر این، فرمان npm ci کمک میکنه که build های سریعتر، قابل اتکاتر و قابل تکثیر برای محیط‌های پروداکشن بسازیم. در این مورد میتونی اینجا بیشتر بخونی.برای بسته‌بندی کردن سورس‌کدهای اپ توی ایمیج داکر، از دستور COPY استفاده کن:# سورس اپ رو بسته‌بندی کن
COPY . .اپلیکیشنت خودشو به پورت 8080 میچسبونه، پس از دستور EXPOSE استفاده کن تا داکر این پورت رو برات مپ کنه:EXPOSE 8080در آخر، فرمانی که اپلیکیشنت رو به اجرا درمیاره با استفاده از CMD تعریف کن. در اینجا ما از ‍node server.js برای شروع سرور استفاده میکنیم:CMD [ &amp;quotnode&amp;quot, &amp;quotserver.js&amp;quot ]فایل dockerfile الان باید اینشکلی باشه:FROM node:14

# رو بساز app دایرکتوری
WORKDIR /usr/src/app

# وابستگی‌های اپ رو نصب کن
# از علامت ستاره استفاده شده تا هم فایل قفل و هم فایل عادی کپی بشه
COPY package*.json ./

RUN npm install
# اگه داری اپلیکیشن رو برای پروداکشن میسازی از دستور زیر استفاده کن

# سورس اپ رو بسته‌بندی کن
COPY . .

EXPOSE 8080
CMD [ &amp;quotnode&amp;quot, &amp;quotserver.js&amp;quot ]فایل dockerignore.یه فایل ‍‍dockerignore داخل همون فولدری که فایل dockerfile هست بساز که محتواش ایناس:node_modules
npm-debug.logاینکار باعث میشه که ماژول‌های محلی (ماژول‌هایی که روی سیستم خودت داخل فولدر اپ نصب کردی) و لاگ‌های دیباگ توی ایمیج داکر کپی نشه.ساخت imageبرو به فولدری که dockerfile داخلشه و فرمان زیر رو اجرا کن تا ایمیج داکر رو بسازه. پرچم t- یه برچسب به ایمیج میچسبونه که بعدا راحت‌تر بتونی با فرمان docker images پیداش کنی:docker build . -t &lt;your username&gt;/node-web-appحالا باید داکر ایمیجت رو لیست کرده باشه:$ docker images

# مثال
REPOSITORY                      TAG        ID              CREATED
node                            14         1934b0b038d1    5 days ago
&lt;your username&gt;/node-web-app    latest     d64d3505b0d2    1 minute agoاجرای imageاجرا کردن ایمیجل با پرچم d- کانتینر رو در پس‌زمینه اجرا میکنه. پرچم p- یه پورت خصوصی داخل کانتینر رو به یه پورت عمومی ریدایرکت میکنه. ایمیجی که از قبل ساختی رو اجرا کن:docker run -p 49160:8080 -d &lt;your username&gt;/node-web-appخروجی اپلیکیشنت رو چاپ کن:$ docker ps
# خروجی اپ رو چاپ کن
$ docker logs &lt;container id&gt;

# مثال
Running on http://localhost:8080اگه میخوای بری داخل خود کانتینر، میتونی از فرمان exec استفاده کنی:$ docker exec -it &lt;container id&gt; /bin/bashتستبرای این که اپلیکیشنت رو تست کنی، پورتی رو که داکر مپ کرده پیدا کن:$ docker ps

# مثال
ID            IMAGE                                COMMAND    ...   PORTS
ecce33b30ebf  &lt;your username&gt;/node-web-app:latest  npm start  ...   49160-&gt;8080توی مثال بالا، داکر پورت داخلی 8080 کانتینر رو به پورت 49160 روی کامپیوترت مپ کرده.حالا اپلیکیشنت رو با استفاده از curl فراخوانی کن:$ curl -i localhost:49160

HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 12
ETag: W/&amp;quotc-M6tWOb/Y57lesdjQuHeB1P/qTV0&amp;quot
Date: Mon, 13 Nov 2017 20:53:59 GMT
Connection: keep-alive

Hello worldامیدوارم این خودآموز بهت کمک کرده باشه که بتونی یه اپلیکیشن ساده Node.js رو با Docker اجرا کنی.منبع: Dockerizing a Node.js web app از وبسایت رسمی نود جی‌اس</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Thu, 29 Apr 2021 16:07:43 +0430</pubDate>
            </item>
                    <item>
                <title>انواع loop برای آرایه‌ها: for و for-in و ()forEach. و for-of</title>
                <link>https://virgool.io/yavarjs/looping-over-arrays-imjsa9ifnwxs</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/looping-over-arraysدر این نوشته چهار روش مختلف برای استفاده از حلقه‌ها روی آرایه‌ها رو مقایسه می‌کنیم.حلقه‌ی for:for (let index=0; index &lt; someArray.length; index++) {
  const elem = someArray[index];
  // ···
}حلقه‌ی for-in:for (const key in someArray) {
  console.log(key);
}متد ()forEach. از کلاس Array:someArray.forEach((elem, index) =&gt; {
  console.log(elem, index);
});حلقه‌ی for-of:for (const elem of someArray) {
  console.log(elem);
}حلقه‌ی for-of در اغلب موارد بهترین انتخابه. در ادامه میبینم چرا.۱ - حلقه‌ی for [جاوااسکریپت ES1]حلقه‌ی ساده for در جاوااسکریپت قدمت داره و از نسخه‌ی ۱ ECMAScript وجود داشته. حلقه زیر اندیس و مقدار هر عنصر آرایه arr رو چاپ میکنه:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (let index=0; index &lt; arr.length; index++) {
  const elem = arr[index];
  console.log(index, elem);
}

// Output:
// 0, &#039;a&#039;
// 1, &#039;b&#039;
// 2, &#039;c&#039;نقاط مثبت و منفی این حلقه چیه؟کاملا همه‌کارس اما از طرفی وقتی فقط میخوایم روی آرایه حلقه بزنیم، نوشتنش طولانی و پرجزئیاته.اگه نمیخوایم از اولین عنصر آرایه شروع کنیم، این حلقه خیلی بدردبخوره. هیچکدوم از روش‌های دیگه این امکان رو بهمون نمیدن.۲ - حلقه‌ی for-in [جاوااسکریپت ES1] حلقه‌ی for-in به اندازه‌ی حلقه‌ی for قدمت داره. حلقه‌ی زیر کلید‌های آرایه‌ی arr رو چاپ میکنه:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (const key in arr) {
  console.log(key);
}

// Output:
// &#039;0&#039;
// &#039;1&#039;
// &#039;2&#039;
// &#039;prop&#039;for-in انتخاب خوبی برای حلقه‌زدن روی آرایه‌های نیست، چون:کلیدهای property رو مرور میکنه و نه مقادیر رو.اندیس‌های آرایه وقتی به صورت کلید‌های property دیده‌میشن، به جای این که عدد باشن، از جنس string هستن. ( اطلاعات بیشتر درمورد نحوه کار عناصر آرایه‌ها )به جای اندیس عناصر آرایه، تمام کلید‌های property که قابل شمارش هستن (enumerable) رو مرور میکنه (هم اونایی که مال خود آرایه هستن و هم اونایی که به ارث رسیدن).این ویژگی for-in که تمام propertyهای به ارث‌رسیده رو مرور میکنه یه جا کاربرد داره: زمانی که میخوایم روی propertyهای قابل شمارش یه object حلقه بزنیم. اما حتی در اون مورد هم حلقه زدن روی زنجیره prototype به شکل دستی بهتره، چون کنترل بیشتری در اختیارمون میذاره.۳ - متد ()forEach. [جاوااسکریپت ES5]با توجه به این که نه حلقه‌ی for و نه حلقه‌ی for-in انتخاب‌های خوبی برای حلقه‌زدن روی آرایه‌ها نیستن، یه متد کمکی در ECMAScript 5 معرفی شد: ()Array.prototype.forEach:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

arr.forEach((elem, index) =&gt; {
  console.log(elem, index);
});

// Output:
// &#039;a&#039;, 0
// &#039;b&#039;, 1
// &#039;c&#039;, 2این متد خیلی راحته: بدون نیاز به انجام کار زیاد ، هم دسترسی به اندیس و هم به عناصر آرایه رو میده. تابع‌های فِلشی (Arrow functions) که در ES6 معرفی شدن، این متد رو از قبل هم زیباترش کرده.معایب اصلی ()forEach. از این قراره:امکان استفاده از await در «بدنه» این نوع حلقه وجود نداره.از حلقه‌ی ()forEach. نمیشه زودتر از موعد خارج شده. درصورتیکه در حلقه‌های for میشه از break استفاده کرد.۱.۳ - خارج شدن از ()forEach. - یه راه حلیه راه حل برای خارج شدن از این حلقه هست: استفاده از ()some. که روی تمام عناصر آرایه حلقه میزنه و زمانی که تابع callback یه مقدار truthy (یه مقداری که بشه به معنی true تفسیرش کرد) رو برگردونه، متوقف میشه.const arr = [&#039;red&#039;, &#039;green&#039;, &#039;blue&#039;];
arr.some((elem, index) =&gt; {
  if (index &gt;= 2) {
    return true; // از حلقه خارج میشه
  }
  console.log(elem);
   // رو برمیگردونه undefined تابع به طور ضمنی مقدار
  // هست حلقه ادامه پیدا میکنه falsy که چون یه مقدار
});

// Output:
// &#039;red&#039;
// &#039;green&#039;۴ - حلقه‌ی for-of [جاوااسکریپت ES6]این حلقه در ECMAScript 6 اضافه شد:const arr = [&#039;a&#039;, &#039;b&#039;, &#039;c&#039;];
arr.prop = &#039;property value&#039;;

for (const elem of arr) {
  console.log(elem);
}
// Output:
// &#039;a&#039;
// &#039;b&#039;
// &#039;c&#039;حلقه‌ی for-of برای حلقه زدن روی آرایه‌ها خیلی خوبه، چون:روی عناصر آرایه تکرار میشه.داخلش میتونیم از await استفاده کنیم.و اگه نیاز پیدا کنیم خیلی راحت میتونیم به for-await-of کوچ کنیم.میتونیم از break و continue استفاده کنیم - حتی در اسکوپ (scope) های بیرونی‌تر.۱.۴ - حلقه‌ی for-of و آبجکت‌های iterableیه مزیت اضافه‌ی for-of اینه که با اون نه فقط روی آرایه‌ها بلکه روی آبجکت‌های iterable هم میشه حلقه زد - برای مثال، روی Mapها:const myMap = new Map()
  .set(false, &#039;no&#039;)
  .set(true, &#039;yes&#039;)
;
for (const [key, value] of myMap) {
  console.log(key, value);
}

// Output:
// false, &#039;no&#039;
// true, &#039;yes&#039;حلقه زدن روی myMap جفت [key, value] رو برمیگردونه که در کد بالا از روش destructre کردن برای دسترسی مستقیم به مقادیر این جفت استفاده کردیم.۲.۴ - حلقه‌ی for-of و اندیس‌های آرایهمتد ()keys. در آرایه‌ها، یه iterable روی اندیس‌های آرایه رو برمیگردونه:const arr = [&#039;chocolate&#039;, &#039;vanilla&#039;, &#039;strawberry&#039;];

for (const index of arr.keys()) {
  console.log(index);
}
// Output:
// 0
// 1
// 2۳.۴ - حلقه‌ی for-of و دسترسی همزمان به مقادیر و اندیس‌ها با ()entries.متد ()entries. در آرایه‌ها یه iterable روی جفت‌های [index, value] برمیگردونه. با استفاده از for-of و destructuring خیلی راحت میتونیم روی مقادیر و اندیس‌های آرایه به طور همزمان حلقه بزنیم:const arr = [&#039;chocolate&#039;, &#039;vanilla&#039;, &#039;strawberry&#039;];

for (const [index, value] of arr.entries()) {
  console.log(index, value);
}
// Output:
// 0, &#039;chocolate&#039;
// 1, &#039;vanilla&#039;
// 2, &#039;strawberry&#039;۵ - نتیجه‌گیریهمونطور که دیدیم، وقتی معیار کاربرد باشه حلقه‌ی for-of از بقیه‌ی روش‌ها بهتره.هر تفاوتی در سرعت (performance) بین این چهار روش حلقه‌زدن، در حالت عادی نباید اهمیتی داشته باشه. اگه اهمیت داره احتمالا داری یه کار خیلی سنگین از نظر محاسباتی انجام میدی و بنابراین استفاده از WebAssembly احتمالا گزینه‌ی معقول‌تری باشه.منبع: Looping over Arrays: for vs. for-in vs. .forEach() vs. for-of از وبلاگ 2ality - JavaScript and more</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Thu, 29 Apr 2021 04:38:23 +0430</pubDate>
            </item>
                    <item>
                <title>تاریخچه typeof null در جاوا اسکریپت</title>
                <link>https://virgool.io/yavarjs/typeof-null-vdgnyfdakrob</link>
                <description>نوشته رو در وبلاگ یاvar بخونید: yavarjs.ir/posts/typeof-nullخروجی typeof null توی جاوا اسکریپت برابر میشه با &quot;object&quot; که به نادرستی این معنی رو منتقل میکنه که null یک آبجکت (شیء) هست (در صورتی که نیست. null یه primitive value یا مقدار اولیه هست). این یه باگه که چون کدهای فعلی از کار می‌افتن نمیشه رفعش کرد.باگ «typeof null» بازمانده‌ی اولین نسخه‌ی جاوااسکریپته. توی اون نسخه، مقادیر در واحدهای ۳۲‌بیتی ذخیره میشدن که از یک برچسب (tag) ۱ الی ۳ بیتی برای تشخیص نوع و از بقیه‌ی بیت‌ها برای ذخیره کردن مقدار اصلی داده استفاده میشد. «برچسب‌های نوع داده» در بیت‌های کم‌ارزش ذخیره میشدن. پنج‌تا از این برچسب‌ها وجود داشت:000: آبجکت. داده به یک آبجکت اشاره میکنه.1: عدد صحیح (int). داده یک عدد صحیح علامت‌دار (signed integer) ۳۱‌بیتی هست.010: عدد double. داده یک مرجع به یک عدد اعشاری double هست.100: رشته (string). داده یک مرجع به یک رشته هست.110: بولی (boolean). داده یک بولین است.اگه بی‌ارزش‌ترین بیت مقدارش 1 بود، برچسب نوع داده یک بیتی بود و اگه بی‌ارزش‌ترین بیت 0 بود، برچسب نوع داده ۳ بیتی بود که از دو‌ بیت اضافه‌تر، برای تعیین چهار نوع داده مختلف استفاده میشد.دو مقدار ویژه هم وجود داشتن:مقدار undefined یا JSVAL_VOID که عدد صحیح 30^2- بود (یه عدد خارج از محدوده‌ی اعداد صحیح).مقدار null یا JSVAL_NULL که کد ماشین اشاره‌گر NULL بود: یک نوع داده آبجکت که مقدار اشاره‌گرش 0 بود.الان دیگه باید واضح باشه که چرا typeof برای null مقدار آبجکت رو برمی‌گردونه: برچسبِ نوع داده رو چک میکنه و ‌میبینه که برابر با آبجکت هست. کد اولین موتور جاوا اسکریپت برای typeof: https://gist.github.com/mahdavipanah/e74e1269660aa23bdf6f57ea74f0de71 گام‌هایی که کد بالا طی میکنه:گام (1)، موتور بررسی میکنه که آیا مقدار v برابر با undefined (VOID) هست یا نه. این بررسی با انجام یه دستور برابری انجام میشه:#define JSVAL_IS_VOID(v)  ((v) == JSVAL_VOID)بررسی بعدی (2) اینه که آیا مقدار موردنظر برچسب آبجکت داره یا نه. علاوه‌بر این اگه مقدار v قابل صدا زدنه یا به عبارتی callable هست (3) یا ویژگی داخلی [[Class]] اون داره میگه که یک تابع هست (4) پس بنابراین v یک تابعه. در غیر این صورت، یک آبجکته.این نتیجه‌ایه که برای typeof null تولید میشه.بررسی‌های بعدی برای اعداد، رشته‌ها و بولین هست. هیچ بررسی صریحی برای مقدار null وجود نداره، که می‌تونست خیلی راحت با یه ماکرو C انجام بشه:#define JSVAL_IS_NULL(v)  ((v) == JSVAL_NULL)این باگ شاید خیلی واضح به نظر بیاد، اما نباید فراموش کرد که برای نوشتن اولین نسخه‌ی جاوا اسکریپت زمان خیلی کمی در اختیار بود.منبع: The history of typeof null از وبلاگ 2ality - JavaScript and more</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 18 Apr 2021 18:04:27 +0430</pubDate>
            </item>
                    <item>
                <title>ساخت functionهای stateful در جاوا اسکریپت</title>
                <link>https://virgool.io/@mahdavipanah/%D8%B3%D8%A7%D8%AE%D8%AA-function%D9%87%D8%A7%DB%8C-stateful-%D8%AF%D8%B1-%D8%AC%D8%A7%D9%88%D8%A7-%D8%A7%D8%B3%DA%A9%D8%B1%DB%8C%D9%BE%D8%AA-j4pyqvhacmsa</link>
                <description>خیلی از زبان‌های برنامه‌نویسی امکانی رو به ما میدن که طول عمر یه متغیر داخل تابع رو، از هربار صدا زدن اون تابع طولانی‌تر کنیم (برای تابع یک state یا وضعیت تعریف کنیم که با هربار صدا زدنش بتونیم براساس وضعیتش کار متفاوتی انجام بدیم). برای مثال در زبان C با استفاده از متغیرهای static اینکارو انجام میدیم: https://gist.github.com/mahdavipanah/1057cbf5372947b984b0d61c18d81bef در جاوا اسکریپت به شکل‌های مختلف اینکار قابل انجامه. برای نمونه با استفاده از Class: https://gist.github.com/mahdavipanah/1f973498d4981eab71380aa8f8e06830 و یا با استفاده از IIEF که خیلی خودمونی میشه گفت «عبارت تابعیه فوری» یا به بیان ساده‌تر، یه تابع بی‌نامی هست که تعریف می‌کنیم و بلافاصله هم صداش میزنیم: https://gist.github.com/mahdavipanah/f80a0c5cd6270f8bb6965d8aff6a8354 </description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Fri, 16 Apr 2021 15:24:56 +0430</pubDate>
            </item>
                    <item>
                <title>تکه‌تکه‌ کردن راحت ویدئو با کامندلاین (لینوکس و مک)</title>
                <link>https://virgool.io/@mahdavipanah/splitting-video-file-kf6uslj9w6zb</link>
                <description>مسئله‌ی پیش رو: نیاز داریم تا یه فایل ویدئویی رو به بخش‌های مختلف و مشخصی تکه‌تکه کنیم و هرکدوم رو در قالب یه فایل ویدئویی جدید ذخیره کنیم.پیش‌نیاز: نصب FFmpeeg.اول یک فایل متنی ( times.txt ) می‌سازیم که در هر خط اون زمان مبدا و مقصد یه تکه از ویدئو مشخص شده: https://gist.github.com/mahdavipanah/b65f795a46629a957e8b6e8a90cda4ad#file-times-txt اسکریپت زیر رو در فایلی با پسوند sh. ذخیره می‌کنیم‌ ( cut-parts.sh ): https://gist.github.com/mahdavipanah/895878d2a8b36cad0acd0aacdf99bc13 با دستور زیر فایل اسکریپت رو به یه فایل با قابلیت اجرا شدن تبدیل می‌کنیم:$ chmod +x cut-parts.shدستور زیر رو اجرا می‌کنیم:$ ./cut-parts.sh input.mp4 times.txt ./parts-folderاسکریپت شامل سه ورودی میشه:اولین ورودی ( input.mp4 ): آدرس فایل ویدئو اصلی.دومین ورودی‌ ( times.txt ): آدرس فایل متنی‌ای که زمان برش‌ها رو داخلش نوشتیم.سومین ورودی ( parts-folder/. ): آدرس فولدری هست که می‌خوایم فایل‌های برش‌های ویدئویی داخلش ذخیره بشن.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sat, 10 Apr 2021 03:55:24 +0430</pubDate>
            </item>
                    <item>
                <title>توضیح Load Balancing به زبان ساده</title>
                <link>https://virgool.io/@mahdavipanah/load-balancing-gzwbsdlnrugc</link>
                <description>لود‌بالانسینگ (متعادل نمودن بار ترافیکی) یه مؤلفه‌ی کلیدی در زیرساخت‌های با دسترس‌پذیری بالاست که معمولا ازش استفاده میشه تا کارایی (performance) و قابلیت اطمینان (reliability) وب‌سایت‌ها، اپلیکیشن‌ها، دیتابیس‌ها و انواع دیگه‌ی سرویس‌ها، با توزیع کردن حجم کار روی چندین سرور، بالا بره.یه زیرساخت وب که هیچ لود‌بالانسینگی نداره احتمالا چیزی شبیه به تصویر زیره:توی این مثال، کاربر به طور مستقیم و از دامنه‌ی yourdomain.com به وب‌سرور متصل میشه. اگه این یک وب‌سرور از دسترس خارج بشه، کاربر دیگه نمیتونه به وب‌سایت دسترسی داشته باشه. علاوه‌بر این، اگه تعداد بیشتری کاربر تلاش کنن که به طور همزمان به سرور دسترسی داشته‌باشن و سرور نتونه به حجم درخواست‌ها رسیدگی کنه، کاربرها ممکنه با کاهش سرعت لود شدن و یا اساسا ناتوانی در اتصال به سرور مواجه بشن.مشکل این یک وب‌سرور، که نقطه‌ی حساسیه که میتونه باعث از کار افتادن کل سیستم بشه (single point of failure)، رو میشه با استفاده از یک load balancer و حداقل یک وب‌سرور اضافه‌ی دیگه در بک‌اند حل کرد. معمولا به این شکله که تمام سرورهای بک‌اند محتوای یکسانی رو به عنوان پاسخ درخواست به کاربر برمیگردونن تا کاربر همیشه محتوای سازگار و یکسانی رو فارق از سروری که به اون درخواست داده، دریافت کنه.در مثال بالا، ابتدا کاربر درخواستش رو به لود‌بالانسر میده که سپس لود‌بالانسر درخواست کاربر رو به یکی از سرورها در بک‌اند منتقل میکنه و بعد از اون سرور پاسخ درخواست کاربر رو به طور مستقیم میده. در مثال بالا، نقطه‌ای که میتونه به شکست کل سیستم منجر بشه، خود load balancer هست. این مشکل رو میشه با معرفی یک load balancer دوم حل کرد. اما قبل از اون بیاید تا ببینیم لود‌بالانسرها چجوری کار میکنن.لودبالانسر‌ها چه نوع ترافیکی رو میتونن مدیریت کنن؟ادمین‌های load balancer یک سری از قوانین فوروارد (forwarding rules) رو برای چهار نوع اصلی از ترافیک تعریف میکنن:پروتکل HTTP - این کار با هدایت کردن درخواست‌ها برپایه‌ی مکانسیم‌های استاندارد HTTP انجام میگیره. لودبالانسر هدر‌های X-Forwarded-For، X-Forwarded-Proto و X-Forwarded-Port رو تنظیم میکنه تا به بک‌اند اطلاعات لازم درمورد درخواست اصلی رو منتقل کنه.پروتکل HTTPS - بالانس کردن درخواست‌های HTTPS دقیقا شبیه به HTTP عمل میکنه با این تفاوت که رمزگزاری رو هم داخلش داره. رمزگزاری با یکی از این دو راه انجام میشه: یا با SSL passthrough ‌که رمزگزاری رو توی تمام مسیر تا بک‌اند برقرار میکنه و یا با SSL termination که مسئولیت رمزگشایی رو به دوش load balancer میذاره و ترافیکی که از لود‌بالانسر به بک‌اند میره رمزگزاری نشده است.پروتکل TCP - برای اپلیکیشن‌هایی که از HTTP یا HTTPS استفاده نمی‌کنن، ترافیک TCP رو نیز میشه بالانس کرد. برای مثال، میشه ترافیک یک کلاستر دیتابیس رو روی تمام سرورها پخش کرد.پروتکل UDP - به تازگی، بعضی از لودبالانسرها از پروتکل‌های هسته‌ی اینترنت مثل DNS و syslogd، که با UDP کار میکنن، هم پشتیبانی میکنن. قوانین فوروارد (forwarding rules) پروتکل و پورت روی خود لودبالانسر رو تعریف میکنن و اون‌ها رو نگاشت (map) میکنن روی پروتکل و پورتی که لودبالانسر از اون استفاده میکنه برای هدایت ترافیک در بک‌اند.چگونه load balancer سرور بک‌اند رو انتخاب میکنه؟لودبالانسرها برپایه‌ی ترکیب دو فاکتور انتخاب میکنن که درخواست رو به چه سروری منتقل کنن. load balancerها اول مطمئن میشن که سروری که میخوان انتخاب کنن میتونه به درستی به درخواست‌ها جواب بده و سپس از یک قانون از پیش‌تعیین‌شده برای انتخاب از بین سرورهای سالم استفاده میکنن.تست‌های سلامتیلودبالانسرها باید ترافیک رو فقط به سرورهای بک‌اند «سالم» ارسال کنن. برای مانیتور کردن سلامتی سرور بک‌اند، تست‌های سلامتی (health checks) به طور منظم تلاش میکنن تا با پورت و پروتکل تعریف شده در قوانین فوروارد، به سرورهای بک اند وصل بشن و مطمئن بشن که سرورها در حال گوش‌دادن برای درخواست هستند. اگه یه سرور تست سلامتی رو با موفقیت نگذرونه، و در نتیجه نتونه به درخواست‌ها رسیدگی کنه، به طور خودکار از استخر (pool) [مترجم: مجموعه‌ی سرورها] حذف میشه و دیگه ترافیکی به اون منتقل نمیشه تا زمانیکه دوباره به تست‌های سلامتی پاسخ بده.الگوریتم‌های Load Balancingاز الگوریتم load balancingی که تعیین شده استفاده میشود تا از بین سرورهای سالم در بک‌اند یکی انتخاب بشه. چندتایی از الگوریتم‌های متداول عبارتند از:الگوریتم Round Robin - این الگوریتم سرورها رو به ترتیب انتخاب میکنه. لودبالانسر برای اولین رکوئست، اولین سرور رو در لیست انتخاب میکنه و برای دومین رکوئست دومی رو و به همین ترتیب جلو میره و وقتی به آخر لیست رسید دوباره از اول شروع میکنه.الگوریتم Least Connections (کمترین اتصال‌ها) - این الگوریتم اول سروری رو انتخاب میکنه که در حال حاضر کمترین اتصال ممکن بهش انجام شده و استفاده از این الگوریتم زمانی توصیه میشه که ترافیک به نحویه که زمان اتصال رکوئست‌ها زیاده.الگوریتم Source (منبع) - لودبالانسر با این الگوریتم، برپایه‌ی هش IP منبع رکوئست، سرور رو انتخاب میکنه. این متد تضمین میده که یک کاربر مشخص، همواره به یک سرور یکسان وصل بشه.الگوریتم‌هایی که ادمین امکان استفاده ازشون رو داره، براساس نوع تکنولوژی load balancerی که ازش استفاده میکنه، میتونه متفاوت باشه.چجوری لودبالانسر stateها رو مدیریت میکنه؟بعضی از اپلیکیشن‌ها نیاز دارن تا کاربر همواره به یک سرور یکسان در بک‌اند متصل بشه. یک راه، استفاده از یک الگوریتم Source هست که نوعی وابستگی رو بین اطلاعات IP کاربر و سروری که بهش متصل میشه ایجاد میکنه. راه دیگه برای حل این مشکل در سطح اپلیکیشن وب، اسمش sticky sessions هست. در این روش، لود بالانسر یک cookie مخصوص رو ست میکنه و با استفاده از اون همه‌ی درخواست‌های اون session به یک سرور فیزیکی یکسان فرستاده میشن.لودبالانسر‌های اضافیبرای این که load balancer در سیستم به نقطه‌ی شکست تبدیل نشه، یک load balancer دوم رو اضافه میکنیم تا با اولی تشکیل یه خوشه (cluster) بدهند. در این طراحی، هر لودبالانسر، وضعیت سلامتی دیگری رو زیرنظر داره و هرکدوم از اون‌ها به طور یکسان قابلیت تشخیص شکست و بهبود دارند.در صورتیکه لودبالانسر اصلی از کار بیافته، DNS مسئول اینه که کاربرها رو به لودبالانسر دوم هدایت کنه. از اونجایی که اعمال تغییرات DNS در اینترنت میتونه زمان قابل توجهی رو بگیره و برای این که حل مشکلِ از کارافتادنِ لودبالانسر به طور اتوماتیک انجا بشه، خیلی از ادمین‌ها از سیستم‌هایی مثل IPهای شناور (floating IPs) استفاده میکنن که اجازه‌ میدن نگاشتِ آدرس‌های IP به طور منعطف انجام بشه. با اینکار، در صورت نیاز سیستمِ نگاشت ِآدرس‌هایِ IP، پروسه‌ی تکثیر (propagation) و caching که در ذات تغییرات DNS هست رو با انتصاب یک IP استاتیک، که در صورت نیاز به آسانی قابل تغییره، حل میکنه. نام دامنه همیشه به یک IP یکسان متصله و تنها خود آدرس IP بین سرورها جابه‌جا میشه.در زیر، میتونید یک زیرساخت با دسترس‌پذیری بالا رو که از IPهای شناور استفاده میکنه، مشاهده کنید:منبع: https://www.digitalocean.com/community/tutorials/what-is-load-balancingلینک نوشته در وبلاگ شخصی من: mahdavipanah.com/blog/load-balancing</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Mon, 30 Dec 2019 18:52:47 +0330</pubDate>
            </item>
                    <item>
                <title>چک‌لیست امنیتی API</title>
                <link>https://virgool.io/apieco/%DA%86%DA%A9%D9%84%DB%8C%D8%B3%D8%AA-%D8%A7%D9%85%D9%86%DB%8C%D8%AA%DB%8C-api-arbeviscqkbx</link>
                <description>داستان ترجمهبه طور خیلی اتفاقی به یه مخزن Github رسیدم که استار خیلی زیادی داشت و داخلش چک‌لیستی از موارد امنیتی مهمی رو که باید در حین طراحی، پیاده‌سازی و دپلوی APIها رعایت کرد، قرار داده بود.چون کوتاه بود و با خوندنش حس کردم خیلی مفیده، تصمیم گرفتم ترجمش کنم. بعد از این که ترجمه کردم و چند بار مرور و ویرایش کردم، مشکل راست‌به‌چپ کردن فایل مارک‌داون رو حل کردم و بعد دیدم که متاسفانه وقتی با ترفندی که توی استک اورفلو پیدا کرده بودم، فایل مارک‌داون رو راست‌به‌چپ میکنم، checkboxها میافته روی متن! واقعا از دست Github عصبانی بودم و در نهایت با کلی آزمون و خطا و با کمک ;nbsp&amp; مشکل رو حل کردم :)توی pull requestهای مخزن دیدم که دوتا پول‌رکوئست فعال برای ترجمه‌ی فارسی وجود داره! یکی از پول‌رکوئست‌ها که جدیدتر هم بود ترجمه‌ی خوبی نداشت و مترجم، فایل مارک‌داونش رو راست‌به‌چپ نکرده بود! پول‌رکوئست دومی ترجمه‌ی خوبی داشت (و از بخش‌هایی از ترجمش برای بهتر کردن ترجمه‌ی خودم هم استفاده کردم) و فایل مارک‌داونش هم راست‌به‌چپ بود ولی مشکل روهم‌افتادن checkboxها رو حل نکرده بود. پس خودم یه پول‌رکوئست جدید درست کردم و موارد بالارو داخلش توضیح دادم‌.لینک مخزن گیت‌هاب چک‌لیست. نگاه کنید و اگه خوشتون اومد استار کنید. در ادامه‌ی نوشته ترجمه‌ی خود چک‌لیست رو هم قرار میدم چون ویرگول نوشته رو حذف کرد به دلیل تبلیغات و لینک‌سازی! اما توجه داشته باشید که چک‌لیست در واقع یه چیز پویاست که میتونه تغییر کنه و موارد مختلفی به اون اضافه یا کم بشه و اگه واقعا می‌خواین نسخه‌ی بروزش رو ببینید باید از گیتهاب اینکارو بکنید. https://github.com/mahdavipanah/API-Security-Checklist/blob/add-persian/README-fa.md چک‌لیست امنیتی APIچک‌لیستی از مهم‌ترین کارهای لازم برای حفظ امنیت در زمان طراحی، تست و انتشار API.احراز هویتاز Basic Auth یا همان اصالت‌سنجی برای دسترسی‌های اولیه استفاده نکن. به جای آن از روش‌های استاندارد احراز هویت استفاده کن (مثلا JWT یا OAuth).برای کارهایی مثل احراز هویت، تولید توکن و ذخیره پسوورد چرخ را دوباره اختراع نکن. از استانداردها استفاده کن.برای لاگین محدودیت‌های تعداد ماکسیمم تلاش مجدد و تعداد دفعات ورود را قرار بده.همه‌ی داده‌های حساس را رمزگذاری کن.JWT (JSON Web Token)از یک کلید پیچیده‌ی تصادفی برای JWT Secret استفاده کن تا حمله‌ی بروت‌فورس به توکن بسیار سخت باشد.الگوریتم را از هدر استخراج نکن. در بک‌اند الگوریتم را تحمیل کن (HS256 یا RS256).انقضای توکن (TTL یا RTTL) را تا حد ممکن کوتاه کن.اطلاعات حساس را در پی‌لود JWT ذخیره نکن چون به راحتی قابل رمزگشایی است.OAuthهمیشه redirect_uri را در سمت سرور اعتبارسنجی کن تا تنها به URLهای مجاز اجازه داده شود.همیشه تلاش کن تا code را به جای token تبادل کنی (اجازه response_type=token را نده).از پارامتر state با یک هش تصادفی استفاده کن تا از CSRF روی پروسه‌ی احراز هویت OAuth جلوگیری کنی.مقدار scope پیش‌فرض را تعریف کن و پارامترهای scope را برای هر اپلیکیشن اعتبارسنجی کن.دسترسیرکوئست‌ها را محدود کن (Throttling) تا از حملات DDos یا بروت‌فورس جلوگیری شود.در سمت سرور از HTTPS استفاده کن تا از حملات مرد میانی جلوگیری شود.از هدر HSTS استفاده کن تا از حمله‌ی SSL Strip جلوگیری شود.ورودیاز متد HTTP مناسب با توجه به نوع عملیات استفاده کن: GET برای خواندن، POST برای ایجاد کردن، PUT/PATCH برای جایگزین یا بروزرسانی و DELETE برای حذف یک رکورد، و در صورتیکه متد درخواستی برای منبع درخواست‌شده مناسب نیست با 405 Method Not Allowed پاسخ بده.مقدار content-type را در هدر Accept رکوئست (مذاکره محتوا یا Content Negotiation) اعتبارسنجی کن تا فقط به فرمت‌های مورد پشتیبانی اجازه داده شود (مثلا application/xml، application/json و ...).مقدار content-type در داده‌ی پست‌شده را اعتبارسنجی کن (مثلا application/x-www-form-urlencoded، multipart/form-data، application/json و ...).ورودی کاربر را اعتبارسنجی کن تا از آسیب‌پذیری‌های معمول جلوگیری شود (مثلا XSS، SQL-Injection و Remote Code Execution).هیچ داده‌ی حساسی مثل (داده‌های اعتبارسنجی، پسوورد‌ها، توکن‌های امنیتی یا کلید‌های API) را داخل URL قرار نده و از هدر Authorization استاندارد استفاده کن.از یک سرویس API Gateway استفاده کن تا کش‌کردن و سیاست‌های Rate Limit (مثلا Quota، Spike Arrest یا Concurrent Rate Limit) فعال شوند و منابع APIها را به صورت داینامیک دپلوی کن.پردازشچک کن که تمامی endpointها توسط احراز هویت محافظت شوند تا از شکستن پروسه‌ی احراز هویت جلوگیری شود.از استفاده از ID ریسورس خود کاربر اجتناب کن. به جای user/654321/orders از /me/orders استفاده کن.از IDهای auto-increment استفاده نکن. به جای آن از UUID استفاده کن.اگر فایل‌های XML را parse میکنی مطمئن شو تا entity parsing غیرفعال باشد تا از XXE (XML External entity attack) جلوگیری شود.اگر فایل‌های XML را parse میکنی، مطمئن شو تا entity expansion غیرفعال باشد تا از Billion Laughs/XML bomb توسط exponential entity expansion attack جلوگیری شود.از یک CDN برای آپلودهای فایل استفاده کن.اگر با مقادیر بسیار حجیمی از داده باید کار کنی، از Workerها و Queueها استفاده کن تا حداکثر پردازش در بک‌گراند انجام شود و سریع پاسخ را برگردان تا از HTTP Blocking جلوگیری شود.خاموش کردن حالت DEBUG را فراموش نکن.خروجیهدر X-Content-Type-Options: nosniff را ارسال کن.هدر X-Frame-Options: deny را ارسال کن.هدر &#x27;Content-Security-Policy: default-src &#x27;none را ارسال کن.هدرهایی که به نوعی اثرانگشت برجای میگذارند را حذف کن، مثلا X-Powered-By، Server و ‍X-AspNet-Version.مقدار content-type را برای جواب اجباری کن. اگر application/json برمیگردانی، پس content-type پاسخ application/json است.اطلاعات حساس مثل داده‌های اعتبارسنجی، پسوورد‌ها و توکن‌های امنیتی را برنگردان.با توجه به عملیات انجام‌شده، status code مناسب را برگردان. مثلا 200 OK، 400 Bad Request، 401 Unauthorized و 405 Method Not Allowed.CI &amp; CDطراحی و پیاده سازی خودت را با پوشش تست‌های unit/integration بازرسی کن.از یک پروسه‌ی مرور کد استفاده کن و خود-تاییدی را نادیده بگیر.مطمئن شو تا تمامی اجزای سرویس‌هایت، شامل کتابخانه‌های استفاده‌شده و دیگر وابستگی‌ها، قبل از انتشار در حالت production، به طور ایستا توسط نرم‌افزارهای آنتی‌ویروس اسکن شده‌اند.برای دپلوی، یک راه‌حل با قابلیت عقبگرد (rollback) طراحی کن.نگاهی بیانداز به:yosriady/api-development-tools - یک مجموعه از منابع بردردبخور برای ساختن APIهای RESTful با HTTP و JSON -مشارکتبرای همکاری و کمک می‌توانی به راحتی این مخزن را fork کنی، تغییرات مورد نظرت را اعمال کنی و یک pull request ثب کنی. اگر سوالی داشتی به آدرس team@shieldfy.io ایمیل بزن.</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Wed, 25 Dec 2019 15:12:44 +0330</pubDate>
            </item>
                    <item>
                <title>انسان، تکنولوژی و زمان</title>
                <link>https://virgool.io/@mahdavipanah/%D8%A7%D9%86%D8%B3%D8%A7%D9%86-%D8%AA%DA%A9%D9%86%D9%88%D9%84%D9%88%DA%98%DB%8C-%D9%88-%D8%B2%D9%85%D8%A7%D9%86-gzhfuamh23ih</link>
                <description>مفهموم «زمان» به طور مستقل میتونه عنوانی برای ساعت‌ها بحث و گفت‌و‌گو باشه. آیا زمان بُعدی است کاملا مستقل؟ تاثیراتی که کشفیات انیشتین روی مفهوم زمان گذاشت چه بود؟ و بیشمار سوالهایی که میشه مطرح کرد و تبدیلش کرد به میدون مبارزه‌ی بی‌نظیری بین فیزیک‌دان‌ها، فیلسوف‌ها و اصولا هرکسی که کمی به مفاهیم اینچنینی علاقه داره.من نه فیزیک‌دانم و نه فیلسوف. پس طبیعیه که مطالعه و اطلاعات عمیق و خاصی در خصوص ماهیت «زمان» ندارم. چیزی که من رو به مفهوم زمان خیلی علاقه‌مند کرد، در وهله‌ی اول ارتباطش با نور بود! که خب متفاوته با چیزی که اینجا میخوام مطرح کنم، و در وهله‌ی دوم ایده‌ای بود که توی کتاب «انسان خردمند» باهاش آشنا شدم و بعد با مرور زمان بیشتر و بیشتر بهش فکر کردم.اینطور که به نظر میاد با پیشرفت تمدن، همواره سرعت زندگی آدم‌ها بیشتر شده و در نتیجه اهمیت زمان روز به روز افزایش پیدا کرده. به طور مثال، انسان شکارچی و خوراکجویی رو فرض کنید که راه زندگی و زنده‌موندش وابسته به اینه که در روز به دنبال جمع کردن میوه و شکار حیوانات باشه و در شب به استراحت بپردازه. در این شرایط، هیچ موجودی نیاز به داشتن فهم خاصی از زمان نداره. بالاترین طبقه‌بندی زمانی از نظر یک انسان اینچنینی، درک تفاوت روز و شبه. بعدها که انسان‌ها یکجانشین و کشاورز شدند، اهمیت زمان کم‌کم بیشتر شد. یک انسان کشاورز باید درک میکرد که فصل‌ها چه هستند، چه روزهایی احتمال بارش باران بیشتره و ... انسان کم‌کم درکی انتزاعی از مفهوم «زمان» پیدا کرد. یعنی اساسا انسان خوراکجو نیازی به داشتن درک از متغیر زمان به شکل امروزی نداشت. امروزه بچه‌های ما در سنین ۵ یا ۶ سالگی درک بسیار بالاتری از مفهوم زمان نسب به یک انسان خوراکجوی اولیه دارند و این در صورتیه که هردوی اینها از ژنتیک یکسانی برخوردارند.انقلاب صنعی داستان رو از قبل هم پیچیده‌تر کرد. انسان تلاش کرد تا با ساخت ابزارهای مختلف بتونه سرعت کارهای روزمرشو بیشتر و بیشتر کنه و به این ترتیب زمانی که در اختیار داره رو بهینه‌تر استفاده کنه. این فرآیند چیزی نبود که از انقلاب صنعتی شروع بشه ولی بهترین نمونه‌ی تلاش انسان برای تاثیر بر زمان رو میشه در انقلاب صنعتی دید. فیلم‌های چارلی چاپلین و انتقاد‌های او به دنیای آهنی و پرسرعت بعد از انقلاب صنعتی یادآور رابطه‌ی تنگاتنگ انسان، تکنولوژی و زمانه.تمدن با سرعت جلو میره و هر روز شاهد اختراع ابزارهایی هستیم که ما رو در کارها بیشتر و بیشتر کمک میکنه و باعث میشه زمان بیشتری در اختیار داشته باشیم. با چند حرکت انگشت روی صفحه‌ی گوشی هوشمند میتونیم سفارش غذا بدیم، به فردی در اونور دنیا پیام بدیم و ... اینها نمونه‌ای از کارهاییه که بدون تکنولوژی، زمان‌بر و پردردسر بود. اما سوال اساسی از نظر من اینه: با این زمان اضافه چیکار باید بکنیم؟به لطف تکنولوژی، در روز زمان بیشتری در اختیار داریم؛ تا اینجاش که خوب به نظر میاد. اما، این زمان اضافه رو دوباره با تکنولوژی هدر میدیم! چجوری؟ با ساعت‌ها چرخیدن در شبکه‌های اجتماعی. یعنی عملا تکنولوژی زمان بیشتری در اختیار ما قرار میده ولی از طرفی ما رو غرق در ابزارهایی میکنه که ساعت‌های پای اونها وقت میگذرونیم و در این بین تبدیل میشیم به منبع درآمد اصلی هزاران کسب‌‌و‌کار. با زمان اضافه‌ی خودمون، شروع میکنیم به ساختن داده برای شبکه‌های اجتماعی که اون‌ها هم از اون داده‌ها برای کسب پول و تبلیغات استفاده می‌کنن. زیباست!از تئوری توطئه که فاصله بگیریم، به عقیده‌ی من تازه میرسیم به بحثی جدی‌تر! این که اگه فرض کنیم این وقت اضافه رو که به دلیل موهبت تکنولوژی در اختیار داریم، دوباره در تکنولوژی هدر ندیم، پس باید دقیقا باهاش چیکار کنیم؟با همین سواله که من به این نتیجه میرسم: زمان بزرگترین و مهمترین متغیر در زندگی انسان امروزیه.شما امروز با چند کلیک ساده میتونید هر کتابی در هر زمینه‌ای رو به هر زبانی که میخواید دانلود کنید و در دسترس داشته باشید. موهبت اطلاعات، معجزه‌ی قرن فعلیه. پس اگه اطلاعات در اختیارمون هست و تکنیک و فنون هم به راحتی از اینترنت قابل یادگیریه، پس چرا همه‌ی آدم‌ها در یک زمینه‌ی خاص متخصص نیستند؟ به نظر من: چون اساسا چیزی که مهمه اینه که زمان رو در کجا خرج می‌کنیم.بیاید فرض کنیم که مغز، مهم‌ترین و پایه‌ای‌ترین رکن انسان باشه. نگاهی کاملا مادی‌گرا. در طی میلیون‌ها سال تکامل و فرگشت، مغز انسان توانایی خارق‌العاده‌ای در یادگیری و همچنین ارتباط زبانی با همنوعان خودش پیدا میکنه. این توانایی فوق‌العاده در یادگیری در زمان خوراک‌جویی و شکار، به انسان بدوی کمک میکرد تا بتونه از پس موانع و سختی‌های زندگی در طبیعت وحشی بربیاد و به بقای خودش و همنوعانش کمک کنه. صدها هزارسال طی میشه و گونه‌ی انسان تبدیل میشه به مسلط‌ترین گونه‌ی روی کره‌ی زمین و حتی تا جایی پیش میره که از بالای درخت خودش رو میرسونه به کره‌ی ماه!قبل از عصر اطلاعات، توانایی یادگیری مغز برای یادگرفتن از محیط وحشی پیرامونش استفاده میشد. برخلاف تصور ما، انسان‌های ماقبل تاریخ نه تنها احمق و کودن نبودند که اتفاقا بسیار ماهر و باهوش بودند. مهارت اونها در کار با کامپیوتر نبود، بلکه در زنده‌موندن در محیط طبیعی وحشی بود. محیطی که در اون نه تنها انسان جزو بزرگترین حیوانات شکارچی نبود که اتفاقا به دلایلی (مثل ناتوانی زیاد کودکان انسان) بسیار آسیب‌پذیر هم بود. اگه یک انسان امروزی رو در محیط مشابه قرار بدیم، بعید به نظر میاد که بتونه بیشتر از چند روز زنده بمونه. پس از عصر اطلاعات انسان با منبع بسیار عظیمی از اطلاعات و دانش مواجهه. پس حداقل در تئوری میتونه از توانایی مغز خودش به طور کامل استفاده کنه و در یک یا چند زمینه استاد تمام بشه! یعنی دقیقا چیزی که معمولا خانواده‌ها از بچه‌هاشون توقع دارن‌:) درس بخون درس بخون و درس بخون!به نظر من اطلاعات تنها برای پرورش مغزی مفید و بزرگ کافی نیست! آزمون و خطا و تجربه کردن در محیط پیرامون (جمع دوستان، سفرهای مختلف و ...) و در معرض خطر قرار گرفتن لازمه‌ی رشد روانی یک انسانه. چطور میشه مغزی که برای زندگی در محیطی وحشی تکامل پیدا کرده، بتونه بدون بوجود آمدن مشکلات روانی، در محیطی کاملا امن و به دور از هیچگونه خطر، فقط درس بخونه، درس بخونه و درس بخونه؟به عقیده‌ی من هر تجربه، هر قطعه‌ی موسیقی، هر کتاب، هر گفت‌و‌گو و هر تراکنش با افراد یا محیط پیرامون ما رو کمی رشد میده، تغییر میده و در نهایت پس از گذر زمان کافی، برآیندی از این ورودی‌هاست که ما رو در لحظه تعریف می‌کنه. در عصری که همه‌چیز با سرعت در حال سپری شدنه و همه در تلاشی بی‌وقفه برای رسیدن به هدفی کوتاه یا بلند‌مدت هستند، مهمه که بشناسیم و درک کنیم که چه ورودی‌هایی به ذهن خودمون میدیم. ما در ایده‌آل‌ترین حالت ۱۰۰ سال و در واقع‌بینانه‌ترین حالت ۷۰ سال عمر میکنیم. پس طبیعیه که زمان کافی برای تجربه کردن، خواندن و شنیدن همه‌چیز نداریم. پس در واقع هنر انسان امروزی نه در جمع‌آوری میوه‌ها در دل طبیعت وحشی و نه در توانایی شکار کردن، بلکه در گلچین کردن و انتخاب ورودی‌هایی است که به ذهن و مغز خودش میده. چرا که با گذر زمان کافی همه‌ی ما میتونیم شهادت بدیم که هر دیده، شنیده و تجربه‌ای که داشتیم، در روزی و در مکانی خاص تاثیرش رو در زندگی ما خواهد گذاشت. پس زمان مهمه. این که زمان خودمون رو با چه اولویتی و به چه تجربیات و فعالیت‌هایی اختصاص میدیم عاملیه که زندگی و خود ما رو خواهد ساخت.لینک نوشته در وبلاگ شخصی من: mahdavipanah.com/blog/man-technology-time</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Sun, 03 Nov 2019 19:37:02 +0330</pubDate>
            </item>
                    <item>
                <title>الگوریتم‌هایی که شما رو اعدام می‌کنن!</title>
                <link>https://virgool.io/@mahdavipanah/%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85%D9%87%D8%A7%DB%8C%DB%8C-%DA%A9%D9%87-%D8%B4%D9%85%D8%A7-%D8%B1%D9%88-%D8%A7%D8%B9%D8%AF%D8%A7%D9%85-%D9%85%DB%8C%DA%A9%D9%86%D9%86-klnk6pffkmhw</link>
                <description>تیتر عجیب یک خبر در SienceMag مشتاقم کرد تا کمی بیشتر درمورد نرم‌افزارهای دادگاهی سرچ کنم. تیتر خبر اینه:یک نماینده‌ی ِ مجلس ِ آمریکا خواستار بررسی دقیق‌تری پیرامون الگوریتم‌هایی است که در دادگاه‌های جنایی استفاده می‌شونداینطور که مشخصه در دادگاه‌های ایالات متحده از نرم‌افزارها برای کارهای مختلفی، مثل تطبیق DNAهای موجود در صحنه‌ی جرم با DNA متهمین، تشخیص و تطبیق اثر انگشت و تشخیص و تطبیق صورت اشخاص در فیلم‌های ضبط‌شده در دوربین‌های امنیتی استفاده میشه.https://www.nature.com/articles/d41586-018-05469-3 :منبع عکسمشکل اینه که شرکت‌های مختلفی وجود دارن که این نرم‌افزارها رو تولید می‌کنن و اینطور که پیداست اکثر این نرم‌افزارها متن‌باز و آزاد نیستن و شرکت‌های سازندشون حاضر نیستن تا سورس کد این برنامه‌ها رو در اختیار دیگران (مثل تیم مدافعین متهمان و دادگاه) قرار بدن و حتی حاضر نیستن تا درمورد نحوه‌ی نتیجه‌گیری این نرم‌افزارها هم داده‌های مهمی رو ارائه کنن و دلایل متعددی هم برای این کار دارن، از جمله این که نمیخوان شرکت‌های رقیب از تکنولوژیشون سر در بیارن.حالا فرض کنید که آدما می‌تونن به خاطر خروجی‌هایی که این نرم‌افزارها و الگوریتم‌ها ارائه‌می‌کنن، به زندان و یا حتی مرگ محکوم بشن! و حتی در بعضی مواقع تنها شواهد موجود در پرونده نتایج همین الگوریتم‌هاست! و خب الان صدای خیلیا از جمله یک نماینده مجلس آمریکا به نام Mark Takano دراومده که داره تلاش می‌کنه تا لایحه‌ای رو تصویب کنه که اجازه میده روی این نرم‌افزارها بررسی دقیقی انجام بشه تا چیزهای زیادی مثل خطا و یا این که آیا این نرم‌افزارهای نسبت به اقلیت‌ها تعصبی دارن یا نه مشخص بشه.از قرار معلوم یکی از مهم‌ترین دسته‌های این نرم‌افزارها اسمش هست probabilistic genotyping software که ترجمه‌ی تحت‌اللفظیش میشه نرم‌افزار ژنوتیپ احتمالی که برای تشخیص و تطبیق DNA یک فرد مظنون در بین DNAهایی که از صحنه‌ی جرم جمع‌آوری شده استفاده میشه. از اونجا که DNAهای صحنه‌ی جرم ممکنه آسیب‌دیده باشه و یا با مواد دیگه‌ای آلوده شده باشه و حتی حاوی چند DNA مختلف باشه، تشخیص DNAهای موجود در اون و این که آیا DNA فرد خاصی در اون نمونه هست یا نه همیشه کار راحتی نیست و بنابراین از این نرم‌افزارها استفاده میشه تا با یک احتمال مشخص وجود یک DNA خاص در اون نمونه تعیین بشه.علاوه بر این که این نرم‌افزارها رو شرکت‌های مختلفی تولید میکنن و سورس و نحوه‌ی کارشون رو هم در اختیار دیگران قرار نمیدن، مشکل دیگه اینه که قاضی‌ها، وکیل‌های مدافع، دادستان‌ها و دیگر افرادی که در پروسه‌ی یک پرونده‌ی جنایی درگیرن، معمولا اطلاعات کافی و درستی درمورد این الگوریتم‌ها و حتی تفسیر خروجی اون‌ها ندارن!اگه به خوندن بیشتر درمورد نرم‌افزارهای ژنوتیپ احتمالی علاقه دارید پیشنهاد میکنم این مقاله‌ی کوتاه و جالب رو (که دیوان محاسبات آمریکا اون رو نوشته) مطالعه کنید که خیلی خلاصه توضیحی درمورد نحوه‌ی کار و همچنین مزایا و معایب این نرم‌افزارها داده.و خب جدای همه‌ی این جزئیات چیزی که آدمو به فکر میبره، اینه که یه روزی ممکنه همه‌ی چیزی که ما به عنوان دادگاه، قاضی و پروسه‌ی عادلانه‌ی قضاوت می‌شناسیم، با یکسری الگوریتم و هوش‌مصنوعی جایگزین بشه!سناریوی بدترش اینه که فرض کنیم نرم‌افزارهایی در دادگاه‌ها استفاده بشن که از شبکه‌های عصبی مصنوعی استفاده کنن. خب مشکلش چیه؟ حتی اگه شرکت سازندش اجازه هم بده، نمی‌تونیم از درونش سردربیاریم! فرض کنید روزی رو که یک جعبه‌ی سیاه بزرگ وجود داره و متهم‌ها توی صف ایستادن و وقتی نوبتشون میشه از اون جعبه یک حکم پرینت میشه و میاد بیرون!لینک نوشته در وبلاگ شخصی من: mahdavipanah.com/blog/algorithms-criminal-trials</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Tue, 24 Sep 2019 18:19:03 +0330</pubDate>
            </item>
                    <item>
                <title>رابطه‌ی عاطفی ما با خونه‌هامون</title>
                <link>https://virgool.io/@mahdavipanah/homes-d9jaiprxv84o</link>
                <description>عکس صرفا تزئینیه و با گوشی در روستای قمصر گرفتماین اولین بارم نیست. در اصل این دومین خونه‌ای بود که تاحالا توش زندگی کردم. خونه‌ی اولمون یک خونه‌ی سازمانی بود که تا هشت سالگیم اونجا بزرگ شدم. خونه‌ای ساده با حیاطی بزرگ و یه باغچه‌ی نسبتا پر گل و گیاه و درخت گل یاسی که هیچوقت از یادم نمیره. درخت گل یاسی که پدربزرگ خدابیارزم همیشه بهش رسیدگی می‌کرد. هنوز که هنوزه هرموقع بوی گل یاس به دماغم می‌خوره ناخودآگاه پرت میشم به همون حیاط، همون کوچه و همون دوران کودکی. خداحافظی با خونه‌ی اول برام خیلی ساده بود. سنم کم‌تر بود و بنابراین مثل آدم‌بزرگا هنوز درگیر خاطرات نبودم و وابستگی مسئله‌ی جدی‌ای به حساب‌نمیومد؛ مخصوصا برای خونه‌ای درب و داغون و مخصوصا برای منی که بسیاری از زمان‌های کودکیم رو توی خونه‌ی خالم گذرونده بودم. تصاویری که از اون دوران توی ذهنمه خیلی درهم و برهم و محوه؛ ملغمه‌ای از باغ اونور کوچمون و خونه‌ی همسایه‌ی کشاورزمون که اسمش آقای «چرب‌دست» بود و همچنین کوچه‌ای که انتهاش خاکی بود و برای من ِ پنج شش‌ساله حکم انتهای دنیا را داشت. جرئت می‌طلبید رفتن تا آخر اون کوچه، اما ارزششو داشت، چون دقیقا همون‌جایی که جاده‌ی خاکی شروع می‌شد جائی بود که سمت راستش راه داشت به یک محوطه‌ی باغ‌مانند و باز که برکه‌ی آب توش جاری بود و درخت توتی اونجا بود که از بهترین شادی‌های بچه‌های محل محسوب می‌شد. توت‌های سفید و درشت که شیرینیش هنوز زیر زبونمه.هشت سالم که بود ساخت خونه‌ی جدید شروع شد. خونه‌ای که در کاشان، شهر کنار زادگاهم واقع شده بود. در همون آغاز ساخت خونه، برای این که من با محیط شهر جدید وفق بگیرم و تا زمانی که قراره ساکن بشیم، دوستایی برای خودم داشته باشم و شروع زندگی در شهر جدید ساده‌تر باشه، سال دوم دبستان رو در مدرسه‌ای جدید در کاشان شروع کردم، دبستان ملامحسن. صبح‌ها به همراه داییم مسیر نیم‌ساعته تا کاشان را طی می‌کردم و بعد از تعطیلی مدرسه، پیاده به کارگاه نجاری دائیم که تا دبستان فاصله‌ی کمی داشت می‌رفتم و بعد از اتمام کار دایی، باهم برمی‌گشتیم.خونه‌ی جدید و مدرسه‌ی جدید و کارگاه دائیم در یک محله بود و بنابراین این سه مکان اصلی‌ترین خاطرات اون دوران من رو در خودش جای میده. بعد از تعطیلی مدرسه و مراجعه به کارگاه داییم، بعضی روزها به خونه‌ی جدید می‌رفتیم و به دایی در انجام کارهای چوبی خونه‌ی جدید (که دیگه داشت تکمیل می‌شد) کمک می‌کردم. منگنه‌های پارکت کف خونه رو با مغار بیرون می‌کشیدم و بعد دایی جای اونارو صیقل می‌کرد و رنگ میزد. این روند ادامه داشت و من، تولد و رشد خونه‌ی جدید رو از نزدیک شاهد بودم. خونه‌ای که داشت همپای کودکی من بزرگ می‌شد و مکانی رو آماده می‌کرد که تمام دوران نوجوانی و ابتدای جوانیم رو در اون بگذرونم.از اون روزها ۱۶ سال ناقابل می‌گذره و الان که در حال نوشتن این کلماتم، کمتر از ۲۴ساعته که در خونه‌ای جدید (که خونه‌ی سومم حساب می‌شه) ساکن شدیم. خونه‌ای که آپارتمانیه و محوطه‌ای بزرگ و مشترک بین چندتا بلوک داره و تعداد همسایه‌هامون چند‌ده برابر خونه‌ی قبلیه!اما این‌ها دلیل نمی‌شه تا هنوز خونه‌ی جدید رو بیشتر از خونه‌ای که ساختنش رو ذره‌ذره شاهد بودم، دوست‌داشته‌باشم. خونه‌ی قبلیمون رو کماکان داریم، اما قراره دایی بزرگترم، همونی که صاحب کارگاه نجاری بود، اونجا ساکن بشه. اول که این خبر رو شنیدم واقعا بهم ریختم! ترکیبی از حس حسادت، عصبانیت و غم داشت دیوونم می‌کرد! و جالبتر این که این اولین بار بود که همچین حسی رو، اون‌هم برای یک ساختمون(!) تجربه می‌کردم. یه جوری انگار منی که با داییم خونه رو ساخته بودیم، بعد از ۱۶ سال داشت از چنگم درش میاورد :) بیشتر که فکر کردم همه‌چیز یادم اومد. تمام اون ۱۶‌سال مثل فیلم از جلوی چشمام گذشت. تمام خاطرات ریز و درشت، گریه‌ها و خنده‌ها و تک‌تک ملاقات‌ها و ثانیه‌هایی که من ِ ۸ ساله رو تبدیل کرده بود به یه جوون ۲۴ ساله. و بعد فهمیدم که چرا ناراحتم، چرا حسادت می‌کنم و چرا عصبانیم.از ته دل دوست‌داشتم تا یک‌سال آینده رو که قراره پیش‌خونواده بگذرونم در همون خونه‌ای باشم که هم‌بازی نوجونی من به حساب میومد، اما خب نشد. خانوادم تصمیم به تعویض خونه داشتن و من هم پافشاری نکردم. اما این اولین‌بار بود که با یک خونه، در این حد پیوند احساسی برقرار کرده‌بودم و تمام این حس برام آشکار نبود تا لحظه‌ای که در حال ترکش بودم!به نظرم ما آدما تکامل پیدا نکردیم که در یک جا ساکن باشیم. انگار سکونت و وابستگی به مکان با ذات ما سازگار نیست. شاید به همین خاطره که دل کندن از خونه‌ها می‌تونه انقدر برامون سخت باشه و اسباب‌کشی می‌تونه دل‌آشوبی از حسی شیرین و تلخ باشه.قسمت خوب این تجربه، رشد نگاه من به خونه‌ها بود! و درک اهمیتشون در زندگیامون. چون بیشتر که فکر کردم متوجه شدم چقدر خونه‌ها و ساختمونای مختلفی وجود داره که من وقتی بهشون فکر می‌کنم، موجی از احساسات و خاطره‌ها بهم سرازیر میشه. نهایتا هر خاطره‌ای جایی برای ساخته‌شدن می‌خواد. هر خونه‌ای پناهگاه کلی آدم و خاطره‌هاشونه، گاو‌صندوقی که ما توش زندگی می‌کنیم و ذره‌ذره لحظه‌هامون رو درش به امانت می‌ذاریم و گاهی اونو می‌سپاریم به آدمای جدید تا اونا هم جایی داشته باشن برای ساختن خاطرات جدیدشون :)لینک نوشته در وبلاگ شخصی من: mahdavipanah.com/blog/homes-and-emotions</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Tue, 13 Aug 2019 15:33:24 +0430</pubDate>
            </item>
                    <item>
                <title>چرا خواندن کتاب «انسان خردمند» را توصیه می‌کنم؟</title>
                <link>https://virgool.io/ketabaz/%D8%A7%D9%86%D8%B3%D8%A7%D9%86-%D8%AE%D8%B1%D8%AF%D9%85%D9%86%D8%AF-hjlgcpnnrxuu</link>
                <description>بعد از خواندن نوشته‌ای با عنوان «چرا کتاب انسان خردمند را نمی‌خوانم؟» که MAHSA MOJDEHY در صفحه‌ی ویرگولشان منتشر کرده بودند، تصمیم گرفتم جوابیه‌ای کوتاه بنویسم که هم پاسخی به نوشته‌ی ایشان باشد و هم توصیه‌ای به خواندن این کتاب از نگاه بنده. پس توصیه می‌کنم ابتدا نوشته‌ی ایشان و سپس ادامه‌ی این متن را بخوانید.ترجمه‌ی فارسی کتاب «انسان خردمند» از انتشارات «فرهنگ‌نشر‌نو» (منبع تصویر: kafebook.ir)نوشته‌ی شما از جهت صادقانه بودن قابل ستایش است اما ایراداتی جدی به بررسی شما درمورد این کتاب وارد است.اولین نکته‌ای که خود همیشه سعی در رعایتش دارم این است که بدون خواندن هیچ کتابی، درموردش نظر نمی‌دهم و اولین ایراد بنده به نوشته‌ی شما عنوان آن است. کتاب‌ها باید خوانده شوند، درک شوند و سپس نقد شوند. البته که می‌توان در نقد یک کتاب به مخاطب توصیه کرد تا انرژی و وقت خود را صرف مطالعه‌ی آن نکند ولی این توصیه از زبان کسی که خود نیز کتاب را نخوانده، زیاده‌روی در پیش‌داوری است. البته که این امر یک انتخاب شخصی است و البته که انسان می‌تواند بدون شناخت یک موضوع، نظر شخصی خود را درموردش بیان کند و حتی گاهی این نظرات صحیح نیز هستند، اما قضاوت‌های اینگونه معمولا با خطای زیادی همراه‌اند.«کلی گویی همیشه ضد جذابیت است»:هرکتابی که روی جلد آن «تاریخ بشر» حک شده باشد، حتی اگر کتابی ۱۰۰ جلدی باشد، این ایراد شما بر آن وارد است. نویسنده به هیچ عنوان تلاشی در جهت دادن شناختی عمیق از ده‌ها هزارسال تاریخ بشر به خواننده نمی‌کند بلکه تلاش می‌کند که بینش و روایتی که خود از مطالعاتش به دست‌آورده‌است را با نثری روان، درست و البته علمی (تاکیید میکنم، «علمی») به خواننده‌ی علاقه‌مند منتقل کند و در اصل به جای این که شما به این کتاب به عنوان مرجعی برای شناخت عمیق نگاه کنید باید به آن به مثابه‌ی یک نقشه‌ی راه بنگرید.«وقتی با یک کتاب عکس های زیادی گرفته می شود، یک جای کار می لنگد»:حرفتان را تا حدودی قبول دارم اما به نظرم جمله‌تان باید کمی تغییر کند: «وقتی با یک کتاب عکس های زیادی گرفته می شود، باید شک کرد که شاید یک جای کار می لنگد.» این که کتابی پرفروش و پرخواننده می‌شود می‌تواند معلول عوامل گوناگونی مثل معرفی شدن آن توسط چهره‌ی سرشناس در بین مردم، بازاریابی قوی ناشر، زمان مناسب انتشار و ... باشد. پس آیا هر کتابی که بر سر زبان‌ها می‌افتد به این معناست که از محتوا خالی است و کتابی است بازاری؟ به عقیده‌ی بنده قطعا خیر. همچنان که در بسیاری از کشور‌های دیگر دنیا بر خلاف کشور ما که معمولا کتاب‌هایی که سرشان به تنشان میارزد تیراژشان از چندهزارتا (تازه اگر خوش‌شانس باشند و اجازه‌ی چاپ پیدا کنند) بالاتر نمی‌رود، می‌توانند کتاب‌هایی پرفروش شوند و مخاطبان زیادی در بین مردم پیدا کنند.«... و یک طرف دیگر مخالفانی هستند که می گویند کتاب زیاده از حد عقلانی است.»:کاملا درست است! کتاب یک کتاب علمی است که در انتهای آن ۲۲ صفحه به ذکر منابع اختصاص دارد! پس اساسا خواننده‌ای که عقلانی بودن یک کتاب، آن هم با موضوع «تاریخ بشر» را، از نقاط ضعف آن می‌داند، به طور واضح موضوع علم برایش هنوز حلاجی نشده باقی‌مانده و اتفاقا شاید خواندن «انسان خردمند» بهترین نقطه‌ی شروع فهم او از رابطه‌ی انسان و علم در تاریخ باشد. به عقیده‌ی بنده کتاب «انسان خردمند» کتابی است کاملا علمی و برپایه‌ی منابع قابل اتکا که بزرگترین برتری خود را در روایتی حقیقی و در عین حال جذاب پیدا کرده است.هنر نویسنده نه در کشف حقایق تاریخ بشر (که خود نیز چنین ادعایی ندارد و منابع فراوانی که نویسنده به آن‌ها ارجاع دارد هم شاهدی بر همین مدعاست) که در پیدا کردن یک خط داستانی و روایت تاریخی بی‌نظیر در دل این حقایق است و می‌توان گفت با این که مخاطب کتاب مخاطبی غیرتخصصی است، اما به هیچ عنوان از ارزش علمی کتاب چیزی کم نمی‌کند و کتاب حتی برای یک خواننده‌ی پرمطالعه در حوزه‌ی مورد نظر نیز می‌تواند  بسیار خواندنی، پرمحتوا و آموزنده باشد.لینک نوشته در وبلاگ شخصی من: mahdavipanah.com/blog/homosapien-book</description>
                <category>حمیدرضا مهدوی‌پناه</category>
                <author>حمیدرضا مهدوی‌پناه</author>
                <pubDate>Wed, 24 Jul 2019 14:41:20 +0430</pubDate>
            </item>
            </channel>
</rss>