<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های میر مجتبی هاشمی جنتی</title>
        <link>https://virgool.io/feed/@s.mojtaba-hashemi</link>
        <description>دانش آموخته مهندسی نرم افزار | فعال در صنعت | یک برنامه نویس ساده</description>
        <language>fa</language>
        <pubDate>2026-07-06 05:01:16</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/941132/avatar/sg5Pav.jpg?height=120&amp;width=120</url>
            <title>میر مجتبی هاشمی جنتی</title>
            <link>https://virgool.io/@s.mojtaba-hashemi</link>
        </image>

                    <item>
                <title>سمت های سازمانی در شرکت ها (بخش 1)</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%B3%D9%85%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86%DB%8C-%D8%AF%D8%B1-%D8%B4%D8%B1%DA%A9%D8%AA-%D9%87%D8%A7-%D8%A8%D8%AE%D8%B4-1-cgbnl8ff2ksw</link>
                <description>سلام. امروز در مورد سمت رئیس هیئت مدیره و مدیر عامل کمی صحبت خواهیم کرد. بیشتر نظرم روی شرکت های نرم افزاری هست ولی در کل سازوکار ها یکی هستند چون در مورد وظایف ها و ... بیشتر صحبت خواهیم کرد.رئیس هیئت‌مدیره شرکت؛جایگاهی که بیشتر از آنچه فکر می‌کنید در موفقیت یا شکست یک کسب‌وکار نقش دارداگر امروز از ده مدیر یک شرکت تازه‌تأسیس بپرسید «رئیس هیئت‌مدیره دقیقاً چه کاری انجام می‌دهد؟»، احتمالاً پاسخ‌هایی می‌شنوید که تفاوت چندانی با شرح وظایف مدیرعامل ندارند. بعضی‌ها می‌گویند رئیس هیئت‌مدیره همان کسی است که همه تصمیم‌های شرکت را می‌گیرد. بعضی دیگر تصور می‌کنند این جایگاه صرفاً یک عنوان تشریفاتی است که برای تکمیل مدارک ثبت شرکت انتخاب می‌شود. گروهی هم معتقدند هرکس سهام بیشتری داشته باشد، طبیعی است که رئیس هیئت‌مدیره باشد و بنابراین همه امور شرکت نیز باید زیر نظر او انجام شود.واقعیت اما چیز دیگری است.در بسیاری از شرکت‌های موفق دنیا، رئیس هیئت‌مدیره نه مدیر اجرایی شرکت است و نه کسی که هر روز درگیر فروش، بازاریابی، منابع انسانی یا تولید باشد. او کسی است که مسیر را مشخص می‌کند، از سلامت تصمیم‌های کلان اطمینان حاصل می‌کند و مراقب است که شرکت در میان هیاهوی فعالیت‌های روزمره، هدف اصلی خود را گم نکند.اتفاقاً همین تفاوت است که باعث می‌شود بسیاری از شرکت‌های تازه‌تأسیس، حتی با وجود داشتن محصول خوب، تیم متخصص و سرمایه اولیه مناسب، بعد از چند سال دچار اختلافات داخلی، تصمیم‌های متناقض یا حتی انحلال شوند. مشکل اغلب از بازار شروع نمی‌شود؛ از داخل اتاق هیئت‌مدیره آغاز می‌شود.در روزهای ابتدایی تأسیس یک شرکت، همه چیز ساده به نظر می‌رسد. دو یا سه شریک کنار هم می‌نشینند، شرکت را ثبت می‌کنند، سهام را تقسیم می‌کنند و برای اینکه مدارک کامل باشد، یکی مدیرعامل می‌شود و دیگری رئیس هیئت‌مدیره. در آن مقطع معمولاً هیچ‌کس به تفاوت این دو جایگاه فکر نمی‌کند. همه در همه کارها دخالت می‌کنند، تصمیم‌ها در یک گروه واتساپی گرفته می‌شود و صورتجلسه‌ها فقط زمانی تنظیم می‌شوند که اداره ثبت یا بانک آن را مطالبه کند.این مدل شاید برای چند ماه اول جواب بدهد، اما شرکتی که قرار است رشد کند، مشتریان بیشتری جذب کند، نیرو استخدام کند، سرمایه‌گذار داشته باشد یا قراردادهای بزرگ منعقد کند، دیگر نمی‌تواند با همین شیوه اداره شود.هرچه شرکت بزرگ‌تر می‌شود، مرز میان «تصمیم‌گیری» و «اجرا» اهمیت بیشتری پیدا می‌کند. اگر این مرز مشخص نباشد، مدیرعامل نمی‌داند تا کجا اختیار دارد، اعضای هیئت‌مدیره دائماً در امور اجرایی دخالت می‌کنند و کارکنان نیز نمی‌دانند باید از چه کسی دستور بگیرند. نتیجه چنین وضعیتی، چیزی جز سردرگمی نیست.جلسات هیئت مدیرهرئیس هیئت‌مدیره؛ معمار شرکت، نه مجری آنیکی از بهترین تشبیه‌ها برای درک جایگاه رئیس هیئت‌مدیره این است که شرکت را به ساخت یک ساختمان بزرگ تشبیه کنیم.فرض کنید قرار است یک مجتمع اداری ساخته شود. معمار پروژه، نقشه کلی را طراحی می‌کند، مشخص می‌کند ساختمان چند طبقه باشد، سازه چه ویژگی‌هایی داشته باشد و مسیر کلی پروژه چگونه پیش برود. اما او خودش آجر روی آجر نمی‌گذارد. اجرای پروژه بر عهده پیمانکار، مهندسان اجرا و نیروهای عملیاتی است.در یک شرکت نیز رئیس هیئت‌مدیره تا حد زیادی چنین نقشی دارد. او باید تصویر بزرگ را ببیند. باید بداند شرکت قرار است سه سال یا پنج سال آینده در چه جایگاهی باشد، چه ریسک‌هایی در کمین آن است، آیا ساختار تصمیم‌گیری درست طراحی شده است یا نه و آیا مدیرعامل مسیر تعیین‌شده را به‌درستی دنبال می‌کند.در مقابل، مدیرعامل کسی است که هر روز با مسائل اجرایی روبه‌روست. او باید فروش را افزایش دهد، هزینه‌ها را کنترل کند، نیروهای انسانی را مدیریت کند، قراردادها را پیش ببرد و پاسخگوی عملکرد روزانه شرکت باشد.به همین دلیل است که در بسیاری از شرکت‌های حرفه‌ای، رئیس هیئت‌مدیره حتی ممکن است هر روز در دفتر شرکت حضور نداشته باشد، اما همچنان تأثیرگذارترین فرد در تصمیم‌های کلان باشد.بزرگ‌ترین اشتباه شرکت‌های تازه‌تأسیسیکی از اشتباهاتی که بارها در شرکت‌های نوپا دیده می‌شود، این است که رئیس هیئت‌مدیره به‌تدریج نقش مدیرعامل را نیز بر عهده می‌گیرد.ابتدا برای کمک وارد جزئیات می‌شود. در جلسه فروش حضور پیدا می‌کند. درباره استخدام نیرو نظر می‌دهد. در مذاکره با مشتریان شرکت می‌کند. بعد تصمیم می‌گیرد پرداخت‌های مالی نیز با تأیید او انجام شود. چند ماه بعد، مدیرعامل عملاً تبدیل به فردی می‌شود که فقط گزارش می‌دهد و اختیار چندانی برای تصمیم‌گیری ندارد.شاید در نگاه اول این مدل باعث شود همه چیز تحت کنترل باشد، اما در عمل نتیجه کاملاً برعکس است. سرعت تصمیم‌گیری کاهش پیدا می‌کند، مسئولیت‌ها مبهم می‌شوند و اگر مشکلی پیش بیاید، هیچ‌کس دقیقاً نمی‌داند پاسخگو چه کسی است.از سوی دیگر، اگر رئیس هیئت‌مدیره درگیر جزئیات روزمره شود، دیگر فرصتی برای انجام مهم‌ترین وظیفه خود یعنی نگاه بلندمدت به آینده شرکت نخواهد داشت. او به جای آنکه درباره توسعه بازار، جذب سرمایه، مدیریت ریسک یا اصلاح ساختار تصمیم بگیرد، وقت خود را صرف تأیید فاکتورها، بررسی درخواست مرخصی کارکنان یا انتخاب رنگ بروشور تبلیغاتی خواهد کرد.این دقیقاً همان نقطه‌ای است که بسیاری از شرکت‌ها، بدون آنکه متوجه باشند، از مسیر حرفه‌ای مدیریت فاصله می‌گیرند.آیا رئیس هیئت‌مدیره رئیس مدیرعامل است؟این سؤال یکی از رایج‌ترین پرسش‌هایی است که پس از ثبت شرکت مطرح می‌شود.پاسخ کوتاه این است: «هم بله و هم خیر.»اگر منظور از رئیس بودن، مدیریت روزانه و صدور دستور برای امور اجرایی باشد، پاسخ منفی است. مدیرعامل مسئول اداره عملیات شرکت است و اختیار اجرای تصمیم‌هایی را دارد که در چارچوب اختیارات قانونی و مصوبات هیئت‌مدیره به او واگذار شده است. رئیس هیئت‌مدیره نباید هر روز در کار او دخالت کند یا نقش مدیر مستقیم او را بازی کند.اما اگر منظور از رئیس بودن، هدایت هیئت‌مدیره، نظارت بر اجرای سیاست‌های کلان و اطمینان از حرکت شرکت در مسیر صحیح باشد، پاسخ مثبت است. رئیس هیئت‌مدیره مسئول اداره جلسات هیئت‌مدیره، ایجاد هماهنگی میان اعضا و پیگیری اجرای تصمیم‌های کلان است؛ نه مدیریت جزئیات اجرایی.به بیان ساده‌تر، مدیرعامل مسئول «انجام دادن کارها» است و رئیس هیئت‌مدیره مسئول «اطمینان از درست بودن کارهایی است که شرکت تصمیم گرفته انجام دهد». این دو نقش نه رقیب یکدیگر هستند و نه جایگزین هم؛ بلکه دو ضلع مکمل در ساختار راهبری یک شرکت موفق به شمار می‌آیند.شرکتی که این تفاوت را درک کند، معمولاً ساختار منسجم‌تری خواهد داشت، تصمیم‌های شفاف‌تری می‌گیرد و در زمان رشد، کمتر دچار تعارض‌های داخلی می‌شود. اما شرکتی که این مرز را نادیده بگیرد، دیر یا زود با اختلاف میان شرکا، فرسودگی مدیرعامل و کاهش سرعت تصمیم‌گیری روبه‌رو خواهد شد؛ مشکلی که در ظاهر مدیریتی است، اما ریشه آن در نادیده گرفتن جایگاه واقعی رئیس هیئت‌مدیره قرار دارد.رئیس هیئت‌مدیره چه کاری انجام می‌دهد که مدیرعامل انجام نمی‌دهد؟تا اینجا درباره تفاوت جایگاه رئیس هیئت‌مدیره و مدیرعامل صحبت کردیم، اما احتمالاً هنوز یک سؤال در ذهن بسیاری از خوانندگان وجود دارد؛ اگر مدیرعامل شرکت را اداره می‌کند، پس رئیس هیئت‌مدیره دقیقاً چه کاری انجام می‌دهد؟این سؤال کاملاً طبیعی است، چون بخش زیادی از فعالیت‌های رئیس هیئت‌مدیره، برخلاف مدیرعامل، در ظاهر دیده نمی‌شود. اگر یک روز وارد شرکت شوید، احتمالاً مدیرعامل را در حال مذاکره با مشتری، جلسه با مدیران واحدها، بررسی گزارش‌های مالی یا تصمیم‌گیری درباره یک پروژه خواهید دید. اما ممکن است همان روز رئیس هیئت‌مدیره اصلاً در شرکت حضور نداشته باشد. آیا این به معنای کم‌اهمیت بودن نقش اوست؟ قطعاً نه.اتفاقاً یکی از ویژگی‌های مدیریت حرفه‌ای این است که افراد را بر اساس میزان حضور فیزیکی یا تعداد جلساتی که برگزار می‌کنند قضاوت نکنیم. ارزش واقعی یک رئیس هیئت‌مدیره در کیفیت تصمیم‌هایی است که مسیر شرکت را برای سال‌های آینده تعیین می‌کنند، نه در تعداد ایمیل‌هایی که پاسخ می‌دهد یا تماس‌هایی که برقرار می‌کند.برای درک بهتر این موضوع، بهتر است به یک مثال ساده فکر کنیم.فرض کنید یک کشتی بزرگ در حال حرکت است. کاپیتان کشتی وظیفه دارد مسیر روزانه را کنترل کند، وضعیت آب‌وهوا را بررسی کند، سرعت را تنظیم کند و خدمه را مدیریت کند. اما کسی که نقشه سفر را طراحی کرده، مقصد را انتخاب کرده و مشخص کرده کشتی از کدام مسیر حرکت کند، نقش دیگری دارد. اگر مقصد اشتباه انتخاب شده باشد، حتی بهترین کاپیتان دنیا هم کشتی را به جای درستی نخواهد رساند.در یک شرکت نیز مدیرعامل همان کسی است که کشتی را هدایت می‌کند، اما رئیس هیئت‌مدیره باید مطمئن شود که اصلاً کشتی به سمت مقصد درستی حرکت می‌کند.رئیس هیئت‌مدیره، نگهبان آینده شرکت استیکی از تفاوت‌های مهم میان مدیرعامل و رئیس هیئت‌مدیره در افق زمانی تصمیم‌های آن‌هاست.مدیرعامل معمولاً درگیر مسائل امروز و فرداست. او باید حقوق کارکنان را پرداخت کند، قراردادها را پیش ببرد، فروش این ماه را افزایش دهد، مشکلات مشتریان را حل کند و مطمئن شود عملیات شرکت بدون وقفه ادامه پیدا می‌کند. این وظایف کاملاً ضروری هستند و بدون آن‌ها هیچ شرکتی دوام نمی‌آورد.اما اگر تمام مدیران یک شرکت فقط به امروز فکر کنند، چه کسی مسئول آینده خواهد بود؟چه کسی باید از خودش بپرسد که آیا مدل درآمدی فعلی پنج سال دیگر هم جواب می‌دهد؟چه کسی باید بررسی کند که ورود یک رقیب جدید چه تأثیری بر بازار خواهد گذاشت؟چه کسی باید از همین امروز درباره جذب سرمایه، توسعه بازار، جانشین‌پروری مدیران یا تغییر فناوری فکر کند؟این دقیقاً همان جایی است که نقش رئیس هیئت‌مدیره آغاز می‌شود.او باید بتواند چند قدم جلوتر از اتفاقات روزمره حرکت کند. شاید امروز همه چیز خوب پیش برود، اما رئیس هیئت‌مدیره باید از خودش بپرسد اگر فروش شرکت ناگهان پنجاه درصد کاهش پیدا کند چه اتفاقی می‌افتد؟ اگر یکی از بنیان‌گذاران تصمیم به خروج بگیرد چه خواهد شد؟ اگر قوانین بازار تغییر کند، آیا شرکت آمادگی تطبیق با شرایط جدید را دارد؟این نوع نگاه، تفاوت میان مدیریت روزمره و راهبری سازمان است.رئیس هیئت‌مدیره نباید جای مدیرعامل تصمیم بگیردیکی از حساس‌ترین مرزهای مدیریتی، جایی است که رئیس هیئت‌مدیره احساس می‌کند برای کمک به شرکت باید وارد تصمیم‌های اجرایی شود.در ظاهر، این رفتار از روی دلسوزی است. او تجربه بیشتری دارد، سرمایه بیشتری وارد شرکت کرده یا سال‌ها در بازار فعالیت داشته است. بنابراین تصور می‌کند بهتر است خودش درباره استخدام نیرو، قیمت‌گذاری محصولات یا حتی نحوه مذاکره با مشتریان تصمیم بگیرد.اما همین نقطه، آغاز یکی از بزرگ‌ترین آسیب‌های مدیریتی است.مدیرعاملی که برای کوچک‌ترین تصمیم نیاز به تأیید رئیس هیئت‌مدیره داشته باشد، به‌تدریج قدرت تصمیم‌گیری خود را از دست می‌دهد. کارکنان نیز متوجه این موضوع می‌شوند و به جای مراجعه به مدیرعامل، مستقیماً سراغ رئیس هیئت‌مدیره می‌روند. کم‌کم ساختار سازمانی از بین می‌رود و شرکت وارد چرخه‌ای از تصمیم‌های متناقض می‌شود.بدتر از آن، اگر نتیجه یک تصمیم نامطلوب باشد، هیچ‌کس مسئولیت آن را نمی‌پذیرد. مدیرعامل می‌گوید تصمیم را رئیس هیئت‌مدیره گرفته است و رئیس هیئت‌مدیره نیز معتقد است اجرا بر عهده مدیرعامل بوده است.در شرکت‌های حرفه‌ای، چنین وضعیتی به‌ندرت دیده می‌شود، زیرا مرز اختیارات از همان ابتدا مشخص است.رئیس هیئت‌مدیره می‌تواند سؤال بپرسد، گزارش بخواهد، تحلیل کند، هشدار بدهد و در جلسات هیئت‌مدیره درباره تصمیم‌های کلان نظر بدهد؛ اما نباید هر روز وارد جزئیات اجرایی شود، مگر در شرایطی که قانون، اساسنامه یا مصوبات هیئت‌مدیره چنین اختیاری را به او داده باشد.هیئت‌مدیره محل تصمیم‌سازی است، نه محل تأیید تصمیم‌های از قبل گرفته شدهیکی از مشکلاتی که در بسیاری از شرکت‌های ایرانی دیده می‌شود این است که جلسه هیئت‌مدیره صرفاً به یک تشریفات قانونی تبدیل شده است.مدیرعامل تصمیم‌هایش را گرفته، قراردادها امضا شده‌اند، هزینه‌ها انجام شده‌اند و در نهایت جلسه‌ای تشکیل می‌شود تا همه اعضا صورتجلسه را امضا کنند.اگر هیئت‌مدیره فقط برای امضا کردن تشکیل شود، عملاً یکی از مهم‌ترین ابزارهای مدیریتی شرکت از بین رفته است.جلسه هیئت‌مدیره باید جایی باشد که ایده‌ها به چالش کشیده شوند. اعضا باید بتوانند بدون نگرانی نظر مخالف خود را بیان کنند. رئیس هیئت‌مدیره باید فضای جلسه را به‌گونه‌ای مدیریت کند که اختلاف نظر به تعارض شخصی تبدیل نشود.اتفاقاً ارزش یک جلسه خوب، زمانی مشخص می‌شود که همه اعضا در نهایت به تصمیمی برسند که شاید در ابتدای جلسه هیچ‌کس به آن فکر نکرده بود.یکی از وظایف مهم رئیس هیئت‌مدیره همین مدیریت گفت‌وگوهاست. او نباید اجازه دهد جلسه به میدان رقابت میان شرکا تبدیل شود یا افراد فقط برای دفاع از دیدگاه خود صحبت کنند. هدف جلسه، پیدا کردن بهترین تصمیم برای شرکت است، نه اثبات برتری یک نفر.رئیس هیئت‌مدیره باید از مدیرعامل سؤال بپرسد، نه اینکه پاسخ همه سؤال‌ها را خودش بدهدگاهی مدیران تصور می‌کنند یک رئیس هیئت‌مدیره خوب کسی است که برای همه مشکلات راه‌حل آماده داشته باشد.در حالی که تجربه شرکت‌های موفق نشان می‌دهد ویژگی اصلی رؤسای هیئت‌مدیره موفق، کیفیت سؤال‌های آن‌هاست، نه تعداد پاسخ‌هایشان.وقتی مدیرعامل گزارش افزایش فروش ارائه می‌دهد، رئیس هیئت‌مدیره نباید فقط از شنیدن عددهای بزرگ خوشحال شود. او باید بپرسد این رشد از کجا آمده است؟ آیا سودآوری هم افزایش یافته یا فقط درآمد بیشتر شده است؟ آیا این رشد پایدار است یا نتیجه یک قرارداد موقت؟اگر هزینه‌های شرکت کاهش پیدا کرده، سؤال بعدی این است که آیا این کاهش هزینه به کیفیت محصول آسیب نزده است؟اگر شرکت وارد بازار جدیدی شده، باید پرسید آیا منابع انسانی و زیرساخت لازم برای این توسعه وجود دارد؟این پرسش‌ها شاید در ظاهر ساده باشند، اما دقیقاً همین سؤال‌ها هستند که از تبدیل شدن تصمیم‌های هیجانی به بحران‌های بزرگ جلوگیری می‌کنند.رئیس هیئت‌مدیره، میانجی اختلاف‌هاست؛ نه یکی از طرف‌های اختلافهر شرکتی که چند شریک داشته باشد، دیر یا زود با اختلاف نظر روبه‌رو می‌شود. این اختلاف‌ها نه نشانه ضعف شرکت هستند و نه الزاماً خطرناک. اتفاقاً وجود دیدگاه‌های متفاوت می‌تواند کیفیت تصمیم‌ها را افزایش دهد.مشکل از جایی آغاز می‌شود که اختلاف نظر به اختلاف شخصی تبدیل شود.در چنین شرایطی، رئیس هیئت‌مدیره نباید نقش یکی از طرفین دعوا را بازی کند. او باید تلاش کند بحث دوباره به منافع شرکت برگردد.گاهی دو شریک ساعت‌ها درباره اینکه چه کسی ایده اولیه محصول را مطرح کرده بحث می‌کنند، در حالی که سؤال واقعی این است که امروز چه تصمیمی بیشترین منفعت را برای شرکت ایجاد می‌کند.اگر رئیس هیئت‌مدیره نتواند این تغییر زاویه دید را ایجاد کند، اختلاف‌ها به‌تدریج به فرهنگ سازمان منتقل می‌شوند و کارکنان نیز وارد جناح‌بندی‌های داخلی خواهند شد؛ اتفاقی که در بسیاری از شرکت‌های نوپا، حتی پیش از شکست مالی، باعث شکست مدیریتی می‌شود.به همین دلیل، شاید بتوان گفت مهم‌ترین سرمایه یک رئیس هیئت‌مدیره نه دانش حقوقی اوست، نه میزان سهامش و نه حتی سابقه مدیریتی‌اش؛ بلکه توانایی او در حفظ تعادل میان منافع افراد و منافع شرکت است. رئیس هیئت‌مدیره موفق همیشه به اعضای هیئت‌مدیره یادآوری می‌کند که آن‌ها برای دفاع از نظر شخصی خود دور یک میز ننشسته‌اند؛ بلکه برای ساختن آینده یک کسب‌وکار کنار هم قرار گرفته‌اند.وقتی قانون وارد اتاق هیئت‌مدیره می‌شود؛ مسئولیت‌هایی که بسیاری از رؤسای هیئت‌مدیره از آن بی‌خبرندیکی از بزرگ‌ترین اشتباهاتی که در شرکت‌های تازه‌تأسیس رخ می‌دهد، این است که مؤسسان تصور می‌کنند ثبت شرکت پایان کارهای حقوقی است؛ در حالی که ثبت شرکت، تازه آغاز مسئولیت‌های قانونی مدیران است.بسیاری از استارتاپ‌ها و شرکت‌های کوچک در سال‌های نخست فعالیت، بیشتر انرژی خود را صرف فروش، توسعه محصول، جذب مشتری و مدیریت هزینه‌ها می‌کنند. این موضوع کاملاً طبیعی است، اما گاهی آن‌قدر درگیر عملیات روزانه می‌شوند که فراموش می‌کنند شرکت فقط یک کسب‌وکار نیست؛ یک شخصیت حقوقی است که قوانین مشخصی بر آن حاکم است.در این میان، رئیس هیئت‌مدیره یکی از مهم‌ترین افرادی است که باید مراقب باشد فعالیت‌های شرکت در چارچوب قانون انجام شود. البته این به معنای آن نیست که او باید نقش وکیل یا مشاور حقوقی را ایفا کند، اما انتظار می‌رود از اصول کلی راهبری شرکت آگاه باشد و اجازه ندهد تصمیم‌های هیجانی، آینده شرکت را با خطرهای حقوقی مواجه کنند.نکته مهم اینجاست که بسیاری از مشکلات حقوقی شرکت‌ها نه به دلیل سوءنیت، بلکه به دلیل بی‌اطلاعی مدیران ایجاد می‌شوند. صورتجلسه‌ای که تنظیم نشده، مجمعی که در موعد مقرر برگزار نشده، اختیاراتی که بدون مصوبه به یک نفر داده شده یا قراردادی که خارج از حدود اختیارات امضا شده است، همگی می‌توانند بعدها منشأ اختلاف‌های بزرگ شوند.آیا رئیس هیئت‌مدیره بالاترین مقام شرکت است؟این سؤال تقریباً در تمام شرکت‌های تازه‌تأسیس مطرح می‌شود.پاسخ به این سؤال کمی پیچیده‌تر از یک «بله» یا «خیر» ساده است.اگر منظور از «بالاترین مقام» کسی باشد که شرکت را اداره می‌کند، پاسخ منفی است. اداره امور اجرایی شرکت بر عهده مدیرعامل است و او مسئول اجرای برنامه‌ها، مدیریت منابع، هدایت کارکنان و پیشبرد فعالیت‌های روزانه است.اما اگر منظور، جایگاهی باشد که بر تصمیم‌های کلان شرکت نظارت دارد و جلسات هیئت‌مدیره را مدیریت می‌کند، رئیس هیئت‌مدیره نقش بسیار مهمی ایفا می‌کند. با این حال، حتی او نیز به‌تنهایی تصمیم‌گیر نهایی نیست.این نکته‌ای است که بسیاری از مدیران جوان در ابتدای مسیر متوجه آن نمی‌شوند.رئیس هیئت‌مدیره «خودِ هیئت‌مدیره» نیست.او فقط رئیس جلسات هیئت‌مدیره است.به عبارت دیگر، قدرت واقعی در بسیاری از موضوعات، متعلق به مجموعه هیئت‌مدیره است، نه یک فرد. اگر اعضای هیئت‌مدیره تصمیمی را تصویب نکنند، رئیس هیئت‌مدیره نمی‌تواند صرفاً به دلیل عنوان خود آن را به شرکت تحمیل کند.همین موضوع یکی از تفاوت‌های مهم میان شرکت و یک کسب‌وکار شخصی است.در یک مغازه یا کسب‌وکار خانوادگی، مالک می‌تواند تقریباً درباره همه چیز شخصاً تصمیم بگیرد. اما شرکت، به‌ویژه زمانی که چند سهامدار و چند عضو هیئت‌مدیره دارد، بر پایه تصمیم‌های جمعی اداره می‌شود. این ساختار شاید گاهی سرعت تصمیم‌گیری را کاهش دهد، اما در مقابل، احتمال تصمیم‌های شتاب‌زده و پرریسک را نیز کمتر می‌کند.داشتن سهام بیشتر، الزاماً به معنای مدیریت بهتر نیستدر بسیاری از شرکت‌های ایرانی، فردی که بیشترین سرمایه را وارد شرکت کرده است، به‌صورت طبیعی رئیس هیئت‌مدیره نیز می‌شود. این اتفاق از نظر عملی رایج است، اما نباید باعث شود تصور کنیم مالکیت بیشتر، به‌طور خودکار به معنای توانایی بیشتر در مدیریت شرکت است.سرمایه‌گذاری و راهبری سازمان، دو مهارت کاملاً متفاوت هستند.ممکن است فردی سرمایه‌گذار بسیار موفقی باشد، اما در مدیریت جلسات، ایجاد اجماع میان اعضا یا تعیین استراتژی‌های بلندمدت تجربه چندانی نداشته باشد.از طرف دیگر، ممکن است شخصی سهم کمتری از شرکت داشته باشد، اما به دلیل تجربه مدیریتی بالا، بهترین گزینه برای ریاست هیئت‌مدیره باشد.در شرکت‌های بزرگ جهان نیز بارها دیده‌ایم که رئیس هیئت‌مدیره الزاماً بزرگ‌ترین سهامدار شرکت نیست. دلیل آن روشن است؛ این جایگاه بیش از آنکه به میزان سرمایه وابسته باشد، به توانایی راهبری، تصمیم‌سازی و مدیریت تعارض‌ها وابسته است.آیا رئیس هیئت‌مدیره می‌تواند هم‌زمان مدیرعامل هم باشد؟این یکی از بحث‌برانگیزترین موضوعات در ساختار شرکت‌هاست.از نظر حقوقی، در برخی انواع شرکت‌ها و تحت شرایط مشخص، ممکن است یک نفر هر دو سمت را بر عهده بگیرد؛ البته این موضوع تابع مقررات و اساسنامه شرکت است و در همه شرایط یکسان نیست.اما حتی اگر قانون چنین امکانی را فراهم کرده باشد، از نگاه مدیریتی همیشه بهترین انتخاب نیست.دلیل آن ساده است.فرض کنید یک نفر هم مسئول تصمیم‌گیری کلان باشد، هم مسئول اجرای همان تصمیم‌ها و هم مسئول نظارت بر کیفیت اجرای آن‌ها.در این حالت، چه کسی عملکرد او را ارزیابی خواهد کرد؟چه کسی از او گزارش خواهد خواست؟چه کسی می‌تواند تصمیم‌هایش را به چالش بکشد؟یکی از اصول مهم راهبری شرکتی این است که میان «تصمیم‌گیری»، «اجرا» و «نظارت» تا حد امکان تعادل برقرار باشد. هرچه این نقش‌ها بیشتر در یک فرد متمرکز شوند، احتمال خطا، تعارض منافع و تصمیم‌های یک‌جانبه نیز افزایش پیدا می‌کند.به همین دلیل است که بسیاری از شرکت‌های بالغ ترجیح می‌دهند رئیس هیئت‌مدیره و مدیرعامل دو نفر متفاوت باشند؛ نه به این دلیل که به یکدیگر اعتماد ندارند، بلکه برای اینکه ساختار تصمیم‌گیری سالم‌تر و شفاف‌تر باقی بماند.رئیس هیئت‌مدیره باید مراقب «فرهنگ تصمیم‌گیری» شرکت باشدوقتی از فرهنگ سازمانی صحبت می‌کنیم، اغلب ذهنمان به سمت رفتار کارکنان، نحوه ارتباط مدیران یا ارزش‌های سازمان می‌رود. اما یکی از مهم‌ترین بخش‌های فرهنگ هر شرکت، شیوه تصمیم‌گیری آن است.آیا تصمیم‌ها بر اساس داده گرفته می‌شوند یا بر اساس حدس و گمان؟آیا مخالفت کردن در جلسات هیئت‌مدیره پذیرفته شده است یا هرکس با نظر رئیس مخالفت کند، کنار گذاشته می‌شود؟آیا اعضای هیئت‌مدیره قبل از رأی دادن اطلاعات کافی دریافت می‌کنند یا فقط صورتجلسه‌ای آماده برای امضا مقابل آن‌ها قرار می‌گیرد؟پاسخ این سؤال‌ها، آینده شرکت را شکل می‌دهد.رئیس هیئت‌مدیره کسی است که بیش از هر فرد دیگری می‌تواند این فرهنگ را ایجاد کند.اگر او فضای گفت‌وگو را تشویق کند، اعضا نیز آزادانه نظر خواهند داد.اگر او فقط به دنبال تأیید نظر خود باشد، دیگران نیز به‌تدریج سکوت خواهند کرد.و سکوت در جلسات هیئت‌مدیره، معمولاً نشانه توافق نیست؛ نشانه از بین رفتن کیفیت تصمیم‌گیری است.تصمیم‌های امروز، مسئولیت‌های فردابسیاری از مدیران تصور می‌کنند مسئولیت آن‌ها با پایان جلسه هیئت‌مدیره تمام می‌شود.در حالی که هر تصمیمی که در آن جلسه گرفته می‌شود، ممکن است سال‌ها بعد آثار خود را نشان دهد.تصمیم برای ورود به یک بازار جدید، خرید یک شرکت، افزایش سرمایه، دریافت وام، پذیرش یک شریک جدید یا تغییر ساختار مدیریتی، همگی تصمیم‌هایی هستند که آثارشان ممکن است مدت‌ها بعد آشکار شود.رئیس هیئت‌مدیره باید همیشه این سؤال را از خود بپرسد:«اگر پنج سال بعد دوباره به این تصمیم نگاه کنیم، آیا باز هم از آن دفاع خواهیم کرد؟»این سؤال شاید ساده به نظر برسد، اما دقیقاً همان چیزی است که تفاوت میان یک مدیر روزمره و یک راهبر واقعی را مشخص می‌کند.در نهایت، شاید بتوان مهم‌ترین وظیفه رئیس هیئت‌مدیره را در یک جمله خلاصه کرد؛ او باید مراقب باشد شرکت فقط برای حل مشکلات امروز تصمیم نگیرد، بلکه تصمیم‌هایی بگیرد که آینده شرکت را نیز امن‌تر، پایدارتر و قابل پیش‌بینی‌تر کنند. بسیاری از مدیران می‌توانند یک شرکت را برای چند ماه اداره کنند، اما تنها مدیرانی که نگاه راهبردی دارند، می‌توانند سازمانی بسازند که سال‌ها بعد نیز همچنان پابرجا باشد.اشتباهاتی که یک رئیس هیئت‌مدیره می‌تواند با آن‌ها، بدون اینکه متوجه شود، آینده شرکت را نابود کنداگر از بیرون به یک شرکت شکست‌خورده نگاه کنیم، معمولاً اولین چیزی که به ذهن می‌رسد این است که محصول خوبی نداشته، سرمایه کافی جذب نکرده یا بازار مناسبی انتخاب نکرده است. این عوامل بدون شک در موفقیت یا شکست یک کسب‌وکار تأثیر دارند، اما واقعیت این است که بسیاری از شرکت‌ها بسیار زودتر از آنکه بازار آن‌ها را شکست دهد، از درون دچار فروپاشی می‌شوند.جالب است بدانید که این فروپاشی معمولاً با یک تصمیم اشتباه بزرگ آغاز نمی‌شود. کمتر پیش می‌آید که یک رئیس هیئت‌مدیره در یک روز خاص تصمیمی بگیرد که همان روز شرکت را نابود کند. آنچه خطرناک است، مجموعه‌ای از تصمیم‌های کوچک، رفتارهای نادرست و برداشت‌های اشتباه از جایگاه ریاست هیئت‌مدیره است؛ اشتباهاتی که شاید در ابتدا بی‌اهمیت به نظر برسند، اما به مرور زمان اعتماد را از بین می‌برند، ساختار سازمان را تضعیف می‌کنند و شرکت را از مسیر رشد خارج می‌کنند.یکی از مهم‌ترین ویژگی‌های یک رئیس هیئت‌مدیره موفق این نیست که هرگز اشتباه نکند؛ بلکه این است که اشتباهات رایج را بشناسد و قبل از تبدیل شدن آن‌ها به بحران، مسیر خود را اصلاح کند.اشتباه اول؛ تصور اینکه رئیس هیئت‌مدیره یعنی مدیرعامل ارشداین احتمالاً رایج‌ترین اشتباهی است که در شرکت‌های تازه‌تأسیس دیده می‌شود.بسیاری از افرادی که به عنوان رئیس هیئت‌مدیره انتخاب می‌شوند، به‌خصوص اگر از بنیان‌گذاران شرکت باشند، به مرور احساس می‌کنند باید در همه تصمیم‌ها حضور داشته باشند. آن‌ها گزارش فروش را بررسی می‌کنند، درباره استخدام نیرو نظر نهایی می‌دهند، در جلسات واحد بازاریابی شرکت می‌کنند، با مشتریان مذاکره می‌کنند و حتی گاهی مستقیماً به کارکنان دستور می‌دهند.در نگاه اول، این رفتار شاید نشانه مسئولیت‌پذیری باشد، اما در عمل نتیجه متفاوتی ایجاد می‌کند.وقتی کارکنان ببینند رئیس هیئت‌مدیره مستقیماً دستور صادر می‌کند، به تدریج مدیرعامل را دور می‌زنند. هر تصمیمی که مدیرعامل بگیرد، ممکن است با یک تماس یا پیام رئیس هیئت‌مدیره تغییر کند. کم‌کم مدیرعامل اختیار خود را از دست می‌دهد و شرکت وارد چرخه‌ای می‌شود که در آن هیچ‌کس دقیقاً نمی‌داند تصمیم نهایی را چه کسی می‌گیرد.بدتر از همه اینکه خود رئیس هیئت‌مدیره نیز فرصت پرداختن به وظایف اصلی‌اش را از دست می‌دهد. او به جای فکر کردن به آینده شرکت، تمام انرژی خود را صرف حل مسائل روزمره می‌کند؛ مسائلی که اساساً برای حل آن‌ها مدیرعامل انتخاب شده است.اشتباه دوم؛ سکوت در برابر مدیرعامل ضعیفاگر دخالت بیش از حد یک آسیب جدی باشد، بی‌تفاوتی نیز به همان اندازه خطرناک است.گاهی رئیس هیئت‌مدیره برای اینکه به مدیرعامل استقلال بدهد، از هرگونه نظارت فاصله می‌گیرد. گزارش‌ها را دقیق نمی‌خواند، سؤال‌های چالشی مطرح نمی‌کند، درباره شاخص‌های عملکرد پیگیری ندارد و تصور می‌کند هرچه مدیرعامل انجام می‌دهد، حتماً درست است.اعتماد، یکی از پایه‌های مهم همکاری میان رئیس هیئت‌مدیره و مدیرعامل است، اما اعتماد با رها کردن تفاوت دارد.یک رئیس هیئت‌مدیره حرفه‌ای نه در جزئیات اجرایی دخالت می‌کند و نه از کنار نشانه‌های هشداردهنده بی‌تفاوت عبور می‌کند.فرض کنید فروش شرکت سه ماه متوالی کاهش پیدا کرده است. اگر رئیس هیئت‌مدیره فقط گزارش را ببیند و بدون هیچ پرسشی آن را تأیید کند، عملاً نقش نظارتی خود را کنار گذاشته است. اما اگر با حفظ احترام از مدیرعامل بخواهد دلایل کاهش فروش، برنامه اصلاحی و شاخص‌های قابل اندازه‌گیری را ارائه دهد، در حال انجام همان وظیفه‌ای است که از او انتظار می‌رود.اشتباه سوم؛ تبدیل جلسات هیئت‌مدیره به مراسم امضای صورتجلسهدر بسیاری از شرکت‌ها، جلسه هیئت‌مدیره زمانی برگزار می‌شود که لازم باشد صورتجلسه‌ای برای بانک، اداره ثبت یا یکی از نهادهای قانونی تنظیم شود.اعضا دور یک میز جمع می‌شوند، متن از قبل آماده شده را امضا می‌کنند، چند دقیقه درباره مسائل روز صحبت می‌کنند و جلسه تمام می‌شود.اگر جلسات هیئت‌مدیره فقط چنین نقشی داشته باشند، شرکت یکی از ارزشمندترین ابزارهای تصمیم‌سازی خود را از دست داده است.یک جلسه مؤثر، جایی است که آینده شرکت روی میز قرار می‌گیرد.در چنین جلسه‌ای، اعضا درباره روند بازار بحث می‌کنند، ریسک‌های پیش رو را بررسی می‌کنند، گزارش‌های مالی را تحلیل می‌کنند، عملکرد مدیرعامل را ارزیابی می‌کنند و درباره فرصت‌های جدید تصمیم می‌گیرند.رئیس هیئت‌مدیره کسی است که کیفیت این جلسات را تعیین می‌کند.اگر او فقط به دنبال پایان سریع جلسه باشد، اعضا نیز مشارکت چندانی نخواهند داشت. اما اگر جلسه را به فضایی برای تفکر، تحلیل و گفت‌وگوی حرفه‌ای تبدیل کند، کیفیت تصمیم‌های شرکت به شکل محسوسی افزایش پیدا خواهد کرد.اشتباه چهارم؛ تصمیم‌گیری بر اساس احساس، نه اطلاعاتگاهی یک رئیس هیئت‌مدیره آن‌قدر به تجربه شخصی خود اعتماد دارد که دیگر نیازی به داده و تحلیل احساس نمی‌کند.او می‌گوید: «بیست سال است در این بازار هستم، می‌دانم چه باید کرد.»تجربه بدون تردید ارزشمند است، اما تجربه زمانی بیشترین ارزش را دارد که در کنار اطلاعات قرار بگیرد.بازارها تغییر می‌کنند.رفتار مشتریان تغییر می‌کند.فناوری تغییر می‌کند.حتی اگر مدیری سال‌ها تجربه داشته باشد، باز هم باید تصمیم‌های خود را با داده‌های واقعی تطبیق دهد.یکی از وظایف رئیس هیئت‌مدیره این است که از مدیرعامل بخواهد تصمیم‌های مهم را بر اساس تحلیل، گزارش‌های مالی، اطلاعات بازار و شاخص‌های عملکرد ارائه کند، نه صرفاً بر اساس حدس یا احساس.شرکتی که بر پایه داده تصمیم می‌گیرد، احتمال خطای کمتری دارد. شرکتی که فقط به شهود افراد تکیه می‌کند، ممکن است چند تصمیم درست بگیرد، اما در بلندمدت ریسک بسیار بیشتری خواهد داشت.اشتباه پنجم؛ فراموش کردن اینکه شرکت از افراد مهم‌تر استدر بسیاری از اختلاف‌هایی که میان شرکا ایجاد می‌شود، موضوع اصلی از مدت‌ها قبل فراموش شده است.اختلاف دیگر بر سر استراتژی شرکت یا نحوه توسعه بازار نیست؛ بلکه به رقابت‌های شخصی، سوءتفاهم‌ها و تلاش برای اثبات برتری تبدیل شده است.در چنین شرایطی، رئیس هیئت‌مدیره باید اولین کسی باشد که بحث را به منافع شرکت برگرداند.او باید این سؤال را مطرح کند که «کدام تصمیم برای شرکت بهتر است؟» نه اینکه «کدام تصمیم نشان می‌دهد حق با چه کسی بوده است.»گاهی اعضای هیئت‌مدیره ساعت‌ها درباره موضوعاتی بحث می‌کنند که هیچ تأثیری بر آینده شرکت ندارد، در حالی که فرصت بررسی مسائل مهم‌تر را از دست می‌دهند.اگر رئیس هیئت‌مدیره نتواند جهت گفت‌وگوها را مدیریت کند، جلسات به میدان رقابت افراد تبدیل می‌شود و کیفیت تصمیم‌گیری به‌تدریج کاهش پیدا می‌کند.اشتباه ششم؛ نداشتن نگاه بلندمدتبیشتر مدیران اجرایی به دلیل ماهیت شغل خود، ناچارند بر مسائل کوتاه‌مدت تمرکز کنند.این کاملاً طبیعی است.اما اگر رئیس هیئت‌مدیره نیز فقط به فروش این ماه، هزینه‌های این فصل یا قراردادهای جاری فکر کند، دیگر چه کسی مسئول آینده شرکت خواهد بود؟شرکت‌هایی که ماندگار می‌شوند، معمولاً مدیرانی دارند که هم‌زمان در دو زمان زندگی می‌کنند؛ امروز را اداره می‌کنند و فردا را می‌سازند.رئیس هیئت‌مدیره باید مرتب از خود بپرسد:اگر همین روند ادامه پیدا کند، شرکت سه سال دیگر در چه جایگاهی خواهد بود؟آیا ساختار فعلی پاسخگوی رشد آینده است؟اگر تعداد کارکنان دو برابر شود، آیا فرآیندهای مدیریتی همچنان کارآمد خواهند بود؟اگر سرمایه‌گذار جدید وارد شرکت شود، آیا ساختار حاکمیت شرکتی آمادگی این تغییر را دارد؟این پرسش‌ها شاید امروز پاسخ مشخصی نداشته باشند، اما مطرح کردن آن‌ها باعث می‌شود شرکت همیشه چند قدم جلوتر از مشکلات حرکت کند.رئیس هیئت‌مدیره موفق، قهرمان داستان نیستدر فیلم‌ها معمولاً قهرمان کسی است که در لحظه بحران وارد می‌شود، همه تصمیم‌ها را خودش می‌گیرد و شرکت را نجات می‌دهد.اما در دنیای واقعی مدیریت، بهترین رئیس هیئت‌مدیره معمولاً کم‌سروصداترین فرد اتاق است.او تلاش نمی‌کند نشان دهد از همه بیشتر می‌داند.همه تصمیم‌ها را شخصاً نمی‌گیرد.همه پاسخ‌ها را آماده ندارد.در عوض، ساختاری ایجاد می‌کند که افراد مناسب بتوانند تصمیم‌های مناسب بگیرند.او مدیرعامل توانمند انتخاب می‌کند، جلسات مؤثر برگزار می‌کند، اختلاف‌ها را قبل از تبدیل شدن به بحران مدیریت می‌کند، اعضای هیئت‌مدیره را به گفت‌وگوی حرفه‌ای تشویق می‌کند و اجازه نمی‌دهد شرکت اسیر تصمیم‌های احساسی یا فردمحور شود.اگر روزی شرکتی بتواند حتی در غیاب رئیس هیئت‌مدیره نیز با همان کیفیت به مسیر خود ادامه دهد، شاید بتوان گفت آن رئیس هیئت‌مدیره وظیفه خود را به بهترین شکل انجام داده است. زیرا هدف اصلی او این نبوده که خودش محور همه تصمیم‌ها باشد؛ بلکه سیستمی ساخته است که موفقیت شرکت به حضور دائمی هیچ فردی وابسته نباشد. و شاید این، بزرگ‌ترین تفاوت میان یک مدیر خوب و یک رئیس هیئت‌مدیره ماندگار باشد.در این بخش قسمت اول رو به پایان میرسانیم و در بخش بعدی، سمت های دیگر رو بررسی خواهیم کرد.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Mon, 29 Jun 2026 13:56:43 +0330</pubDate>
            </item>
                    <item>
                <title>ارتباط مفاهیم مارکتینگ با مهندسی نرم افزار (بخش1 - UTM)</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D9%85%D8%A7%D8%B1%DA%A9%D8%AA%DB%8C%D9%86%DA%AF-%D8%A8%D8%A7-%D9%85%D9%87%D9%86%D8%AF%D8%B3%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D8%A8%D8%AE%D8%B41-utm-ayfzzisxvtma</link>
                <description>از Awareness تا Advocacy؛ نگاهی مهندسی به چرخه رشد کاربران و طراحی داده‌محور سیستم‌هاسلام. امیدوارم حالتون خوب باشه. امروز میخوام برخی از مفاهیم حساس مارکتینگ رو که ارتباط نزدیکی با برنامه نویس ها و طراحان، معماران و DBA ها داره رو مطرح کنم و بررسی کنیم ببینیم چه موضوعاتی را باید دانست. این مقاله بخش 1 از 4 بخش کلی است. در بسیاری از تیم‌های نرم‌افزاری، مفاهیمی مانند Awareness، Engagement، Conversion، Retention و Advocacy معمولاً متعلق به تیم مارکتینگ تلقی می‌شوند. اما واقعیت این است که این مفاهیم تنها شاخص‌های بازاریابی نیستند، بلکه مراحل مختلفی از چرخه عمر کاربر در یک محصول دیجیتال را توصیف می‌کنند. هر کاربری که وارد یک وب‌سایت، اپلیکیشن یا سرویس آنلاین می‌شود، در مسیری حرکت می‌کند که از آگاهی نسبت به محصول آغاز شده و در بهترین حالت به تبدیل شدن به یک حامی و مروج برند ختم می‌شود.برای مهندسان نرم‌افزار، برنامه‌نویسان Backend، متخصصان Data Engineering و طراحان پایگاه داده، درک این مسیر اهمیت ویژه‌ای دارد؛ زیرا هر مرحله از این چرخه نیازمند جمع‌آوری، ذخیره‌سازی و تحلیل داده‌هایی است که در نهایت مبنای تصمیم‌گیری کسب‌وکار خواهند بود.FunnelAwareness؛ نقطه آغاز سفر کاربرAwareness به مرحله‌ای گفته می‌شود که کاربر برای اولین بار با محصول، سرویس یا برند آشنا می‌شود. این آشنایی می‌تواند از طریق موتورهای جستجو، تبلیغات آنلاین، شبکه‌های اجتماعی، کمپین‌های ایمیلی یا معرفی سایر کاربران اتفاق بیفتد.از دید فنی، Awareness نقطه ورود داده‌ها به اکوسیستم محصول است. در این مرحله مهم‌ترین سؤال این است که کاربر از کجا آمده است؟برای پاسخ به این سؤال معمولاً از UTM Parameters استفاده می‌شود. پارامترهایی مانند utm_source، utm_medium، utm_campaign، utm_term و utm_content اطلاعات ارزشمندی درباره منشأ ترافیک فراهم می‌کنند. زمانی که کاربری وارد آدرس زیر می‌شود:https://example.com?utm_source=google&amp;utm_medium=cpc&amp;utm_campaign=summer_saleسیستم باید بتواند این اطلاعات را استخراج، اعتبارسنجی و ذخیره کند.یکی از اشتباهات رایج در بسیاری از پروژه‌ها این است که پارامترهای UTM تنها در ابزارهای تحلیلی مانند Google Analytics ثبت می‌شوند و در پایگاه داده محصول ذخیره نمی‌شوند. در نتیجه ارتباط میان منبع جذب کاربر و رفتارهای بعدی او از بین می‌رود.در معماری‌های مدرن، معمولاً در اولین درخواست کاربر، اطلاعات UTM در Cookie، Session یا Local Storage ذخیره شده و همزمان در پایگاه داده نیز ثبت می‌شوند تا در آینده بتوان رفتار کاربر را به کمپین اولیه منتسب کرد.Engagement؛ زمانی که کاربر با محصول تعامل می‌کندAwareness به تنهایی ارزش چندانی ایجاد نمی‌کند. بسیاری از کاربران وارد محصول می‌شوند اما هیچ تعاملی انجام نمی‌دهند. مرحله Engagement زمانی آغاز می‌شود که کاربر فعالیت معناداری در سیستم انجام دهد.تعریف تعامل به نوع محصول بستگی دارد. در یک فروشگاه اینترنتی، مشاهده محصولات یا افزودن کالا به سبد خرید می‌تواند Engagement محسوب شود. در یک SaaS ممکن است ایجاد پروژه جدید یا استفاده از یک قابلیت کلیدی نشانه تعامل باشد.از منظر مهندسی نرم‌افزار، Engagement معمولاً از طریق Event Tracking اندازه‌گیری می‌شود. هر تعامل مهم به صورت یک Event در سیستم ثبت می‌شود:Page ViewedProduct ViewedSearch PerformedProject CreatedFile Uploadedاین رویکرد Event-Driven باعث می‌شود رفتار کاربران به صورت دقیق قابل تحلیل باشد.هرچه کیفیت ثبت رویدادها بیشتر باشد، توانایی تیم در تحلیل رفتار کاربران و بهینه‌سازی محصول نیز افزایش خواهد یافت.Conversion؛ لحظه خلق ارزشConversion زمانی رخ می‌دهد که کاربر اقدام مورد انتظار کسب‌وکار را انجام دهد. این اقدام می‌تواند ثبت‌نام، خرید، فعال‌سازی اشتراک، تکمیل فرم یا هر هدف دیگری باشد.بسیاری از تیم‌ها نرخ تبدیل را صرفاً یک عدد بازاریابی در نظر می‌گیرند، اما در عمل Conversion نتیجه عملکرد صحیح کل سیستم است.اگر فرم ثبت‌نام کند باشد، اگر APIها تأخیر داشته باشند یا اگر فرآیند پرداخت دچار خطا شود، نرخ تبدیل کاهش پیدا می‌کند.به همین دلیل شاخص‌های فنی مانند:LatencyError RateAvailabilityPage Load Timeبه صورت مستقیم بر Conversion اثر می‌گذارند.در سازمان‌های داده‌محور، هر Conversion به عنوان یک رویداد مستقل ذخیره می‌شود تا بتوان مسیر کامل کاربر از Awareness تا Conversion را بازسازی کرد.Retention؛ مهم‌ترین شاخص موفقیت محصولبسیاری از محصولات می‌توانند کاربران جدید جذب کنند، اما تعداد کمی قادرند آن‌ها را حفظ کنند. Retention نشان می‌دهد چه تعداد از کاربران پس از اولین تجربه، مجدداً به محصول بازمی‌گردند.اگر Awareness نشان‌دهنده کیفیت جذب باشد و Conversion نشان‌دهنده توانایی متقاعدسازی، Retention معیار واقعی ارزش محصول است.از دید تحلیل داده، معمولاً Retention در بازه‌های زمانی مختلف اندازه‌گیری می‌شود:Day 1 RetentionDay 7 RetentionDay 30 RetentionMonthly Retentionبرای محاسبه Retention لازم است تاریخ اولین فعالیت کاربر و تمام تعاملات بعدی او ثبت شوند. به همین دلیل طراحی صحیح مدل داده نقش حیاتی دارد.Retention معمولاً یکی از سنگین‌ترین کوئری‌های تحلیلی را در سیستم ایجاد می‌کند و به همین دلیل بسیاری از سازمان‌ها داده‌های رفتاری را از پایگاه داده عملیاتی به Data Warehouse منتقل می‌کنند.Advocacy؛ زمانی که کاربر به موتور رشد تبدیل می‌شودآخرین مرحله چرخه، Advocacy است. در این مرحله کاربر نه تنها از محصول استفاده می‌کند، بلکه آن را به دیگران معرفی می‌کند.معرفی دوستان، اشتراک‌گذاری محتوا، ثبت بازخورد مثبت و تولید محتوا درباره محصول همگی نمونه‌هایی از Advocacy هستند.از دید کسب‌وکار، Advocacy کم‌هزینه‌ترین و پایدارترین کانال رشد است.از دید مهندسی داده، لازم است ارتباط میان کاربران معرفی‌کننده و کاربران معرفی‌شده قابل ردیابی باشد. سیستم‌های Referral معمولاً بر همین اساس طراحی می‌شوند.ارتباط میان مراحل چرخهاین پنج مفهوم را نباید به صورت مستقل در نظر گرفت. آن‌ها یک زنجیره متصل هستند.Awareness باعث ورود کاربران می‌شود.Engagement نشان می‌دهد کاربران به محصول علاقه‌مند شده‌اند.Conversion ثابت می‌کند محصول توانسته ارزش اولیه ایجاد کند.Retention نشان می‌دهد ارزش ایجاد شده پایدار بوده است.Advocacy نیز محصول را به یک موتور رشد خودکار تبدیل می‌کند.اگر هر مرحله ضعیف باشد، مراحل بعدی نیز تحت تأثیر قرار می‌گیرند. جذب میلیون‌ها کاربر بدون Retention عملاً ارزشی ایجاد نمی‌کند و Retention بالا بدون Awareness نیز رشد محصول را محدود خواهد کرد.طراحی پایگاه داده برای تحلیل چرخه رشد کاربرانیکی از الگوهای رایج در سیستم‌های مدرن استفاده از مدل Event-Based Analytics است.در این معماری، به جای ذخیره‌سازی صرف وضعیت فعلی کاربر، تمامی رویدادهای مهم ثبت می‌شوند.جدول Users اطلاعات هویتی کاربران را نگهداری می‌کند. جدول User Acquisition اطلاعات مربوط به اولین منبع جذب کاربر را ذخیره می‌کند. جدول Events نیز تمام تعاملات کاربر با سیستم را ثبت می‌کند.هر رویداد می‌تواند شامل موارد زیر باشد:شناسه کاربرنوع رویدادزمان وقوعاطلاعات زمینه‌ایپارامترهای اضافیبه عنوان مثال، رویداد Product Viewed می‌تواند شناسه محصول را در قالب Metadata ذخیره کند، در حالی که رویداد Purchase اطلاعات سفارش را در خود نگهداری می‌کند.مزیت این رویکرد آن است که در آینده می‌توان هر نوع تحلیل جدیدی را بدون تغییر ساختار اصلی داده انجام داد.مدیریت UTM در سطح پایگاه دادهیکی از تصمیم‌های مهم معماری، نحوه ذخیره‌سازی داده‌های UTM است.در بسیاری از پروژه‌ها، ذخیره‌سازی تنها در سطح Session انجام می‌شود. اما رویکرد حرفه‌ای‌تر این است که اطلاعات Acquisition به صورت دائمی در پایگاه داده ذخیره شوند.به عنوان مثال، هنگام ثبت‌نام کاربر می‌توان اطلاعات زیر را ثبت کرد:SourceMediumCampaignContentTermLanding Pageاین اطلاعات بعدها امکان تحلیل‌هایی مانند موارد زیر را فراهم می‌کنند:کدام کمپین بیشترین Conversion را ایجاد کرده است؟کدام منبع ترافیک بالاترین Retention را دارد؟کاربران جذب‌شده از گوگل چه تفاوتی با کاربران جذب‌شده از لینکدین دارند؟کدام کمپین بیشترین Advocacy را ایجاد کرده است؟پاسخ به این سؤالات تنها زمانی امکان‌پذیر است که داده‌های بازاریابی و داده‌های محصول در یک مدل داده یکپارچه نگهداری شوند.جمع‌بندیAwareness، Engagement، Conversion، Retention و Advocacy صرفاً اصطلاحات بازاریابی نیستند. این مفاهیم در واقع مراحل مختلف سفر کاربر در یک محصول دیجیتال را توصیف می‌کنند و هر مرحله نیازمند زیرساخت نرم‌افزاری، مدل داده و مکانیزم تحلیل مناسب است.مهندسان نرم‌افزار زمانی می‌توانند سیستم‌های داده‌محور و مقیاس‌پذیر طراحی کنند که این چرخه را به عنوان بخشی از معماری محصول در نظر بگیرند. ذخیره‌سازی صحیح UTMها، طراحی Event Store مناسب، پیاده‌سازی سیستم‌های تحلیلی و ایجاد ارتباط میان داده‌های جذب، رفتار و نگهداشت کاربران، همگی گام‌هایی هستند که محصول را از یک نرم‌افزار معمولی به یک سیستم قابل رشد و قابل اندازه‌گیری تبدیل می‌کنند.امیدوارم موفق باشید. </description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Mon, 15 Jun 2026 12:00:19 +0330</pubDate>
            </item>
                    <item>
                <title>واکاوی عمیق RFC 7636 و مکانیسم PKCE</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D9%88%D8%A7%DA%A9%D8%A7%D9%88%DB%8C-%D8%B9%D9%85%DB%8C%D9%82-rfc-7636-%D9%88-%D9%85%DA%A9%D8%A7%D9%86%DB%8C%D8%B3%D9%85-pkce-dodhm98ykhn2</link>
                <description>معماری امنیت در عصر اپلیکیشن‌های عمومیسلام و عرض ادب خدمت دوستان. در این بخش به بررسی موضوع PKCE و RFC 7636 خواهیم پرداخت تا ببینیم این موضوع در SSO هایی که با OAuth 2.0 و OIDC کار میکنند، چگونه است. با توجه به کثرت موضوعات و اینکه میخوام موضوع رو طوری بیان کنم که اون عزیزانی که اطلاعات اولیه هم ندارند رو پوشش بدهد، پس جریان رو به صورت زیر بخش بندی میکنم: بخش اول: مقدمه و ضرورت وجودیبخش دوم: کالبدشکافی مکانیسم PKCE و فرآیند تبادلبخش سوم: آناتومی سناریوهای حمله و تهدیدات پیش روبخش چهارم: چالش‌های پیاده‌سازی در معماری‌های توزیع‌شدهبخش پنجم: بررسی PKCE در وب‌اپلیکیشن‌ها و جایگاه آن در معماری مدرن وببخش ششم: پیاده‌سازی PKCE در اکوسیستم‌های مدیریت هویت: اختصاصاً Keycloakبخش هفتم: دستورالعمل اجرایی برای تیم‌های مهندسی؛ هماهنگی میان کلاینت و سروربخش اول: مقدمه و ضرورت وجودیدر دنیای توسعه نرم‌افزار مدرن، جایی که مرزهای بین کلاینت‌های قابل اعتماد و غیرقابل اعتماد به‌طور فزاینده‌ای محو شده‌اند، پروتکل OAuth 2.0 به عنوان ستون فقرات تبادل دسترسی‌ها شناخته می‌شود. با این حال، با ظهور اپلیکیشن‌های موبایل (Native Apps) و اپلیکیشن‌های تک‌صفحه‌ای (SPA)، حفره‌های امنیتی نوینی پدیدار شدند که در طراحی اولیه این پروتکل پیش‌بینی نشده بودند. مشکل اصلی در “کلاینت‌های عمومی” (Public Clients) نهفته است؛ کلاینت‌هایی که قادر به نگهداری امن یک “Secret” نیستند، زیرا کد منبع آن‌ها در اختیار کاربر نهایی قرار دارد. RFC 7636، که با نام PKCE (Proof Key for Code Exchange) شناخته می‌شود، نه یک وصله مقطعی، بلکه یک تغییر پارادایم در تأیید هویت است که تلاش می‌کند نقطه ضعف کلاسیکِ “رهگیری کد مجوز” را به طور کامل پوشش دهد. این مقاله به واکاوی ریاضیاتی و معماری این مکانیسم می‌پردازد تا روشن سازد چگونه یک لایه محافظتی مبتنی بر رمزنگاری، می‌تواند امنیت تبادلات در محیط‌های به ظاهر ناامن را تضمین کند.بخش دوم: کالبدشکافی مکانیسم PKCE و فرآیند تبادلتکنیک PKCE با معرفی یک جفت پارامتر پویا به نام‌های Code Verifier و Code Challenge، فرآیند سنتی صدور توکن را به یک پیوند رمزنگاری‌شده دوطرفه تبدیل می‌کند. برخلاف روش‌های سنتی که صرفاً به اعتبار “Client ID” تکیه داشتند، در این متد، کلاینت پیش از آغاز فرآیند احراز هویت، یک رشته تصادفی با آنتروپی بالا تولید کرده و هشِ آن را به عنوان چالش به سمت سرور می‌فرستد. زمانی که سرور کد مجوز را صادر می‌کند و کلاینت در مرحله نهایی قصد تبادل آن با Access Token را دارد، باید خودِ رشته اصلی (Verifier) را ارائه دهد. سرور با هش کردن این رشته و مقایسه آن با چالشی که در مرحله اول دریافت کرده بود، اطمینان حاصل می‌کند که درخواست‌کننده توکن، همان نهادی است که فرآیند احراز هویت را آغاز کرده است. این فرآیند، عملاً حملات تزریق کد که در آن مهاجم سعی می‌کند کد مجوزِ متعلق به یک نشست دیگر را برباید، خنثی می‌سازد، زیرا مهاجم دسترسی به Verifier اصلی کلاینت را ندارد.PKCE Flowبخش سوم: آناتومی سناریوهای حمله و تهدیدات پیش روبزرگترین تهدید امنیتی که PKCE برای مقابله با آن طراحی شده است، حمله “Authorization Code Interception” است. در سیستم‌عامل‌های موبایل، کلاینت‌ها برای دریافت پاسخ از سرور OAuth، از URIهای سفارشی استفاده می‌کنند. مهاجمان می‌توانند با ثبت یک URI مشابه در سیستم‌عامل، کدهای مجوزی که برای اپلیکیشن مقصد ارسال می‌شود را رهگیری کنند. بدون PKCE، این کد برای دریافت توکن کافی است و مهاجم می‌تواند به سادگی به حساب کاربری قربانی دسترسی یابد. اما با پیاده‌سازی این استاندارد، کدی که مهاجم سرقت کرده است، به دلیل عدم انطباق با مقدار Verifier که فقط در اختیار اپلیکیشن اصلی است، برای سرور احراز هویت بی‌اعتبار خواهد بود. علاوه بر این، بررسی دقیق‌تر نشان می‌دهد که PKCE در برابر حملات جعل نشست (Session Hijacking) نیز تا حد قابل قبولی مقاوم است، چرا که پیوند بین مرحله اول (درخواست کد) و مرحله دوم (درخواست توکن) از نظر زمانی و منطقی قفل شده است.بخش چهارم: چالش‌های پیاده‌سازی در معماری‌های توزیع‌شدهپیاده‌سازی موفقیت‌آمیز PKCE مستلزم هماهنگی دقیق بین لایه کلاینت و سرورِ صادرکننده توکن (Authorization Server) است. توسعه‌دهندگان باید توجه داشته باشند که استفاده از الگوریتم‌های هشینگ مانند SHA-256 در حال حاضر استاندارد طلایی محسوب می‌شود و متدهای ضعیف‌تر باید کنار گذاشته شوند. علاوه بر آن، مدیریت وضعیت (State Management) در سمت کلاینت برای ذخیره موقت Code Verifier تا زمان بازگشت از محیط احراز هویت، یکی از نقاط حساس است که اگر به درستی مدیریت نشود، می‌تواند منجر به خطاهای غیرمنتظره در تجربه کاربری شود. در سیستم‌های بزرگ‌مقیاس، این موضوع نه تنها یک چالش امنیتی، بلکه یک ضرورت در معماری سیستم‌های Zero-Trust است که باید در تمامی اپلیکیشن‌های موبایل و کلاینت‌های غیرقابل اعتماد پیاده‌سازی شود.بخش پنجم: بررسی PKCE در وب‌اپلیکیشن‌ها و جایگاه آن در معماری مدرن وباگرچه PKCE در ابتدا با هدف حل مسئله امنیتی کلاینت‌های عمومی، به‌ویژه اپلیکیشن‌های موبایل و دسکتاپ طراحی شد، اما در سال‌های اخیر اهمیت آن در وب‌اپلیکیشن‌ها نیز به‌شدت افزایش یافته است. دلیل این تغییر، تحول بنیادین در معماری وب است. وب‌اپلیکیشن‌های مدرن دیگر صرفاً صفحات ایستای سمت سرور نیستند؛ بلکه اغلب به صورت SPA، PWA یا ترکیبی از رندر سمت سرور و client-side rendering پیاده‌سازی می‌شوند و همین موضوع باعث می‌شود مرز میان client confidential و public به‌صورت کلاسیک دیگر چندان روشن نباشد. در چنین فضایی، PKCE نه فقط یک سازوکار تکمیلی، بلکه در بسیاری از سناریوها یک لایه حفاظتی ضروری برای جلوگیری از سوءاستفاده از authorization code محسوب می‌شود.در معماری سنتی وب، زمانی که اپلیکیشن در سمت سرور اجرا می‌شد و secret می‌توانست به‌صورت امن در محیط backend نگهداری شود، فرآیند OAuth 2.0 معمولاً با یک client secret همراه بود و این secret برای اثبات هویت کلاینت کافی تلقی می‌شد. اما در وب‌اپلیکیشن‌های مدرن، به‌ویژه آن‌هایی که بخش عمده منطق خود را در مرورگر اجرا می‌کنند، این فرض دیگر معتبر نیست. هر چیزی که در browser bundle قرار بگیرد، عملاً در معرض مشاهده، استخراج یا مهندسی معکوس قرار دارد. بنابراین در بسیاری از وب‌اپلیکیشن‌ها، حتی اگر ظاهراً با یک کلاینت وب طرف باشیم، از دید امنیتی با یک public client مواجه هستیم. PKCE دقیقاً در همین نقطه معنا پیدا می‌کند، زیرا به جای تکیه بر secret ثابت و قابل افشا، از یک وابستگی موقت، تصادفی و رمزنگاری‌شده برای اتصال مرحله آغازین و مرحله تبادل توکن استفاده می‌کند.در وب‌اپلیکیشن‌ها، استفاده از PKCE به‌ویژه زمانی اهمیت می‌یابد که کاربر از طریق مرورگر به یک Authorization Server هدایت می‌شود و پس از ورود، با یک authorization code به اپلیکیشن بازمی‌گردد. در یک سناریوی ساده، مهاجم می‌تواند تلاش کند از طریق دستکاری redirect URI، تزریق نشست، یا ربودن response code، کنترل فرآیند تبادل را به دست بگیرد. در نبود PKCE، اگر تنها authorization code برای گرفتن access token کافی باشد، هر موجودیتی که بتواند آن code را به دست آورد، بالقوه می‌تواند توکن را نیز دریافت کند. اما PKCE این زنجیره را می‌شکند، زیرا authorization code به‌تنهایی بی‌ارزش می‌شود مگر آنکه code verifier متناظر نیز ارائه شود. در نتیجه، حتی اگر مهاجم بتواند پاسخ احراز هویت را رهگیری کند، بدون داشتن verifier نمی‌تواند مرحله نهایی را کامل کند.از منظر طراحی سیستم، PKCE در وب‌اپلیکیشن‌ها به‌ویژه در سه الگوی رایج نقش حیاتی دارد. نخست، در SPAها که تمام یا بخش اعظم منطق در مرورگر اجرا می‌شود، استفاده از client secret عملاً بی‌معناست و PKCE تبدیل به مکانیزم اصلی حفاظت از exchange flow می‌شود. دوم، در اپلیکیشن‌هایی که از backend-for-frontend یا BFF architecture استفاده می‌کنند، PKCE می‌تواند بین مرورگر و backend نقش یک لایه امنیتی موقت را بازی کند و exchange code را به‌صورت ایمن‌تری به سرور قابل اعتماد منتقل نماید. سوم، در PWAها و معماری‌های ترکیبی، PKCE به اپلیکیشن کمک می‌کند تا حتی در حالی که وابسته به مرورگر است، سطحی از اطمینان را در اتصال authorization request و token request حفظ کند. در هر سه حالت، نکته اصلی این است که PKCE جایگزین کامل امنیت لایه‌های دیگر نیست، اما شکاف‌های بنیادین OAuth در کلاینت‌های غیرقابل اعتماد را به‌خوبی می‌بندد.البته باید توجه داشت که در وب‌اپلیکیشن‌ها، PKCE به‌تنهایی تضمین‌کننده امنیت کامل نیست. اگر redirect URIها به‌درستی محدود نشده باشند، اگر state parameter نادیده گرفته شود، اگر cross-site scripting در برنامه وجود داشته باشد، یا اگر توکن‌ها در storageهای ناامن مانند localStorage ذخیره شوند، آنگاه PKCE تنها یکی از اجزای دفاعی خواهد بود و نه همه آن. از این منظر، PKCE باید در کنار اصولی مانند use of HTTPS، کنترل دقیق redirect endpointها، مدیریت صحیح session، و طراحی مناسب token lifecycle دیده شود. مهندسی امنیت در وب، هیچ‌گاه با یک مکانیزم واحد تکمیل نمی‌شود؛ PKCE فقط یکی از اجزای ضروری این پازل است.در نهایت، می‌توان گفت PKCE در وب‌اپلیکیشن‌ها بیش از آنکه یک انتخاب اختیاری باشد، به یک استاندارد عملی برای کاهش ریسک در flows مبتنی بر authorization code تبدیل شده است. هرچه معماری وب به سمت توزیع‌شدگی بیشتر، client-side execution بیشتر و reliance کمتر بر secretهای ایستا حرکت می‌کند، نقش PKCE پررنگ‌تر می‌شود. از دید یک معمار نرم‌افزار، PKCE در وب نه یک جزئیات فنی حاشیه‌ای، بلکه بخشی از طراحی دفاعی سیستم است که باید از ابتدا در معماری authentication و authorization لحاظ شود.بخش ششم: پیاده‌سازی PKCE در اکوسیستم‌های مدیریت هویتبررسی اختصاصی در Keycloakدر دنیای واقعی و در میان معماران نرم‌افزار، پروتکل‌ها زمانی اهمیت واقعی خود را نشان می‌دهند که در قالب ابزارهای مدیریت هویت (Identity Providers) همچون Keycloak پیاده‌سازی می‌شوند. Keycloak به عنوان یک راهکار Enterprise، مسئولیت سنگینِ انطباق با استانداردهای پیچیده OAuth 2.0 و OIDC را بر دوش دارد. در این سیستم‌ها، PKCE دیگر یک گزینه اختیاری نیست، بلکه بخشی از سیاست‌های امنیتی یکپارچه (Security Policies) محسوب می‌شود. زمانی که یک معمار تصمیم می‌گیرد کلاینتی را در Keycloak تعریف کند، گزینه‌ای به نام “PKCE Enforcement” پیش‌روی او قرار می‌گیرد که فعال‌سازی آن، سیستم را از حالتِ اتکا به رمزهای استاتیک به سمت یک مدل اعتماد پویا سوق می‌دهد.در ساختار Keycloak، فرآیند احراز هویت با فعال بودن PKCE، به شکلی کاملاً سخت‌گیرانه مدیریت می‌شود. سرور در لحظه دریافت اولین درخواست، پارامترهای code_challenge و code_challenge_method را اعتبارسنجی می‌کند. اگر کلاینت این پارامترها را ارسال نکند و سرور در حالت “اجباری” قرار داشته باشد، Keycloak بلافاصله درخواست را با خطای امنیتی رد می‌کند. این سطح از سخت‌گیری برای محیط‌های تولیدی (Production) حیاتی است، زیرا مانع از آن می‌شود که توسعه‌دهندگان به‌صورت سهوی از جریان‌های قدیمی و آسیب‌پذیر استفاده کنند. در واقع، Keycloak نقش یک بازرس امنیتی را بازی می‌کند که اطمینان حاصل می‌کند پیش از صدور توکن، پیوند رمزنگاری بین درخواست اول و دوم به درستی برقرار شده است.علاوه بر این، Keycloak با ارائه گزینه‌های متعددی برای متدهای هشینگ، دست معماران را برای افزایش سطح امنیت باز می‌گذارد. در حالی که استاندارد پایه ممکن است استفاده از S256 را توصیه کند، سیستم‌های پیشرفته‌ای مانند Keycloak این امکان را فراهم می‌کنند که حتی سیاست‌های پیچیده‌تری بر اساس نوع کلاینت اعمال شود. برای مثال، کلاینت‌های موبایل که ریسک بالاتری دارند، می‌توانند مجبور به استفاده از متدهای هشینگ قوی‌تر شوند. این انعطاف‌پذیری در پیکربندی، PKCE را از یک کد ساده به یک ابزار مدیریتی تبدیل می‌کند که می‌تواند در طول چرخه حیاتِ یک اپلیکیشن، بسته به نیازهای امنیتی تغییر کند و ارتقا یابد.نکته قابل تأمل در استفاده از ابزارهایی نظیر Keycloak، تأثیر PKCE بر لاگ‌های حسابرسی (Audit Logs) و مانیتورینگ است. در یک سیستم متمرکز، ردیابیِ شکست‌های مربوط به PKCE می‌تواند نشانه‌ای از حملاتِ فعال (مانند Attempted Hijacking) باشد. وقتی Keycloak گزارشی از عدم تطابق code_verifier ارائه می‌دهد، تیم‌های عملیاتی و امنیتی می‌توانند این رویداد را به عنوان یک تلاش ناموفق برای سرقت توکن شناسایی کنند. در حقیقت، PKCE در کنار یک Identity Provider قدرتمند، نه تنها امنیتِ حین اجرا (Runtime) را تأمین می‌کند، بلکه سطح دید و قابلیت ردیابی (Observability) سیستم را در برابر تهدیدات سایبری به‌شکل قابل‌توجهی افزایش می‌دهد.در نهایت، استفاده از PKCE در محیط‌هایی که Keycloak یا سیستم‌های مشابه در آن‌ها نقش هسته مرکزی را دارند، به معنای پذیرش یک رویکرد دفاعی مدرن است. این رویکرد به جای اعتمادِ کورکورانه به کلاینت‌ها، آن‌ها را ملزم به اثبات مداوم هویت خود از طریق توابع ریاضی می‌کند. برای معماران، پیاده‌سازی PKCE در چنین پلتفرم‌هایی، انتقال بارِ مسئولیت احراز هویت از لایه‌های پراکنده به یک لایه مرکزی و مدیریت‌شده است که در آن امنیت، نه یک ویژگی جانبی، بلکه بخشی از ساختارِ زیربنایی تبادل داده‌هاست.بخش هفتم: دستورالعمل اجرایی برای تیم‌های مهندسی؛ هماهنگی میان کلاینت و سرورپیاده‌سازی PKCE در سطح کلان سازمانی، بیش از آنکه یک چالش رمزنگاری باشد، یک چالش هماهنگی میان تیم‌های توسعه فرانت‌اند و بک‌اند است. از دیدگاه معمار، این پروتکل زمانی به درستی عمل می‌کند که دو تیم، تعریفی واحد و یکپارچه از “قراردادِ تبادل” داشته باشند. برای تیم فرانت‌اند، PKCE به معنای مدیریت چرخه حیاتِ یک جفت رشته موقت (Verifier و Challenge) در طول فرآیند احراز هویت است، در حالی که برای تیم بک‌اند یا تیم پلتفرم، این به معنای اجبار به رعایت سخت‌گیرانه قوانین RFC 7636 در لایه Authorization Server و عدم صدور توکن در صورت عدم انطباق یا نقص در فرآیند است.تیم فرانت‌اند باید مسئولیت تولید و نگهداری موقت Code Verifier را بر عهده بگیرد. در این متدولوژی، فرانت‌اند موظف است پیش از آغازِ Redirect به سمت سرور هویت، یک رشته تصادفی با آنتروپی کافی (حداقل ۴۳ کاراکتر و حداکثر ۱۲۸ کاراکتر بر اساس استاندارد) تولید کند. نکته کلیدی اینجاست که فرانت‌اند نباید این مقدار را در حافظه‌های پایدار مانند localStorage ذخیره کند، زیرا این امر خطر نشت داده را افزایش می‌دهد؛ بلکه باید از حافظه‌های موقت نشست (Session Storage) یا حافظه رمِ اپلیکیشن استفاده کند. پس از تولید Verifier، فرانت‌اند باید مقدار Code Challenge را از طریق تابع هش SHA-256 محاسبه کرده و آن را در پارامترهای درخواستِ اولیه ارسال کند. دقت در اجرای دقیقِ Base64URL encoding در هر دو سمت، محل بروز بسیاری از باگ‌های اولیه است که باید در تست‌های واحد (Unit Testing) هر دو تیم لحاظ شود.از سوی دیگر، تیم بک‌اند در لایه Identity Provider وظیفه دارد تا Code Challenge و متد استفاده شده را در دیتابیسِ نشست‌های موقت خود ذخیره کند. این وظیفه حیاتی است که بک‌اند، کدهای مجوز (Authorization Codes) صادر شده را بدون در نظر گرفتن چالشِ مرتبط با آن‌ها به ثبت نرساند. هنگامی که کلاینت در مرحله دوم برای دریافت Access Token مراجعه می‌کند، بک‌اند باید بلافاصله مقدار Code Verifier دریافتی را با همان متد هشینگِ اعلام شده در مرحله اول پردازش کند. اگر هشِ تولید شده با مقدارِ ذخیره شده در دیتابیس مطابقت نداشت، بک‌اند باید نه تنها درخواست را رد کند، بلکه این رخداد را به عنوان یک هشدار امنیتی در سیستم مانیتورینگ ثبت نماید. هرگونه اغماض در این مرحله از سوی بک‌اند، کل فلسفه PKCE را زیر سوال می‌برد.در مباحث مربوط به پروتکل و ارتباطات، تیم‌های فرانت‌اند و بک‌اند باید بر سر «محدودیت‌های زمانی» یا همان Expiration Window به توافق برسند. کد مجوزِ صادر شده برای PKCE نباید طول عمر بالایی داشته باشد. اگر فاصله زمانی بین مرحله اول (صدور کد) و مرحله دوم (تبادل توکن) بیش از حد استاندارد شود، سرور باید کد را ابطال کند. همچنین، برای جلوگیری از حملات بازپخش (Replay Attacks)، پیاده‌سازیِ “یک‌بار مصرف بودن” کد مجوز توسط بک‌اند الزامی است؛ به این معنا که پس از اولین تلاش برای مبادله توکن (چه موفق و چه ناموفق)، آن کد مجوز باید بلافاصله از سیستم حذف شود. این سطح از سخت‌گیریِ هماهنگ‌شده است که باعث می‌شود یک سیستم نرم‌افزاری در برابر مهاجمانِ حرفه‌ای مقاومت کند.در نهایت، برای رسیدن به یک پیاده‌سازی بدون نقص، توصیه می‌شود که تیم‌ها از کتابخانه‌های استاندارد و تست‌شده برای OAuth 2.0 استفاده کنند و از پیاده‌سازی دستی منطق هشینگ یا تولید رشته‌های تصادفی پرهیز نمایند. پیاده‌سازی PKCE یک فرآیند “بلاک‌محور” است؛ یعنی اگر یکی از مراحلِ زنجیره اعتبارسنجی شکست بخورد، کل فرآیند باید متوقف شود. معماران باید در جلسات طراحی (Design Review)، روی این موضوع تأکید کنند که خطاهای مربوط به PKCE نباید اطلاعات حساسی را به مهاجم نشت دهند؛ بلکه باید پیام‌های خطای استاندارد و خنثی بازگردانده شود تا از تکنیک‌های Enumeration جلوگیری شود. تعاملِ دقیقِ فرانت‌اند و بک‌اند در این حوزه، عملاً تضمین‌کننده آن است که امنیت در اپلیکیشن شما، فراتر از یک شعارِ بازاریابی، در لایه‌های کد جاری است.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Thu, 11 Jun 2026 11:25:51 +0330</pubDate>
            </item>
                    <item>
                <title>موضوع CDC (Change Data Capture) در SQL Server</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D9%85%D9%88%D8%B6%D9%88%D8%B9-cdc-change-data-capture-%D8%AF%D8%B1-sql-server-l1ww0jfhxy9j</link>
                <description>راهنمای جامع فعال‌سازی و مدیریت CDCقابلیت Change Data Capture یا به اختصار CDC، یکی از ابزارهای قدرتمند در SQL Server برای ردیابی تغییرات (Insert، Update، Delete) در جداول دیتابیس است. برخلاف روش‌های سنتی مانند تریگرها (Triggers) که بار پردازشی زیادی به سیستم تحمیل می‌کنند، CDC با خواندن مستقیم Transaction Log، تأثیر ناچیزی بر عملکرد دیتابیس دارد.در این مقاله، به نحوه پیکربندی و مدیریت CDC می‌پردازیم. قبل از اینکه یادم بره بگم که موضوع فقط برای SQL SERVER نیست و برای دیگر سیستم ها وجود داره. مثلاً PostgreSQL (با ابزار Logical Decoding)MySQL (با استفاده از Binary Log)Oracle (با استفاده از Oracle GoldenGate)یا دیگر ابزار ها و مکانیزم ها. منتها در این مقاله، تمرکز، روی SQL SERVER هست.SQL Server - CDC - Transaction Log۱. پیش‌نیازهای فعال‌سازیقبل از شروع، باید اطمینان حاصل کنید که Agent سرویس SQL Server در حال اجرا است؛ چرا که CDC برای مدیریت لاگ‌های تغییرات از Capture Jobها استفاده می‌کند.همچنین، برای فعال‌سازی CDC، ابتدا باید آن را در سطح دیتابیس فعال کنید:                                                                    
USE YourDatabaseName;
GO
EXEC sys.sp_cdc_enable_db;
GO
نکته: برای اطمینان از فعال شدن، می‌توانید فیلد is_cdc_enabled را در جدول sys.databases بررسی کنید.۲. نحوه فعال‌سازی CDC برای جداولپس از فعال‌سازی در سطح دیتابیس، باید CDC را برای جدول مورد نظر خود روشن کنید. این کار با استفاده از پروسیجر sys.sp_cdc_enable_table انجام میشه.                                            
EXEC sys.sp_cdc_enable_table
    @source_schema = N&#039;dbo&#039;,
    @source_name   = N&#039;YourTableName&#039;,
    @role_name     = NULL; -- در صورت نیاز به محدودیت دسترسی، نقش تعریف کنید
GO
پس از اجرای این دستور، SQL Server به صورت خودکار یک Schema جدید به نام cdc ایجاد کرده و جداول سیستمی برای ذخیره تغییرات (Change Tables) می‌سازد.۳. نحوه غیرفعال‌سازی (Disable)اگر دیگر نیازی به ردیابی تغییرات ندارید، غیرفعال‌سازی به دو صورت انجام می‌شود:غیرفعال‌سازی برای یک جدول خاص:                                            
EXEC sys.sp_cdc_disable_table
    @source_schema = N&#039;dbo&#039;,
    @source_name   = N&#039;YourTableName&#039;,
    @capture_instance = N&#039;all&#039;;
GO
غیرفعال‌سازی برای کل دیتابیس:                                            
USE YourDatabaseName;
GO
EXEC sys.sp_cdc_disable_db;
GO
۴. دستورات و مدیریت تغییراتوقتی CDC فعال است، داده‌های تغییر یافته در جداول جانبی ذخیره می‌شوند. برای کوئری گرفتن از این تغییرات، از توابع سیستمی استفاده می‌کنیم:استخراج تغییراتبرای مشاهده تغییرات ثبت شده در یک بازه زمانی، از تابع cdc.fn_cdc_get_all_changes_... استفاده می‌شود:DECLARE @from_lsn BINARY(10), @to_lsn BINARY(10);

-- دریافت محدوده LSN
SET @from_lsn = sys.fn_cdc_get_min_lsn(&#039;dbo_YourTableName&#039;);
SET @to_lsn   = sys.fn_cdc_get_max_lsn();

-- نمایش تغییرات
SELECT * FROM cdc.fn_cdc_get_all_changes_dbo_YourTableName(@from_lsn, @to_lsn, &#039;all&#039;);
اگر نمیدونید LSN چی هست، به معنای Log Serial Number هست که SQL میده به لاگمدیریت Jobهامدیریت CDC بر عهده دو Job اصلی در SQL Server Agent است:cdc.YourDB_capture: داده‌ها را از لاگ می‌خواند و در جداول CDC می‌نویسد.cdc.YourDB_cleanup: داده‌های قدیمی (بیش از دوره نگهداری پیش‌فرض که ۷۲ ساعت است) را پاک می‌کند.برای تغییر دوره نگهداری (مثلاً به ۴۸ ساعت):EXEC sys.sp_cdc_change_job 
    @job_type = &#039;cleanup&#039;, 
    @retention = 2880; -- زمان به دقیقه
نکات کلیدی برای محیط‌های عملیاتی (Production)Storage Space: جداول CDC فضای دیسک را اشغال می‌کنند. حتماً تنظیمات cleanup را متناسب با نیاز خود بهینه‌سازی کنید.Transaction Log: از آنجایی که CDC به Log وابسته است، در دیتابیس‌هایی که تغییرات بسیار سنگینی دارند، ممکن است باعث رشد سریع Log File شود (در مدل Recovery Full، حتماً Log Backup منظم داشته باشید).Performance: اگرچه CDC بهینه است، اما فعال کردن آن برای جداول بسیار حجیم با نرخ تراکنش بالا، نیاز به پایش دقیق منابع دارد.امیدوارم موفق باشید.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Tue, 09 Jun 2026 10:26:10 +0330</pubDate>
            </item>
                    <item>
                <title>سند ADR چیست و چرا برای معماران و تحلیلگران داده حیاتی است؟</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%B3%D9%86%D8%AF-adr-%DA%86%DB%8C%D8%B3%D8%AA-%D9%88-%DA%86%D8%B1%D8%A7-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D8%A7%D9%86-%D9%88-%D8%AA%D8%AD%D9%84%DB%8C%D9%84%DA%AF%D8%B1%D8%A7%D9%86-%D8%AF%D8%A7%D8%AF%D9%87-%D8%AD%DB%8C%D8%A7%D8%AA%DB%8C-%D8%A7%D8%B3%D8%AA-zv3ekqkksanv</link>
                <description>سلام. امیدوارم حالتون خوب باشه. امروز در مورد اسناد ADR باهم صحبت میکنیم. در بسیاری از شرکت‌های مهندسی نرم‌افزار، مخصوصاً در تیم‌هایی که با سرعت بالا محصول می‌سازند، تصمیم‌های فنی مهمی روزانه گرفته می‌شوند؛ تصمیم‌هایی که اثر آن‌ها فقط در لحظه‌ی طراحی یا پیاده‌سازی دیده نمی‌شود، بلکه ماه‌ها و حتی سال‌ها بعد در مقیاس‌پذیری، نگه‌داری، توسعه‌پذیری، کیفیت داده، هزینه‌ی زیرساخت و سرعت تحویل محصول خود را نشان می‌دهند. یکی از مهم‌ترین ابزارهایی که به تیم‌های فنی کمک می‌کند این تصمیم‌ها را شفاف، مستند و قابل‌ردیابی نگه دارند، ADR یا Architecture Decision Record است.ADR در ساده‌ترین تعریف، یک سند کوتاه اما ساختارمند برای ثبت تصمیم‌های معماری و فنی مهم است؛ تصمیم‌هایی که باید مشخص باشد چه چیزی تصمیم گرفته شد، چرا این تصمیم گرفته شد، چه گزینه‌هایی بررسی شد، چه پیامدهایی دارد، و چه کسی/چه زمانی آن را تأیید کرده است. این سند در ظاهر ساده است، اما در عمل یکی از مؤثرترین ابزارهای مدیریت دانش فنی در سازمان‌های نرم‌افزاری محسوب می‌شود.ADR فقط یک سند نیست؛ یک «سیستم تصمیم‌گیری» استاشتباه رایجی که بسیاری از تیم‌ها مرتکب می‌شوند این است که ADR را صرفاً به‌عنوان یک فایل مستنداتی یا یک فرم اداری نگاه می‌کنند. در حالی‌که ADR در واقع بخشی از فرآیند مهندسی تصمیم است. یعنی ADR زمانی ارزشمند می‌شود که تصمیم‌های فنی را از حالت شفاهی، سلیقه‌ای و پراکنده خارج کند و آن‌ها را به یک دارایی سازمانی تبدیل کند.در شرکت‌های نرم‌افزاری، معمولاً تصمیم‌ها در جلسات، چت‌ها، تماس‌ها، ریویوها و گاهی در ذهن افراد ارشد باقی می‌مانند. مشکل اینجاست که وقتی فرد تصمیم‌گیرنده تیم را ترک می‌کند، یا وقتی پروژه وارد فاز نگه‌داری و توسعه می‌شود، تیم جدید دیگر به منطق پشت تصمیم دسترسی ندارد. ADR این شکاف را پر می‌کند.در واقع ADR پاسخ می‌دهد به این سؤال کلیدی:«چرا این راه را انتخاب کردیم و چرا راه‌های دیگر را انتخاب نکردیم؟»این سؤال به‌ظاهر ساده، در پروژه‌های واقعی یکی از مهم‌ترین سؤالات است. چون اغلب مشکلات فنی به این دلیل رخ نمی‌دهند که تیم تصمیم بد گرفته، بلکه به این دلیل رخ می‌دهند که تیم بعدی دلیل تصمیم قبلی را نمی‌داند و دوباره همان بحث را از صفر آغاز می‌کند.ADR برای چه کسانی است؟اگرچه ADR در بسیاری از تیم‌ها توسط معمار نرم‌افزار نوشته می‌شود، اما مخاطب آن محدود به معمار نیست. این سند برای طیف وسیعی از نقش‌ها در شرکت‌های مهندسی نرم‌افزار مفید است:معمار نرم‌افزار برای ثبت انتخاب‌های کلان معماریتحلیلگر داده برای مستندسازی تصمیم‌های مربوط به مدل داده، خط لوله داده، کیفیت داده و ذخیره‌سازیتوسعه‌دهنده ارشد برای ثبت تصمیم‌های فنی مؤثر بر کدنویسی و ساختار سرویس‌هاDevOps / SRE برای تصمیم‌های مرتبط با استقرار، زیرساخت و پایشProduct Engineer برای تصمیم‌هایی که میان نیاز محصول و محدودیت فنی تعادل ایجاد می‌کنندمدیر فنی برای بازبینی و ردیابی مسیر تصمیم‌ها در طول زمانبه‌خصوص برای معماران و تحلیلگران داده، ADR نقش بسیار مهمی دارد. زیرا تصمیم‌های این دو نقش اغلب در مرز میان نیاز کسب‌وکار و پیچیدگی فنی قرار می‌گیرد. معمار درباره ساختار سیستم تصمیم می‌گیرد و تحلیلگر داده درباره ساختار و جریان اطلاعات. هر دو حوزه اگر مستند نشوند، خیلی سریع به آشفتگی، وابستگی‌های پنهان و دوباره‌کاری منجر می‌شوند.نمونه ADR تولید شده با ابزار adr-toolsچرا ADR در شرکت‌های مهندسی نرم‌افزار اهمیت دارد؟اهمیت ADR را می‌توان از چند زاویه بررسی کرد. نخست اینکه ADR باعث کاهش حافظه‌ی شفاهی سازمان می‌شود. در بسیاری از شرکت‌ها، تصمیم‌ها در ذهن چند نفر کلیدی متمرکز است. این وضعیت در کوتاه‌مدت شاید کارآمد به نظر برسد، اما در بلندمدت خطرناک است. چون سازمان به جای تکیه بر دانش مکتوب، به افراد خاص وابسته می‌شود.دوم اینکه ADR به شفافیت تصمیم‌ها کمک می‌کند. وقتی تصمیم‌ها ثبت شوند، امکان بازبینی و نقد فنی آن‌ها وجود دارد. تیم‌ها می‌توانند ببینند که آیا تصمیم بر اساس داده، محدودیت، هزینه و اولویت درست گرفته شده یا نه. این شفافیت، سطح بلوغ مهندسی سازمان را بالا می‌برد.سوم اینکه ADR به کاهش اصطکاک بین تیم‌ها کمک می‌کند. بسیاری از اختلاف‌های بین تیم معماری، توسعه، داده و زیرساخت به این دلیل رخ می‌دهد که هر تیم تصور متفاوتی از تصمیم دارد. ADR به‌عنوان یک منبع مشترک، این اختلاف برداشت را کاهش می‌دهد.چهارم اینکه ADR برای آینده‌پژوهی فنی بسیار ارزشمند است. وقتی بعداً بخواهید دلیل استفاده از یک دیتابیس، یک الگوی معماری، یک ابزار ETL (ETL از سه واژه، استخراج (Extract)، تبدیل (Transform) و بارگذاری (Load) برگرفته شده است و فرآیند یکپارچه سازی داد‌ه‌ها (Data Integration) محسوب می‌شود) یا یک روش پیاده‌سازی را بررسی کنید، ADR به شما نشان می‌دهد که آن تصمیم در چه شرایطی گرفته شده و چه قیودی وجود داشته است.ADR چه چیزهایی را ثبت می‌کند؟یک ADR خوب معمولاً این اجزا را دارد:عنوان تصمیمتاریخوضعیت تصمیممثل: پیشنهادی، پذیرفته‌شده، ردشده، منسوخ‌شدهزمینه یا Contextمسئله چه بوده؟ چه نیازی وجود داشته؟تصمیمگزینه‌های بررسی‌شدهمقایسه گزینه‌هادلایل انتخابپیامدها و عوارضنقاط ریسکمراحل اجراارجاعات و لینک‌هانکته مهم این است که ADR نباید صرفاً خروجی نهایی را بگوید؛ بلکه باید مسیر فکری تصمیم را نشان دهد. اگر ADR فقط یک جمله‌ی «ما PostgreSQL را انتخاب کردیم» باشد، هنوز ADR کامل نیست. ارزش ADR در آن است که توضیح دهد چرا PostgreSQL و چرا نه گزینه‌های دیگر.تفاوت ADR با مستندات عمومی چیست؟ADR با مستندات مرسوم تفاوت مهمی دارد. مستندات عمومی معمولاً توصیفی‌اند؛ یعنی توضیح می‌دهند سیستم چه‌طور کار می‌کند. اما ADR تصمیم‌محور است؛ یعنی توضیح می‌دهد چه تصمیمی گرفته شد و چرا.برای مثال، یک سند معماری ممکن است جریان سرویس‌ها، دیاگرام‌ها و اجزای سیستم را توصیف کند. اما ADR می‌گوید چرا ارتباط بین سرویس‌ها رویدادمحور شد، چرا معماری مونو‌لیت به میکروسرویس تغییر کرد، چرا برای گزارش‌گیری از Warehouse جداگانه استفاده شد، یا چرا مدل ذخیره‌سازی داده به شکل خاصی طراحی شد.به بیان دیگر، اگر مستندات معماری «نقشه» باشند، ADR «منطق انتخاب مسیر» است.ADR و نقش معمار نرم‌افزاربرای معمار نرم‌افزار، ADR یکی از بنیادی‌ترین ابزارهای ثبت تصمیم است. معمار دائماً بین گزینه‌های مختلف باید انتخاب کند:مونو‌لیت یا میکروسرویس؟REST یا gRPC؟همگام یا ناهمگام؟SQL یا NoSQL؟Cache در چه لایه‌ای؟Event Sourcing لازم است یا نه؟مدل داده متمرکز باشد یا توزیع‌شده؟هر یک از این انتخاب‌ها روی هزینه، پیچیدگی، عملکرد، توسعه‌پذیری و نگه‌داری اثر می‌گذارد. اگر این تصمیم‌ها مستند نشوند، بعداً معلوم نیست چرا انتخاب شده‌اند و آیا هنوز هم معتبرند یا نه.ADR به معمار کمک می‌کند تصمیم‌ها را از سطح «نظر» به سطح «استدلال قابل‌ردیابی» ارتقا دهد. این موضوع مخصوصاً در سازمان‌هایی که رشد می‌کنند بسیار مهم است، چون تصمیمی که امروز برای ۵ نفر مناسب بوده، ممکن است برای ۵۰ نفر ناکافی باشد. ADR کمک می‌کند این تغییرات با آگاهی و مستندات مناسب انجام شوند.ADR و نقش تحلیلگر دادهبرای تحلیلگر داده، ADR کمتر از معمار نیست؛ شاید در برخی سازمان‌ها حتی مهم‌تر هم باشد. چون تصمیم‌های داده‌ای مستقیماً روی کیفیت تحلیل، گزارش‌گیری، تصمیم‌سازی تجاری و عملکرد سیستم‌های تحلیلی اثر می‌گذارند.تحلیلگر داده با موضوعاتی مثل این‌ها مواجه است:تعریف منبع حقیقت دادهانتخاب ساختار انبار دادهطراحی مدل ستاره‌ای یا برفی (در آینده بیشتر صحبت میکنیم)نحوه پاک‌سازی و اعتبارسنجی دادهتعریف KPIها و شاخص‌های تحلیلیانتخاب ابزارهای ETL/ELT (در آینده بیشتر صحبت میکنیم)تعیین زمان‌بندی به‌روزرسانی دادهمدیریت داده‌های ناقص، تکراری یا ناسازگاراگر این تصمیم‌ها مستند نشوند، بعداً گزارش‌ها با یکدیگر ناسازگار می‌شوند، منابع مختلف یک عدد متفاوت از یک KPI ارائه می‌دهند، و تیم کسب‌وکار اعتماد خود را به داده از دست می‌دهد.ADR برای تحلیلگر داده کمک می‌کند تصمیم‌های مربوط به مدل داده و خط لوله تحلیلی ثبت شوند و معلوم باشد که چرا یک منبع بر دیگری ترجیح داده شده، چرا یک فیلد حذف یا تبدیل شده، و چرا یک تعریف خاص برای یک KPI پذیرفته شده است.چه تصمیم‌هایی باید ADR داشته باشند؟همه چیز نیاز به ADR ندارد. اگر هر انتخاب کوچک را ADR کنید، سندها تبدیل به بایگانی بی‌اثر می‌شوند. ADR باید برای تصمیم‌هایی استفاده شود که اثر معماری، داده‌ای، هزینه‌ای یا عملیاتی قابل توجه دارند. برای مثال:انتخاب پایگاه داده اصلی (توسط هد تیم بانک اطلاعاتی)تغییر مدل معماریتصمیم درباره مسیر ارتباط بین سرویس‌هاانتخاب الگوی ذخیره‌سازی دادهتعریف strategy برای replication یا shardingتغییر ساختار warehouse یا data martانتخاب ابزار orchestrationاستفاده از message brokerانتخاب نوع cacheتصمیم درباره استانداردهای naming یا schema evolutionتصمیم‌های مربوط به consistency و eventual consistencyقاعده‌ی خوب این است:اگر تصمیم به‌سادگی قابل بازگشت نیست، یا اگر عدم ثبت آن در آینده هزینه‌زا خواهد بود، احتمالاً باید ADR داشته باشد.ساختار یک ADR استانداردببینید اگر بخواهیم یک قالب عملی برای ADR ارائه کنیم، ساختار زیر رایج و مؤثر خواهد بود:1. عنوانعنوان باید کوتاه، مشخص و توصیفی باشد.مثلاً:انتخاب PostgreSQL به‌عنوان پایگاه داده اصلیمهاجرت از REST به event-driven communicationاستفاده از dbt برای لایه تبدیل دادهجداسازی OLTP از OLAP2. وضعیتوضعیت ADR معمولاً یکی از این‌هاست:ProposedAcceptedDeprecatedSupersededRejected3. زمینهدر این بخش مسئله، محدودیت‌ها و نیازها توضیح داده می‌شود.مثلاً: حجم تراکنش‌ها زیاد شده، گزارش‌گیری کند است، تیم توسعه به سرعت در حال رشد است، یا نیاز به مقیاس‌پذیری افقی داریم.4. تصمیمخلاصه و روشن: چه چیزی انتخاب شد.5. گزینه‌هاحداقل 2 تا 4 گزینه بررسی شوند. این بخش مهم است، چون نشان می‌دهد تصمیم از روی بررسی بوده نه ترجیح شخصی.6. پیامدهامزایا، معایب، ریسک‌ها و هزینه‌های تصمیم.7. اجرااگر لازم است، قدم‌های عملی مهاجرت یا پیاده‌سازی نیز ذکر شود.8. تاریخ و مالکمشخص باشد چه زمانی ثبت شده و مسئول آن کیست.ویژگی‌های یک ADR خوبADR خوب باید چند ویژگی کلیدی داشته باشد:مختصر ولی کامل باشدتصمیم‌محور باشد، نه روایت‌محورمستدل باشد، نه سلیقه‌ایقابل‌جست‌وجو باشدقابل‌نسخه‌گذاری باشدقابل‌ردیابی باشدقابل‌به‌روزرسانی باشدADR نباید به‌قدری طولانی شود که کسی آن را نخواند. در عین حال نباید آن‌قدر کوتاه باشد که صرفاً یک جمله‌ی مبهم از آن بماند. تعادل بین عمق و اختصار، یکی از هنرهای اصلی نوشتن ADR است.نمونه ADR تولید شده با adr-toolsخطاهای رایج در نوشتن ADRیکی از خطاهای رایج این است که تیم‌ها ADR را بعد از تصمیم و صرفاً برای «پر کردن مستندات» می‌نویسند. در این حالت ADR بیشتر یک گزارش پسینی است تا یک ابزار تصمیم‌سازی.خطای رایج دیگر این است که ADR بدون گزینه‌های جایگزین نوشته می‌شود. وقتی گزینه‌های دیگر بررسی نشده باشند، ارزش تحلیلی سند پایین می‌آید.خطای سوم، تبدیل ADR به متن مبهم و کلی است. عباراتی مثل «به‌دلیل بهتر بودن» یا «به‌خاطر مقیاس‌پذیری» کافی نیستند. باید دقیق گفته شود این بهتر بودن در چه معناست: عملکرد؟ سادگی؟ هزینه؟ تیم‌پذیری؟ نگه‌داری؟خطای دیگر این است که ADRها نگه‌داری نمی‌شوند. تصمیم‌ها عوض می‌شوند، اما ADRها به‌روز نمی‌شوند. نتیجه این می‌شود که مخزن مستندات پر از اطلاعات قدیمی و گمراه‌کننده است.ADR و تصمیم‌های داده‌ای: یک مثال مفهومیبیایید فرض کنیم تیم می‌خواهد برای گزارش‌گیری از داده‌های عملیاتی، انبار داده جداگانه‌ای ایجاد کند. گزینه‌ها ممکن است این‌ها باشند:گزارش‌گیری مستقیم از دیتابیس عملیاتیاستفاده از replica فقط‌خواندنیساخت data warehouse مستقلاستفاده از pipeline مبتنی بر CDC به معنای (CDC (Change Data Capture)) - در مورد CDC در حوزه بانک های اطلاعاتی و دیتابیس ها با مدیران پایگاه داده خیلی صحبت داریم.انجام ETL شبانهدر ADR باید روشن شود چرا هر گزینه بررسی شد و چرا مثلاً data warehouse مستقل انتخاب شد. شاید دلیل این باشد که گزارش‌گیری مستقیم فشار زیادی به سیستم عملیاتی وارد می‌کند، replica فقط‌خواندنی تأخیر دارد، ETL شبانه برای نیاز near-real-time کافی نیست، و CDC تعادل خوبی بین freshness و complexity ایجاد می‌کند.این نوع ثبت تصمیم، بعداً برای تحلیلگر داده و معمار بسیار ارزشمند خواهد بود، چون در زمان تغییر نیازمندی‌ها، می‌توانند بفهمند که انتخاب فعلی بر چه فرض‌هایی استوار بوده است.ADR در چرخه عمر پروژهADR فقط برای شروع پروژه نیست. در طول چرخه عمر نرم‌افزار کاربرد دارد:در فاز Discovery برای ثبت گزینه‌های اولیهدر فاز Design برای نهایی کردن انتخاب‌هادر فاز Implementation برای جلوگیری از انحرافدر فاز Operations برای تحلیل اثر تصمیم‌هادر فاز Refactoring برای ثبت تغییرات بنیادیدر فاز Migration برای مستندسازی انتقال از یک فناوری به فناوری دیگردر واقع ADR مثل حافظه‌ی تصمیم‌گیری سیستم است و باید همراه با پروژه رشد کند.فرهنگ سازمانی و ADRموفقیت ADR فقط به قالب و ابزار بستگی ندارد؛ به فرهنگ سازمانی هم وابسته است. اگر سازمانی تصمیم‌های فنی را فقط از بالا به پایین دیکته کند، ADR تبدیل به یک تشریفات می‌شود. اما اگر فرهنگ شفافیت، نقد فنی، مستندسازی و بازبینی وجود داشته باشد، ADR به یک ابزار زنده و مؤثر تبدیل می‌شود.در بهترین حالت، ADR باید بخشی از فرایند طبیعی تیم باشد؛ درست مثل کدریویو، تست و استقرار. یعنی هر تصمیم مهم فنی، قبل یا همزمان با اجرا، در قالب ADR دیده و بررسی شود.ابزارها و محل نگه‌داری ADRADR می‌تواند در یک repository جداگانه یا کنار کد پروژه نگه‌داری شود. بسیاری از تیم‌ها از فایل‌های Markdown استفاده می‌کنند، چون ساده، نسخه‌پذیر و سازگار با Git هستند.مزیت نگه‌داری ADR در Git این است که:تاریخچه تغییرات مشخص استامکان review و comment وجود داردبا کد و تغییرات فنی هم‌نسخه می‌شودبرای تیم‌های فنی ساده و قابل‌دسترس استبعضی تیم‌ها ADR را در Notion، Confluence یا Wiki نگه می‌دارند. این هم می‌تواند مناسب باشد، اما مهم‌تر از ابزار، دسترسی‌پذیری، نسخه‌پذیری و انضباط نگه‌داری است.جمع‌بندیبریم موضوع رو جمع بندی کنیم. ADR برای شرکت‌های مهندسی نرم‌افزار چیزی فراتر از یک فایل مستنداتی است. این سند، حافظه‌ی تصمیم‌گیری سازمان، ابزار شفاف‌سازی استدلال فنی، و یکی از مهم‌ترین پایه‌های بلوغ معماری و داده به‌شمار می‌آید.برای معمار نرم‌افزار، ADR کمک می‌کند تصمیم‌های ساختاری و زیرساختی قابل‌ردیابی شوند. برای تحلیلگر داده، ADR تضمین می‌کند که انتخاب‌های تحلیلی، مدل داده و جریان اطلاعات با منطق و شفافیت ثبت شوند.در دنیایی که پروژه‌ها سریع تغییر می‌کنند، تیم‌ها جابه‌جا می‌شوند و فناوری‌ها دائماً در حال تحول‌اند، ADR یک ابزار لوکس نیست؛ یک ضرورت مهندسی است. سازمانی که ADR را جدی می‌گیرد، در واقع به آینده‌ی سیستم خود احترام می‌گذارد. عزیزانی که میخواهند ADR درست کنند، adr-tools، این استانداردترین ابزار در این حوزه است. اگرچه اصالتاً برای لینوکس/مک نوشته شده، اما در ویندوز از طریق WSL (Windows Subsystem for Linux) یا Git Bash به راحتی اجرا می‌شود.همیشه ADR داشته باشید. موفق باشید.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Tue, 09 Jun 2026 10:03:14 +0330</pubDate>
            </item>
                    <item>
                <title>مکانیزم کنترل همزمانی چندنسخه‌ای (MVCC)</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D9%85%DA%A9%D8%A7%D9%86%DB%8C%D8%B2%D9%85-%DA%A9%D9%86%D8%AA%D8%B1%D9%84-%D9%87%D9%85%D8%B2%D9%85%D8%A7%D9%86%DB%8C-%DA%86%D9%86%D8%AF%D9%86%D8%B3%D8%AE%D9%87-%D8%A7%DB%8C-mvcc-curedkajtkcs-curedkajtkcs</link>
                <description>در سیستم‌های پایگاه داده، اجرای همزمان چندین تراکنش یک موضوع اجتناب‌ناپذیر است. کاربران مختلف به‌طور همزمان داده‌ها را می‌خوانند یا تغییر می‌دهند و پایگاه داده باید به شکلی این همزمانی را مدیریت کند که هم کارایی حفظ شود و هم سازگاری داده‌ها از بین نرود. یکی از رویکردهای مهم برای حل این مسئله، مکانیزم کنترل همزمانی چندنسخه‌ای یا MVCC (Multi-Version Concurrency Control) است.در MVCC، به‌جای اینکه هر تغییر مستقیماً روی داده موجود اعمال شود، یک نسخه جدید از داده ایجاد می‌شود. نسخه قبلی حذف یا بازنویسی نمی‌شود و تا زمانی که لازم باشد در سیستم باقی می‌ماند. این ایده ساده باعث می‌شود که خواندن و نوشتن بتوانند بدون ایجاد مزاحمت جدی برای یکدیگر انجام شوند. در واقع، خواندن‌ها معمولاً روی نسخه‌های قدیمی‌تر و پایدار داده انجام می‌شوند، در حالی که نوشتن‌ها نسخه‌های جدید را تولید می‌کنند.برای درک بهتر، فرض کنید رکوردی با مقدار balance = 100 در یک جدول وجود دارد. یک تراکنش این مقدار را می‌خواند و همزمان تراکنش دیگری مقدار آن را به 150 تغییر داده و commit می‌کند. در معماری مبتنی بر MVCC، تراکنش اول همچنان مقدار 100 را مشاهده می‌کند، چون این مقدار در زمان شروع تراکنش برای او معتبر بوده است. در مقابل، تراکنش‌هایی که بعد از commit تراکنش دوم شروع می‌شوند، مقدار 150 را خواهند دید. در این سناریو، هیچ نیازی نیست تراکنش خواننده منتظر تراکنش نویسنده بماند.این رفتار معمولاً با اضافه کردن متادیتا به هر نسخه از رکورد پیاده‌سازی می‌شود. هر نسخه مشخص می‌کند توسط کدام تراکنش ایجاد شده و تا چه زمانی معتبر است. موتور پایگاه داده هنگام اجرای یک query بررسی می‌کند که کدام نسخه از هر رکورد با وضعیت فعلی تراکنش سازگار است و همان نسخه را در اختیار تراکنش قرار می‌دهد. به این ترتیب، هر تراکنش یک نمای سازگار از داده‌ها دریافت می‌کند، بدون اینکه درگیر تغییرات همزمان دیگر تراکنش‌ها شود.پایگاه داده هنگام اجرای یک query تصمیم می‌گیرد کدام نسخه از داده برای این تراکنش قابل مشاهده است. این تصمیم‌گیری معمولاً بر اساس زمان شروع تراکنش انجام می‌شود.مزیت اصلی MVCC در افزایش همزمانی و کاهش قفل‌گذاری‌های سنگین است. در بسیاری از workloadها، به‌ویژه سیستم‌هایی که تعداد خواندن‌ها بیشتر از نوشتن‌هاست، این رویکرد باعث بهبود محسوس کارایی می‌شود. خواندن‌ها تقریباً بدون بلاک شدن انجام می‌شوند و نوشتن‌ها نیز با حداقل تداخل پیش می‌روند. با این حال، این مکانیزم هزینه‌هایی هم دارد. نگهداری چند نسخه از داده‌ها فضای بیشتری مصرف می‌کند و پایگاه داده نیازمند فرآیندهایی برای پاک‌سازی نسخه‌هایی است که دیگر توسط هیچ تراکنشی قابل استفاده نیستند.در مجموع، MVCC یکی از پایه‌های اصلی طراحی پایگاه داده‌های مدرن به شمار می‌رود. این مکانیزم با ایجاد چند نسخه از داده‌ها، امکان اجرای همزمان و کارآمد تراکنش‌ها را فراهم می‌کند و تعادل مناسبی بین کارایی و سازگاری ایجاد می‌کند. اگرچه مفاهیمی مانند isolation levelها و snapshotها که در این مقاله مورد بررسی قرار داده ایم، نقش مهمی در درک کامل این رفتار دارند، اما حتی به‌صورت مستقل نیز MVCC تصویر روشنی از نحوه مدیریت همزمانی در دیتابیس‌های امروزی ارائه می‌دهد.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 03 May 2026 18:11:54 +0330</pubDate>
            </item>
                    <item>
                <title>ELK Stack</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/elk-stack-wr3z9dn4anem-wr3z9dn4anem</link>
                <description>داستانی درباره داده‌هایی که بالاخره قابل فهم می‌شوندسلام. امیدوارم حالتون خوب باشه. امروز در این مقاله میخوام در مورد استک ELK باهم صحبت کنیم و ببینیم که در سطح مقدماتی این به چه معنایی است. اگر بخوام بعد از چندین سال متمادی کار در دنیای نرم‌افزار، معماری سیستم و زیرساخت یک نکته را با اطمینان بگم، آن نکته این است:سیستمی که دیده نشود، دیر یا زود از کنترل خارج می‌شود.فرقی نمی‌کند یک وب‌سایت ساده داشته باشیم یا یک پلتفرم بزرگ با ده‌ها سرویس؛ وقتی ندانیم داخل سیستم دقیقاً چه اتفاقی می‌افتد، تصمیم‌هایمان حدسی می‌شود و خطاها معمولاً زمانی خودشان را نشان می‌دهند که کار از کار گذشته است.ELK دقیقاً برای حل همین مشکل به‌وجود آمده است. ELK در اصل نام یک Stack است، نه یک ابزار واحد. این Stack از سه بخش اصلی تشکیل شده: Elasticsearch، Logstash و Kibana. هر کدام از این‌ها به‌تنهایی ابزار قدرتمندی هستند، اما کنار هم معنی واقعی پیدا می‌کنند. این سه ابزار توسط شرکت Elastic توسعه داده شده‌اند و هدفشان این است که داده‌های خام، پراکنده و گاهی بی‌معنی را به چیزی تبدیل کنند که بتوان با آن فکر کرد، تحلیل کرد و تصمیم گرفت.قبل از ELK چه مشکلی داشتیم؟در بیشتر پروژه‌ها، لاگ‌ها اولین و دم‌دست‌ترین منبع اطلاعات هستند. برنامه‌ها لاگ می‌نویسند، سرورها لاگ می‌نویسند، دیتابیس‌ها لاگ می‌نویسند. در ابتدا همه‌چیز ساده است؛ یک فایل، چند خط متن، نهایتاً یک tail یا grep. اما با گذشت زمان حجم لاگ‌ها زیاد می‌شود، سرویس‌ها بیشتر می‌شوند و ناگهان می‌بینید برای پیدا کردن یک خطای ساده باید ده‌ها فایل را در چند سرور مختلف بگردید.مشکل فقط حجم نیست. مشکل این است که لاگ‌ها ساختار ندارند، قابل جستجوی درست نیستند و هیچ دید کلی‌ای از وضعیت سیستم به شما نمی‌دهند. شما نمی‌دانید این خطا چند بار تکرار شده، روی کدام نسخه، برای چه کاربری و از چه زمانی شروع شده است. اینجاست که نگاه سنتی به لاگ شکست می‌خورد و نیاز به یک رویکرد جدید شکل می‌گیرد.Elasticsearch؛ جایی که داده‌ها زنده می‌شوندElasticsearachElasticsearch را اگر بخواهیم خیلی ساده توضیح بدهیم، یک موتور جستجوی توزیع‌شده بسیار سریع و مبتنی بر Lucene برای جستجوی حجم زیاد داده‌هاست. اما این تعریف، حق مطلب را کامل ادا نمی‌کند. Elasticsearch در واقع قلب تپنده ELK است. جایی که همه داده‌ها در آن ذخیره می‌شوند و از حالت متن ساده خارج می‌شوند.Elasticsearch برخلاف دیتابیس‌های کلاسیک، بر پایه مفهوم «سند» ساخته شده است. داده‌ها معمولاً به شکل JSON ذخیره می‌شوند و قبل از ذخیره، ایندکس می‌شوند. این ایندکس شدن باعث می‌شود بتوانید روی حجم بسیار بزرگی از داده‌ها، جستجوهای پیچیده را در زمان بسیار کوتاه انجام دهید. اینجا دیگر فقط دنبال یک متن خاص نیستید؛ می‌توانید بپرسید چه خطاهایی در یک بازه زمانی مشخص رخ داده‌اند، روی کدام سرویس، با چه ویژگی‌هایی و چه الگویی دارند.از نگاه معماری، Elasticsearch جایی است که داده‌ها فقط نگهداری نمی‌شوند، بلکه آماده تحلیل هستند. وقتی سیستم بزرگ می‌شود، این تفاوت حیاتی است.Logstash؛ مترجم دنیای شلوغ داده‌هاLogstashاما یک واقعیت مهم وجود دارد: داده‌ها تمیز و مرتب به‌دنیا نمی‌آیند. لاگ‌ها از منابع مختلف می‌آیند، فرمت‌های متفاوت دارند و پر از نویز هستند. اینجاست که Logstash وارد بازی می‌شود.Logstash را می‌شود یک خط تولید یا یک لوله پردازش داده در نظر گرفت. داده‌ها از هر جایی که باشند، وارد Logstash می‌شوند. در این مسیر، Logstash آن‌ها را می‌خواند، تجزیه می‌کند، فیلدها را جدا می‌کند، اطلاعات اضافی اضافه می‌کند و در نهایت داده‌ای ساخت‌یافته تحویل می‌دهد. این داده آماده است که وارد Elasticsearch شود. این ابزار قابلیت دریافت داده از منابع متنوع (مانند سرورها، دیتابیس‌ها و فایل‌های لاگ) و تبدیل آن‌ها به فرمت‌های قابل استفاده در Elasticsearch را دارد.بدون Logstash هم می‌شود داده وارد Elasticsearch کرد، اما تجربه نشان داده هرچه سیستم جدی‌تر می‌شود، نبود یک لایه پردازش وسط راه دردسرساز خواهد شد. Logstash همان جایی است که داده‌های خام به داده‌های قابل استفاده تبدیل می‌شوند.Kibana؛ وقتی داده‌ها قابل دیدن می‌شوندKibanaذخیره و جستجو کافی نیست. مغز انسان با دیدن الگوها بهتر کار می‌کند. Kibana دقیقاً برای همین ساخته شده است. Kibana یک رابط گرافیکی است که مستقیماً به Elasticsearch متصل می‌شود و به شما اجازه می‌دهد داده‌ها را ببینید، نه فقط بخوانید.در Kibana می‌توانید جستجو کنید، فیلتر بزنید، نمودار بسازید و داشبوردهایی طراحی کنید که وضعیت سیستم را در یک نگاه نشان بدهند. اینجا دیگر فقط برنامه‌نویس مخاطب نیست. مدیر محصول، تیم پشتیبانی و تیم عملیات هم می‌توانند بفهمند سیستم چه حال و روزی دارد.Kibana داده‌ها را از حالت فنی و خام خارج می‌کند و به زبان تصمیم‌گیری ترجمه می‌کند.ELK به‌عنوان یک کل منسجمقدرت واقعی ELK وقتی مشخص می‌شود که این سه ابزار کنار هم قرار می‌گیرند. Logstash داده‌ها را جمع‌آوری و آماده می‌کند، Elasticsearch آن‌ها را ذخیره و قابل جستجو می‌کند و Kibana آن‌ها را به تصویر می‌کشد. این زنجیره باعث می‌شود سیستم شما «قابل مشاهده» شود؛ مفهومی که امروز به آن Observability می‌گویند.در چنین سیستمی، دیگر حدس نمی‌زنید چه اتفاقی افتاده است، بلکه می‌دانید. داده‌ها حرف می‌زنند، فقط باید ابزار درست برای شنیدنشان داشته باشید.ELK فقط برای لاگ نیستاگرچه ELK با لاگ شناخته شد، اما امروز کاربردهای آن بسیار فراتر رفته است. مانیتورینگ عملکرد سیستم، تحلیل رفتار کاربران، بررسی مسائل امنیتی و حتی جستجوی متنی در اپلیکیشن‌ها، همه جاهایی هستند که ELK حضور پررنگ دارد. به همین دلیل هم امروزه بیشتر از اصطلاح Elastic Stack استفاده می‌شود تا نشان دهد این اکوسیستم بزرگ‌تر از سه ابزار اولیه است.جمع‌بندیELK ابزاری نیست که روز اول پروژه به آن فکر کنیم. معمولاً وقتی سیستم بزرگ می‌شود و درد شروع می‌شود، سراغش می‌رویم. اما تجربه نشان داده هرچه زودتر به مسئله مشاهده‌پذیری فکر کنیم، هزینه کمتری در آینده می‌دهیم. ELK کمک می‌کند سیستم ما از یک جعبه سیاه به یک موجود قابل فهم تبدیل شود؛ و این، در دنیای نرم‌افزار، یک مزیت حیاتی محسوب میگردد.قبل از اینکه یادم بره میخوام بگم که الستیک یک ابزار دیگه بنام Beats داره که در اکوسیستم الستیک خیلی کمک کننده هست. در مقالات بعدی به بررسی این ابزار هم خواهیم پرداخت و سپس نحوه راه اندازی و بهره برداری از اون در یک سرور واقعی رو بررسی میکنیم.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 03 May 2026 18:11:42 +0330</pubDate>
            </item>
                    <item>
                <title>Isolation Level در SQL</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/isolation-level-%D8%AF%D8%B1-sql-jneeec4vaa0x</link>
                <description>مقدمهبا گسترش سامانه‌های نرم‌افزاری مبتنی بر پایگاه داده و افزایش همزمانی در دسترسی کاربران و سرویس‌ها به داده‌ها، مسئله‌ی مدیریت صحیح همزمانی به یکی از چالش‌های بنیادین در طراحی سیستم‌های اطلاعاتی تبدیل شده است. در چنین محیط‌هایی، عملیات مختلفی به‌طور همزمان اقدام به خواندن و تغییر داده‌های مشترک می‌کنند و در صورت نبود سازوکارهای کنترلی مناسب، احتمال بروز ناسازگاری، نتایج غیرقابل پیش‌بینی و نقض یکپارچگی داده‌ها به‌طور قابل توجهی افزایش می‌یابد.برای پاسخ به این چالش، پایگاه‌های داده رابطه‌ای از مفهوم تراکنش (Transaction) استفاده می‌کنند. تراکنش مجموعه‌ای از عملیات پایگاه داده است که باید به‌صورت یک واحد منطقی و غیرقابل تجزیه اجرا شود و ویژگی‌های شناخته‌شده‌ی ACID—شامل اتمی بودن (Atomicity)، سازگاری (Consistency)، جداسازی (Isolation) و ماندگاری (Durability)—را رعایت کند. در میان این ویژگی‌ها، «جداسازی» نقشی کلیدی در تعیین نحوه‌ی تعامل تراکنش‌های همزمان با یکدیگر ایفا می‌کند.Isolation Level یا سطح جداسازی، مشخص می‌کند که یک تراکنش تا چه حد از تغییرات ایجادشده توسط سایر تراکنش‌های همزمان آگاه باشد و چه نوع ناهنجاری‌هایی در خواندن داده‌ها مجاز یا غیرمجاز تلقی شوند. استاندارد SQL با هدف ایجاد تعادل میان صحت داده‌ها و کارایی سیستم، چهار سطح اصلی برای جداسازی تراکنش‌ها تعریف کرده است. هر یک از این سطوح، درجه‌ای متفاوت از محدودیت را بر دسترسی همزمان به داده‌ها اعمال می‌کند و در نتیجه، رفتار سیستم را در شرایط بار کاری مختلف تغییر می‌دهد.اهمیت Isolation Level تنها به مباحث نظری محدود نمی‌شود، بلکه تأثیر آن به‌طور مستقیم در طراحی سیستم‌های واقعی، به‌ویژه سامانه‌های مالی، بانکی، تحلیلی و توزیع‌شده قابل مشاهده است. انتخاب نادرست سطح جداسازی می‌تواند منجر به بروز خطاهایی شود که شناسایی و بازتولید آن‌ها دشوار است، در حالی که انتخاب بیش از حد محافظه‌کارانه نیز ممکن است کارایی و مقیاس‌پذیری سیستم را به‌شدت کاهش دهد. از این رو، درک دقیق سطوح مختلف Isolation Level و پیامدهای عملی هر یک، برای طراحان و توسعه‌دهندگان سیستم‌های مبتنی بر پایگاه داده امری ضروری محسوب می‌شود.در این مقاله سعی میکنم با رویکردی تحلیلی، سطوح مختلف Isolation Level در SQL را معرفی کرده و با ارائه‌ی مثال‌های عملی و کوئری‌های واقعی، تأثیر هر سطح را بر رفتار تراکنش‌های همزمان بررسی کنیم. هدف اصلی، ایجاد درکی عمیق و کاربردی از این مفهوم به‌منظور اتخاذ تصمیم‌های آگاهانه در طراحی و پیاده‌سازی سیستم‌های پایگاه داده است.سطوح Isolation Level در SQL استاندارد SQL برای مدیریت همزمانی تراکنش‌ها، چهار سطح اصلی Isolation Level را تعریف می‌کند که هر یک میزان مشخصی از جداسازی را میان تراکنش‌های همزمان اعمال می‌کنند. هدف از این سطوح، ایجاد تعادل میان صحت داده‌ها و کارایی سیستم است؛ به این معنا که هرچه محدودیت‌ها سخت‌گیرانه‌تر باشند، احتمال بروز ناهنجاری‌های همزمانی کاهش می‌یابد، اما در مقابل، سربار پردازشی و کاهش همزمانی افزایش پیدا می‌کند. علاوه بر این سطوح استاندارد، برخی سامانه‌های مدیریت پایگاه داده مفهومی به نام Snapshot Isolation را نیز ارائه می‌دهند که اگرچه جزو سطوح رسمی استاندارد SQL نیست، اما در عمل نقش مهمی در معماری سیستم‌های مدرن ایفا می‌کند.سطح Read Uncommittedپایین‌ترین سطح جداسازی، Read Uncommitted است. در این سطح، یک تراکنش می‌تواند تغییرات اعمال‌شده توسط سایر تراکنش‌ها را حتی پیش از commit شدن مشاهده کند. این رفتار منجر به پدیده Dirty Read می‌شود؛ حالتی که در آن داده‌ی خوانده‌شده ممکن است در ادامه rollback شود و هرگز به وضعیت پایدار نرسد. Read Uncommitted کمترین سطح تضمین سازگاری را فراهم می‌کند و معمولاً تنها در سناریوهایی با حساسیت پایین و تمرکز بر بیشینه‌سازی کارایی مورد استفاده قرار می‌گیرد.ابتدا Transaction A را در نظر بگیرید:SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;

UPDATE accounts
SET balance = 2000
WHERE id = 1;در این لحظه، مقدار balance به 2000 تغییر کرده اما هنوز commit نشده است. حال Transaction B به‌صورت همزمان اجرا می‌شود:SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;

SELECT balance
FROM accounts
WHERE id = 1;خروجی این کوئری مقدار 2000 خواهد بود، در حالی که این مقدار هنوز نهایی نشده است. حال اگر Transaction A دچار خطا شود و rollback گردد:ROLLBACK;داده به مقدار قبلی یعنی 1000 بازمی‌گردد، اما Transaction B عددی را مشاهده کرده که در نهایت هرگز وجود نداشته است. این مثال به‌صورت عملی نشان می‌دهد چرا Dirty Read می‌تواند منجر به تحلیل‌های نادرست شود.سطح Read Committedسطح Read Committed تضمین می‌کند که هر تراکنش فقط داده‌هایی را مشاهده کند که commit شده‌اند. در این سطح، Dirty Read حذف می‌شود و هر خواندن داده مبتنی بر وضعیت پایدار پایگاه داده است. با این حال، Read Committed همچنان اجازه‌ی بروز Non-Repeatable Read را می‌دهد؛ به این معنا که یک تراکنش ممکن است در خواندن‌های مکرر از یک ردیف مشخص، مقادیر متفاوتی دریافت کند. این رفتار نتیجه‌ی commit شدن تغییرات توسط تراکنش‌های دیگر در فاصله‌ی بین دو عملیات خواندن است.Transaction A را به شکل زیر در نظر بگیرید:SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;

SELECT balance
FROM accounts
WHERE id = 1;خروجی در این مرحله مقدار 1000 است. حال Transaction B اجرا می‌شود:SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
BEGIN TRANSACTION;

UPDATE accounts
SET balance = 1500
WHERE id = 1;

COMMIT;پس از commit شدن Transaction B، Transaction A دوباره همان داده را می‌خواند:SELECT balance
FROM accounts
WHERE id = 1;این بار خروجی 1500 خواهد بود. در نتیجه، یک تراکنش واحد در دو بار خواندن یک ردیف، دو مقدار متفاوت دریافت کرده است. این دقیقاً مصداق Non-Repeatable Read است و می‌تواند در محاسبات تجمعی یا گزارش‌گیری مشکل‌ساز شود.سطح Repeatable Readدر سطح Repeatable Read، پایگاه داده تضمین می‌کند که ردیف‌هایی که یک تراکنش آن‌ها را خوانده است، تا پایان عمر آن تراکنش تغییر نخواهند کرد. به این ترتیب، Non-Repeatable Read حذف می‌شود و ثبات داده‌های خوانده‌شده افزایش می‌یابد. با وجود این، Repeatable Read لزوماً مانع بروز Phantom Read نمی‌شود. در چنین شرایطی، ممکن است یک تراکنش در اجرای مجدد یک کوئری شرطی، ردیف‌های جدیدی را مشاهده کند که در اجرای اولیه وجود نداشته‌اند.Transaction A به‌صورت زیر آغاز می‌شود:SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;

SELECT balance
FROM accounts
WHERE id = 1;خروجی مقدار 1500 است. حال Transaction B تلاش می‌کند مقدار را تغییر دهد:SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;

UPDATE accounts
SET balance = 3000
WHERE id = 1;

COMMIT;Transaction A دوباره داده را می‌خواند:SELECT balance
FROM accounts
WHERE id = 1;خروجی همچنان 1500 خواهد بود و تغییر انجام‌شده توسط Transaction B تا پایان Transaction A قابل مشاهده نیست. این رفتار نشان می‌دهد که Non-Repeatable Read در این سطح حذف شده است.اما حال سناریوی Phantom Read را بررسی می‌کنیم. فرض کنید Transaction A کوئری زیر را اجرا می‌کند:SELECT *
FROM accounts
WHERE balance &gt; 1000;در همین زمان، Transaction B یک ردیف جدید درج می‌کند:INSERT INTO accounts (id, balance)
VALUES (2, 5000);

COMMIT;اگر Transaction A مجدداً همان کوئری را اجرا کند، ممکن است ردیف جدید را مشاهده کند. این ردیف در اجرای اول وجود نداشته و اکنون ظاهر شده است؛ این پدیده Phantom Read نام دارد.سطح Serializableبالاترین سطح استاندارد جداسازی، Serializable است. در این سطح، پایگاه داده تضمین می‌کند که نتیجه‌ی اجرای تراکنش‌های همزمان معادل اجرای کاملاً ترتیبی آن‌ها باشد. در نتیجه، تمامی ناهنجاری‌های شناخته‌شده از جمله Dirty Read، Non-Repeatable Read و Phantom Read حذف می‌شوند. این سطح بالاترین میزان سازگاری را فراهم می‌کند، اما هزینه‌ی آن کاهش همزمانی، افزایش قفل‌گذاری و احتمال افت محسوس کارایی سیستم است. به همین دلیل، Serializable معمولاً برای عملیات‌های حیاتی و بسیار حساس مورد استفاده قرار می‌گیرد.Transaction A به شکل زیر شروع می‌شود:SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;

SELECT *
FROM accounts
WHERE balance &gt; 1000;در این حالت، پایگاه داده معمولاً قفل‌هایی اعمال می‌کند که مانع از درج یا تغییر داده‌های مؤثر بر این نتیجه می‌شود. اگر Transaction B تلاش کند رکورد جدیدی درج کند:INSERT INTO accounts (id, balance)
VALUES (3, 7000);این دستور یا تا پایان Transaction A بلاک می‌شود یا با خطا مواجه خواهد شد (بسته به DBMS). در نتیجه، نه Dirty Read، نه Non-Repeatable Read و نه Phantom Read رخ نخواهد داد. این رفتار بالاترین سطح سازگاری داده را تضمین می‌کند، هرچند به قیمت کاهش همزمانی.موضوع Snapshot Isolationدر کنار این سطوح، Snapshot Isolation رویکردی متفاوت برای مدیریت همزمانی ارائه می‌دهد. در این مدل، هر تراکنش هنگام شروع، یک «تصویر ثابت» یا Snapshot از وضعیت پایگاه داده دریافت می‌کند و تمامی عملیات خواندن خود را بر اساس همان تصویر انجام می‌دهد. به این ترتیب، داده‌هایی که یک تراکنش می‌خواند در طول عمر آن ثابت باقی می‌مانند، بدون آنکه نیاز به قفل‌گذاری گسترده برای عملیات خواندن وجود داشته باشد. Snapshot Isolation معمولاً مبتنی بر مکانیزم کنترل همزمانی چندنسخه‌ای (MVCC) است و باعث می‌شود خواندن‌ها مسدودکننده‌ی نوشتن‌ها نباشند و بالعکس. در مورد مکانیزم کنترل همزمانی چندنسخه‌ای (MVCC) بیشتر صحبت خواهیم کرد. Snapshot Isolation از بروز Dirty Read و Non-Repeatable Read جلوگیری می‌کند و در عمل Phantom Read را نیز در بسیاری از سناریوها حذف می‌نماید. با این حال، این سطح به‌طور کامل معادل Serializable نیست و ممکن است ناهنجاری‌هایی مانند Write Skew در آن رخ دهد؛ حالتی که در آن دو تراکنش بر اساس یک Snapshot مشترک تصمیم‌گیری می‌کنند و در نهایت، نتیجه‌ای ناسازگار با منطق کسب‌وکار ایجاد می‌شود. به همین دلیل، Snapshot Isolation را می‌توان سطحی میانی میان Repeatable Read و Serializable دانست که با هدف افزایش کارایی و کاهش قفل‌گذاری طراحی شده است.Isolation Levelدر مجموع، Isolation Level‌ها و Snapshot Isolation چارچوب‌های متفاوتی برای مدیریت همزمانی در پایگاه‌های داده فراهم می‌کنند. انتخاب میان این گزینه‌ها باید بر اساس نیازمندی‌های سازگاری، الگوی دسترسی به داده و الزامات کارایی سیستم انجام شود. درک دقیق تفاوت‌های مفهومی و عملی این سطوح، پیش‌نیاز طراحی سیستم‌های پایگاه داده‌ی قابل اعتماد و مقیاس‌پذیر است.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sat, 28 Feb 2026 10:29:34 +0330</pubDate>
            </item>
                    <item>
                <title>OKR و KPI؛ دو ابزار، دو نگاه متفاوت به مدیریت عملکرد</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/okr-%D9%88-kpi-%D8%AF%D9%88-%D8%A7%D8%A8%D8%B2%D8%A7%D8%B1-%D8%AF%D9%88-%D9%86%DA%AF%D8%A7%D9%87-%D9%85%D8%AA%D9%81%D8%A7%D9%88%D8%AA-%D8%A8%D9%87-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%B9%D9%85%D9%84%DA%A9%D8%B1%D8%AF-jafh7no8ffpd</link>
                <description>سلام. در این مقاله به بررسی دو موضوع و ابزار مهم KPI و OKR خواهیم پرداخت و روابط این دو رو باهم دیگه بررسی میکنیم. در فایل صوتی، مثال های مصداقی برای شرکت های نرم افزاری رو آوردم که بهتر بتونیم موضوع رو درک کنیم. در سال‌های اخیر، مفاهیمی مثل OKR و KPI بیش از هر زمان دیگری وارد ادبیات مدیریتی، استارتاپی و حتی تیم‌های کوچک شده‌اند. تقریباً همه اسمشان را شنیده‌اند، اما در عمل هنوز ابهام‌های زیادی درباره‌ی تفاوت، کاربرد و حتی ترتیب استفاده از آن‌ها وجود دارد. بعضی تیم‌ها KPI دارند اما نمی‌دانند چرا اندازه‌گیری می‌کنند، بعضی دیگر OKR تعریف می‌کنند اما نمی‌دانند قرار است چه تغییری ایجاد شود. این مقاله تلاشی است برای روشن کردن مفاهیم پایه‌ای OKR و KPI، بدون پیچیدگی‌های آکادمیک، اما با دقت مفهومی.سنجش عملکردKPI چیست و چرا به وجود آمد؟KPI یا Key Performance Indicator به‌طور ساده یعنی «شاخص کلیدی عملکرد». KPI به ما می‌گوید که وضعیت فعلی ما چگونه است و آیا عملکردمان در یک مسیر مشخص، قابل قبول هست یا نه. KPIها معمولاً عددی هستند و با اندازه‌گیری مداوم، به ما تصویر نسبتاً دقیقی از سلامت یک فرایند، تیم یا کسب‌وکار می‌دهند.ریشه‌ی KPI بیشتر در مدیریت کلاسیک و کنترل عملکرد است. زمانی که سازمان‌ها بزرگ‌تر شدند، مدیران دیگر نمی‌توانستند صرفاً با مشاهده‌ی مستقیم تصمیم بگیرند. آن‌ها نیاز داشتند بدانند فروش چقدر است، هزینه‌ها چطور تغییر کرده، نرخ خطا چقدر شده و بهره‌وری کارکنان در چه وضعیتی است. KPIها دقیقاً برای پاسخ به همین نیاز به وجود آمدند: دیدن واقعیت عملکرد، آن هم به زبان عدد.ویژگی‌های اصلی KPIKPIها معمولاً پایدار هستند و به‌راحتی تغییر نمی‌کنند. اگر KPI «نرخ تبدیل کاربران» یا «درآمد ماهانه» باشد، این شاخص‌ها قرار نیست هر هفته عوض شوند. KPI بیشتر شبیه یک دماسنج است؛ قرار نیست تب را درمان کند، فقط نشان می‌دهد بدن در چه وضعیتی است.نکته‌ی مهم این است که KPI الزاماً انگیزه‌بخش نیست. دانستن اینکه نرخ ریزش مشتریان ۱۲٪ است، لزوماً به تیم نمی‌گوید چه تغییری باید ایجاد کند. KPI بیشتر ابزار «پایش» است تا «تحول».OKR چیست و چه مسئله‌ای را حل می‌کند؟OKR مخفف Objectives and Key Results است. برخلاف KPI که از دل نیاز به کنترل بیرون آمده، OKR از دل نیاز به جهت‌دهی و تمرکز متولد شده است. OKR تلاش می‌کند به این سؤال پاسخ دهد: «می‌خواهیم به کجا برسیم و از کجا بفهمیم به آن رسیده‌ایم؟»OKR از دو بخش تشکیل می‌شود. Objective یک هدف کیفی، الهام‌بخش و جهت‌دهنده است. چیزی که قرار است وضعیت آینده را بهتر از امروز کند. Key Resultها معیارهای سنجش رسیدن به آن هدف هستند؛ اما نه هر معیاری، بلکه معیارهایی که نشان‌دهنده‌ی تغییر واقعی باشند.تفاوت نگاه OKR با KPIیکی از تفاوت‌های اساسی OKR و KPI در نگاه آن‌ها به «تغییر» است. KPI معمولاً وضعیت موجود را اندازه‌گیری می‌کند، اما OKR برای تغییر وضعیت موجود طراحی شده است. وقتی تیمی OKR تعریف می‌کند، در واقع می‌پذیرد که وضعیت فعلی کافی نیست و باید بهتر شود.OKRها معمولاً بازه‌ی زمانی مشخص دارند (مثلاً فصلی) و انتظار نمی‌رود همه‌ی آن‌ها ۱۰۰٪ محقق شوند. حتی در فلسفه‌ی OKR، رسیدن به حدود ۶۰ تا ۷۰ درصد یک OKR نشانه‌ی خوب طراحی شدن آن است. این موضوع کاملاً برخلاف KPI است که معمولاً باید به‌طور کامل محقق شود.Key Result با KPI چه فرقی دارد؟در نگاه اول، Key Result خیلی شبیه KPI به نظر می‌رسد، چون هر دو عددی هستند. اما تفاوت در «نقش» آن‌هاست. KPI یک شاخص پایدار برای پایش عملکرد است، اما Key Result یک معیار موقتی برای سنجش موفقیت یک هدف مشخص است.ممکن است یک KPI سال‌ها ثابت بماند، اما Key Resultها با تغییر Objective عوض می‌شوند. KPI به ما می‌گوید «اوضاع چطور است»، اما Key Result به ما می‌گوید «آیا به هدفمان نزدیک شده‌ایم یا نه».آیا OKR جایگزین KPI است؟یکی از رایج‌ترین سوءتفاهم‌ها این است که OKR آمده تا KPI را حذف کند. در واقع، این دو ابزار نه رقیب هم هستند و نه جایگزین یکدیگر. KPI بدون OKR ممکن است به اندازه‌گیری بی‌هدف منجر شود، و OKR بدون KPI ممکن است از واقعیت فاصله بگیرد.در عمل، KPIها می‌توانند به‌عنوان ورودی برای طراحی OKR استفاده شوند. یعنی ابتدا بفهمیم وضعیت فعلی چگونه است (با KPI) و بعد تصمیم بگیریم چه چیزی باید تغییر کند (با OKR). همچنین بعضی KPIها می‌توانند در طول اجرای OKR به‌عنوان شاخص‌های سلامت کسب‌وکار پایش شوند.اشتباهات رایج در استفاده از OKR و KPIیکی از اشتباهات رایج این است که سازمان‌ها OKR را به KPI تبدیل می‌کنند. یعنی به‌جای هدف‌گذاری تحول‌محور، فقط اعداد آشنا را در قالب جدید می‌نویسند. اشتباه دیگر این است که KPIهای زیادی تعریف می‌شود، بدون اینکه کسی واقعاً از آن‌ها برای تصمیم‌گیری استفاده کند.همچنین، استفاده از OKR به‌عنوان ابزار ارزیابی عملکرد فردی، یکی از خطرناک‌ترین انحراف‌هاست. OKR برای یادگیری و هم‌راستاسازی طراحی شده، نه برای تنبیه و پاداش مستقیم.جمع‌بندیKPI و OKR هر دو ابزارهای مهمی هستند، اما برای دو هدف متفاوت. KPI به ما کمک می‌کند بفهمیم کجا ایستاده‌ایم، OKR به ما کمک می‌کند تصمیم بگیریم به کجا برویم. ترکیب درست این دو، می‌تواند هم شفافیت ایجاد کند و هم حرکت.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Tue, 24 Feb 2026 12:15:24 +0330</pubDate>
            </item>
                    <item>
                <title>کارکنان و نیرو های ستادی و صف</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%DA%A9%D8%A7%D8%B1%DA%A9%D9%86%D8%A7%D9%86-%D9%88-%D9%86%DB%8C%D8%B1%D9%88-%D9%87%D8%A7%DB%8C-%D8%B3%D8%AA%D8%A7%D8%AF%DB%8C-%D9%88-%D8%B5%D9%81-eqrazyx2czhu</link>
                <description>سلام. دوستان امروز میخوام در مورد بحث مدیریت و کارکنان نیرو های ستادی و صف در سازمان ها یک گفتگویی داشته باشیم. بیشتر مد نظرم روی سازمان های نرم افزاری خواهد بود.در ادبیات مدیریت سازمان، تفکیک میان «نیروهای صف» و «نیروهای ستادی» یکی از مفاهیم بنیادینی است که اگر به‌درستی فهم نشود، به‌ویژه در سازمان‌های نرم‌افزاری، می‌تواند به سوء‌برداشت‌های مدیریتی، تنش‌های درون‌سازمانی و تصمیم‌گیری‌های نادرست منجر شود. این مفاهیم در ظاهر ساده‌اند، اما در عمل لایه‌های عمیق‌تری دارند که شناخت آن‌ها برای مدیران، خصوصاً مدیرانی که از مسیر فنی به مدیریت رسیده‌اند، ضروری است.نیروهای صف به‌طور کلاسیک به آن دسته از افراد و تیم‌ها گفته می‌شود که مستقیماً در تحقق مأموریت اصلی سازمان نقش دارند. اگر سازمان را یک زنجیره ارزش در نظر بگیریم، نیروهای صف همان حلقه‌هایی هستند که خروجی نهایی سازمان بدون آن‌ها معنا ندارد. در یک سازمان نرم‌افزاری، توسعه‌دهندگان، تیم‌های محصول، تست، و گاهی حتی پشتیبانی فنی، معمولاً در این دسته قرار می‌گیرند؛ چرا که محصول نرم‌افزاری، که دلیل وجودی سازمان است، مستقیماً توسط آن‌ها خلق، تکمیل و تحویل می‌شود. قدرت نیروهای صف نه از جایگاه سازمانی، بلکه از نزدیکی آن‌ها به «کار واقعی» ناشی می‌شود.در مقابل، نیروهای ستادی نقش پشتیبان، تسهیل‌گر و تنظیم‌کننده دارند. این نیروها مستقیماً محصول نهایی را تولید نمی‌کنند، اما شرایطی را فراهم می‌کنند که نیروهای صف بتوانند مؤثرتر، پایدارتر و با ریسک کمتر فعالیت کنند. واحد منابع انسانی، مالی، حقوقی، برنامه‌ریزی، تحلیل فرایندها و حتی در بسیاری از سازمان‌های نرم‌افزاری، تیم‌های PMO یا DevOps در نقش ستادی قرار می‌گیرند. نقش ستاد نه انجام کار اصلی، بلکه افزایش کیفیت تصمیم‌گیری، هماهنگی و کنترل هوشمندانه است.کارکنان و نیرو های ستادی و صفنکته‌ای که اغلب در سازمان‌های نرم‌افزاری نادیده گرفته می‌شود، این است که ستاد و صف نه در تقابل، بلکه در یک رابطه‌ی وابستگی متقابل قرار دارند. مشکل زمانی آغاز می‌شود که نیروهای ستادی تصور کنند «مالک تصمیم» هستند و نیروهای صف را صرفاً مجری ببینند، یا برعکس، نیروهای صف ستاد را سربار، کندکننده یا جدا از واقعیت پروژه تلقی کنند. این شکاف معمولاً ریشه در نبود تعریف شفاف از نقش‌ها و مرز اختیارات دارد، نه در ضعف ذاتی یکی از این دو.در سازمان‌های نرم‌افزاری، این چالش به شکل خاص‌تری بروز می‌کند. بسیاری از مدیران ارشد سابقه فنی دارند و ناخودآگاه ذهنیت صف‌محور دارند؛ یعنی ارزش را فقط در کدنویسی، معماری و تحویل فیچر می‌بینند. در چنین فضایی، نقش‌های ستادی مانند منابع انسانی، برنامه‌ریزی ظرفیت، یا حتی مستندسازی، کم‌اهمیت جلوه داده می‌شوند. نتیجه این نگاه، فرسودگی نیروهای صف، تصمیم‌گیری‌های کوتاه‌مدت و ناپایداری سازمان در مقیاس‌پذیری است.از سوی دیگر، ستاد در سازمان نرم‌افزاری اگر از زبان و منطق صف فاصله بگیرد، به‌سرعت اعتبار خود را از دست می‌دهد. ستادی که بدون درک واقعیت اسپرینت‌ها، بدهی فنی، فشار ددلاین‌ها و پیچیدگی توسعه نرم‌افزار، سیاست‌گذاری می‌کند، ناخواسته به مانع تبدیل می‌شود. بنابراین بلوغ سازمانی زمانی رخ می‌دهد که ستاد، عمیقاً کار صف را بفهمد و صف، ارزش نگاه سیستمی ستاد را درک کند.برای مدیران، درک این تمایز به معنای انتخاب طرف نیست، بلکه به معنای طراحی درست ساختار و روابط است. مدیر بالغ می‌داند که صف بدون ستاد، سریع اما شکننده است، و ستاد بدون صف، منظم اما بی‌اثر. هنر مدیریت، ایجاد تعادلی پویا میان این دو است؛ تعادلی که در آن ستاد قدرت خود را از تخصص و تحلیل می‌گیرد، نه از دستور، و صف نقش خود را نه صرفاً اجرا، بلکه مشارکت آگاهانه در تصمیم‌سازی می‌داند.در نهایت، سازمان نرم‌افزاری موفق سازمانی است که نیروهای صف را قهرمانان تولید ارزش بداند و نیروهای ستادی را معماران پایداری. هرگاه یکی جای دیگری بنشیند یا حذف شود، سازمان یا به هرج‌ومرج می‌رسد یا به بوروکراسی. فهم دقیق نیروهای صف و ستاد، نه یک بحث تئوریک، بلکه پیش‌نیاز رشد سالم و حرفه‌ای سازمان است.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Mon, 23 Feb 2026 16:07:09 +0330</pubDate>
            </item>
                    <item>
                <title>عارضه‌یابی سازمانی؛</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%B9%D8%A7%D8%B1%D8%B6%D9%87-%DB%8C%D8%A7%D8%A8%DB%8C-%D8%B3%D8%A7%D8%B2%D9%85%D8%A7%D9%86%DB%8C-sunglvquvcc5</link>
                <description>از مفهوم تا واقعیت در شرکت‌های نرم‌افزاریسلام. امروز میخوام در مورد عارضه یابی سازمانی کمی صحبت کنم و یک مقدمه کوتاهی رو در این مقاله بهش بپردازم و بیشترِ تمرکزم روی این موضوع، در شرکت های مهندسی نرم افزاری باشد.عارضه یابی سازمانی و جلوگیری از فروپاشی هادر طول حدود چندین سال فعالیت مدیریتی‌ام در سازمان‌های مختلف، بارها با این تصور مواجه شده‌ام که مشکل اصلی یک سازمان، کمبود تخصص، نیروی انسانی یا منابع مالی است. اما تجربه به من نشان داده که در بسیاری از موارد، مسئله نه کمبود است و نه ناتوانی؛ بلکه نشناختن درست مسئله‌ی واقعی است. سازمان‌ها اغلب درد دارند، اما محل درد را اشتباه تشخیص می‌دهند. اینجاست که عارضه‌یابی سازمانی معنا پیدا می‌کند.عارضه‌یابی سازمانی، پیش از آن‌که یک ابزار یا مدل باشد، یک نوع نگاه است. نگاهی که تلاش می‌کند قبل از ارائه‌ی راه‌حل، مسئله را در بستر واقعی خود ببیند. بسیاری از مشکلاتی که ما در سازمان‌ها می‌بینیم، در واقع «عارضه» هستند؛ نشانه‌هایی بیرونی از اختلالات عمیق‌تر. تأخیر در تحویل پروژه، نارضایتی مشتری، افت کیفیت محصول یا حتی فرسودگی تیم، معمولاً خودِ مشکل نیستند، بلکه پیامد تصمیم‌ها، ساختارها و رفتارهایی هستند که شاید سال‌ها قبل شکل گرفته‌اند.یکی از اشتباهات رایجی که در سازمان‌ها دیده‌ام، عجله برای درمان است. مدیران، به‌محض دیدن نشانه‌ها، سراغ نسخه می‌روند: تغییر فرایند، اضافه‌کردن نیرو، خرید ابزار جدید یا حتی جابه‌جایی افراد. اما وقتی تشخیص درست نباشد، درمان نه‌تنها مؤثر نیست، بلکه گاهی وضعیت را پیچیده‌تر می‌کند. عارضه‌یابی، در اصل تمرینی برای «صبر مدیریتی» است؛ ایستادن، دیدن و فهمیدن، قبل از اقدام.در شرکت‌های نرم‌افزاری، عارضه‌یابی اهمیت دوچندانی پیدا می‌کند. ماهیت ناملموس محصول، وابستگی شدید به نیروی انسانی و سرعت بالای تغییرات تکنولوژیک، باعث می‌شود مشکلات خیلی زود پنهان شوند یا به‌اشتباه تفسیر شوند. در بسیاری از تیم‌های نرم‌افزاری که با آن‌ها کار کرده‌ام، تا زمانی که پروژه‌ها به‌زور جلو می‌روند، کسی متوجه عمق مسائل نمی‌شود. اما به‌محض اینکه رشد متوقف می‌شود یا خروج نیروها آغاز می‌شود، تازه مشخص می‌شود که عارضه‌ها مدت‌ها قبل شکل گرفته بودند.در شرکت‌های نرم‌افزاری کوچک، عارضه‌یابی اغلب به‌طور مستقیم با خودِ مدیر یا مؤسس گره خورده است. این سازمان‌ها معمولاً وابستگی شدیدی به چند نفر کلیدی دارند و تصمیم‌ها به‌صورت متمرکز گرفته می‌شود. در چنین فضایی، مرز نقش‌ها شفاف نیست و فشار برای تحویل سریع، به‌تدریج تیم را فرسوده می‌کند. تجربه‌ی شخصی من نشان می‌دهد که بسیاری از مشکلات این شرکت‌ها، نه فنی هستند و نه منابعی؛ بلکه ریشه در سبک تصمیم‌گیری و اولویت‌گذاری مدیر دارند. در یکی از تیم‌هایی که با آن کار می‌کردم، مسئله‌ی اصلی تأخیرهای مداوم بود، اما بعد از بررسی مشخص شد که مشکل واقعی، ناتوانی مسئولین مربوطه در مدیریت انتظارات و «نه گفتن» به درخواست‌های غیرواقعی است.با بزرگ‌تر شدن سازمان و ورود به مقیاس متوسط، جنس عارضه‌ها تغییر می‌کند. در این مرحله، سازمان از حالت صمیمی و غیررسمی عبور کرده، اما هنوز به بلوغ ساختاری نرسیده است. ناهماهنگی بین تیم‌ها، فاصله‌ی میان مدیریت و اجرا، و شکل‌گیری مدیران میانی بدون آمادگی لازم، از نشانه‌های رایج این مرحله است. در چنین سازمان‌هایی، مدیران اغلب تصور می‌کنند مشکل از عملکرد تیم‌هاست، در حالی که بررسی عمیق‌تر نشان می‌دهد پیام‌های متناقض مدیریتی، اولویت‌های نامشخص و فرایندهای نیمه‌کاره، عامل اصلی اختلال هستند. عارضه‌یابی در این سطح، بدون گفت‌وگوی صادقانه با تیم‌ها و بدون پذیرش خطا از سوی مدیریت ارشد، عملاً بی‌نتیجه خواهد بود.در سازمان‌های نرم‌افزاری بزرگ، عارضه‌ها معمولاً کمتر دیده می‌شوند، اما اثر مخرب‌تری دارند. بروکراسی، کندی تصمیم‌گیری، از بین رفتن حس مالکیت و فاصله‌ی بین استراتژی و اجرا، به‌تدریج انرژی سازمان را تحلیل می‌برد. در این مقیاس، اگر عارضه‌یابی صرفاً از بالا انجام شود، معمولاً به نتایج سطحی می‌رسد. تجربه‌ی من نشان داده که واقعیت سازمان‌های بزرگ، در لایه‌های عملیاتی جریان دارد، نه در گزارش‌ها و اسلایدها. در یکی از این سازمان‌ها، تصور مدیران این بود که تیم‌ها چابک نیستند، اما عارضه‌یابی نشان داد که سیستم ارزیابی عملکرد، هرگونه ریسک‌پذیری را تنبیه می‌کند و عملاً مانع نوآوری شده است.اگر بخواهم جمع‌بندی شخصی خودم را از این سال‌ها بگویم، عارضه‌یابی سازمانی بدون صداقت، به یک نمایش مدیریتی تبدیل می‌شود. سازمان‌ها معمولاً دقیقاً در همان نقطه‌ای آسیب‌پذیر هستند که دوست ندارند به آن نگاه کنند. هیچ فریم‌ورک، ابزار یا مدلی جای گفت‌وگوی واقعی با آدم‌ها را نمی‌گیرد و عارضه‌یابی درست، اغلب ناراحتی کوتاه‌مدت ایجاد می‌کند، اما سلامت بلندمدت سازمان را تضمین می‌کند.در نهایت، عارضه‌یابی سازمانی نشانه‌ی بحران نیست؛ نشانه‌ی بلوغ است. سازمان‌هایی که حاضرند خودشان را همان‌طور که هستند ببینند، نه آن‌طور که دوست دارند باشند، شانس بیشتری برای رشد پایدار دارند. در صنعت نرم‌افزار، که همه‌چیز به انسان و تصمیم‌های او گره خورده، این شجاعت دیدن، شاید مهم‌ترین مزیت رقابتی باشد.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Mon, 23 Feb 2026 15:48:59 +0330</pubDate>
            </item>
                    <item>
                <title>مفاهیم پایه برای معماران و تحلیلگران نرم‌افزار</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D9%85%D9%81%D8%A7%D9%87%DB%8C%D9%85-%D9%BE%D8%A7%DB%8C%D9%87-%D8%A8%D8%B1%D8%A7%DB%8C-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%D8%A7%D9%86-%D9%88-%D8%AA%D8%AD%D9%84%DB%8C%D9%84%DA%AF%D8%B1%D8%A7%D9%86-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-dow1uhtxa6ng</link>
                <description>مفاهیم و موضوعات پایه و اساسی برای معماران و تحلیلگران نرم‌افزار در دنیای مهندسی نرم‌افزارانتقال تجربیات و منتورینگ جوانان در شرکتسلام دوستان. این مقاله بیشتر جنبه اشتراک تجربه رو خواهد داشت. میخوام موضوعاتی رو در این مقاله بیان کنم که برای افرادی که میخوان وارد دنیای مهندسی نرم افزار بشوند یا کسانی که وارد شده اند و در این دنیا دارند کار میکنند، بسیار حائز اهمیت خواهد بود. احتمالاً لحن مقاله برای اکثرا عزیزان مخصوصاً دوستانی که زیاد با فرهنگ اصلاح ساختار های فنی-سازمانی آشنا نیستند، شیرین نخواهد بود. سعی میکنم موضوعات رو به صورت بولت پوینت های کوتاه و قابل فهم در مقاله بنویسم تا مطالعه کمی اسان تر بشود.در سال‌های اخیر، عناوینی مانند Software Architect و Software Analyst به‌سرعت در بازار کار رواج پیدا کرده‌اند. کافی‌ هست چند سالی برنامه‌نویسی کرده باشید، چند نمودار کشیده باشید یا چند کتاب معماری خوانده باشید تا بعضاً خودتان یا دیگران شما را شایسته‌ی این عناوین بدانند.اما واقعیت مهندسی نرم‌افزار، بسیار سخت‌گیرانه‌تر، عمیق‌تر و بی‌رحم‌تر از چیزی است که در رزومه‌ها و لینکدین دیده می‌شود.معماری و تحلیل نرم‌افزار شغل نیستند، مسئولیت‌اند؛ مسئولیت تصمیم‌هایی که می‌توانند یک شرکت را به رشد برسانند یا سال‌ها عقب بیندازند.و اینجاست که سن، تجربه، بلوغ فکری و فهم سازمانی اهمیت حیاتی پیدا می‌کند.تجربه، نه فقط دانشمعماری و تحلیل، نقطه‌ی شروع نیستندیکی از بزرگ‌ترین خطاهای رایج در شرکت‌های نرم‌افزاری این است که معماری و تحلیل را به‌عنوان نقطه‌ی شروع مسیر حرفه‌ای می‌بینند، نه نقطه‌ی بلوغ آن.معمار نرم‌افزار کسی نیست که:فقط الگوها را بشناسدفقط دیاگرام بکشدفقط درباره‌ی تکنولوژی‌ها نظر بدهدمعمار کسی است که:پیامد تصمیم‌ها را سال‌ها بعد پیش‌بینی کندبداند کِی نه بگویدبداند کِی سکوت کندبداند کِی نظر افراد باتجربه‌تر از خود را بپذیرداین‌ها با چند سال کدنویسی یا چند پروژه‌ی کوچک به‌دست نمی‌آیند.سن کم معنیش ناتوانی نیست،ولی میتونه این باشه که صلاحیت کامل ندارید.دوستان من، کم‌سن‌بودن به‌خودیِ‌خود ایراد نیست؛ایراد زمانی شروع می‌شود که کم‌تجربگی با اعتمادبه‌نفس کاذب ترکیب شود.افراد جوان معمولاً:سریع یاد می‌گیرندانرژی بالایی دارندبا تکنولوژی‌های جدید آشناترنداما اغلب:هزینه‌ی تصمیم اشتباه را تجربه نکرده‌اندبا پیچیدگی‌های سازمانی آشنا نیستنداثر تصمیم‌ها بر تیم‌های دیگر را دست‌کم می‌گیرندمعماری نرم‌افزار جایی نیست که «آزمون و خطا» در مقیاس سازمان انجام شود. این رو باید کسی که در این پوزیشن قرار میگیرد، به صراحت بداند.فاجعه‌ی اول: بازنویسی خودسرانه سیستمیک تحلیلگر/معمار جوان تصمیم می‌گیرد:«سیستم فعلی قدیمی است، بیایید کل آن را Microservice کنیم.»بدون:درک محدودیت‌های تیمشناخت فرآیندهای واقعی کسب‌وکارتوجه به توان DevOpsبررسی هزینه‌های عملیاتینتیجه:چندین سرویس نیمه‌کارهافزایش شدید باگتیمی فرسوده و بی‌انگیزهبازگشت دوباره به معماری قبلی با هزینه‌ی چندبرابریاین فاجعه نه به‌خاطر Microservice،بلکه به‌خاطر تصمیم‌گیری بدون تجربه و بدون گوش‌دادن رخ داد.Ownership؛ مالکیت، نه خودخواهییکی از مفاهیم کلیدی در مهندسی نرم‌افزار Ownership است؛اما این مفهوم اغلب اشتباه فهمیده می‌شود.Ownership یعنی:مسئولیت‌پذیری در برابر نتیجهپاسخ‌گویی در برابر شکستدر نظر گرفتن کل سیستم، نه فقط بخش خودتOwnership یعنی من صاحب مسئله‌ام، نه صاحب قدرت.وقتی فرد کم‌تجربه ownership را با «هرکاری دلم خواست انجام بدهم» اشتباه می‌گیرد:ساختار سازمانی نادیده گرفته می‌شودتصمیم‌ها شخصی می‌شوندسیستم قربانی خواسته های فردی می‌شودفاجعه‌ی دوم: نادیده‌گرفتن سلسله‌مراتب سازمانییک معمار جوان:بدون هماهنگی با مدیر فنیبدون هم‌راستاسازی با تیم عملیاتبدون اطلاع تیم‌های دیگرتصمیم معماری کلیدی می‌گیرد.نتیجه:تضاد بین تیم‌هابی‌اعتمادی مدیریتیشکست پروژه، حتی اگر تصمیم فنی درست بوده باشددر مهندسی نرم‌افزار،تصمیم درست در زمان و جای غلط = تصمیم اشتباه است. لازمه درک همین جمله ای که نوشتم، چندین سال کار و تجربه مستمر هست. این رو که به اشتراک میگذاریم، افراد در نظر نمیگیرند.گوش‌دادن، مهارتی مهم‌تر از طراحیافراد باتجربه:کمتر حرف می‌زنندبیشتر سؤال می‌پرسندعجله نمی‌کنندیکی از نشانه‌های بلوغ حرفه‌ای این است که:بدانی همیشه کسی هست که بیشتر از تو می‌داند.نصیحت‌پذیری از افراد باتجربه:نشانه ضعف نیستنشانه حرفه‌ای‌بودن استاین مسئله فقط مخصوص معماران نیستاین الگو در تمام نقش‌ها دیده می‌شود:برنامه‌نویس‌های تازه‌کار که استانداردها را نادیده می‌گیرندلیدهای کم‌تجربه که تیم را فرسوده می‌کنندتحلیلگرانی که مسئله را درست نمی‌فهمند ولی راه‌حل می‌دهندهرجا:ego (مَنیت - مًن مَن کردن) جای تجربه را بگیردسرعت جای بلوغ راتکنولوژی جای فهم مسئله رافاجعه محتمل است.جمع‌بندیمعماری و تحلیل نرم‌افزار:با سال‌ها کار واقعی ساخته می‌شوندبا گوش‌دادن رشد می‌کنندبا احترام به ساختار سازمانی معنا پیدا می‌کننداگر کم‌سن هستید:عجله نکنیدیاد بگیریدگوش بدهیدکار واقعی انجام بدهیدو اگر مسئول تصمیمی هستی که آینده‌ی یک سیستم را می‌سازد یا خراب می‌کند:یادتان باشد، هزینه‌ی اشتباه شما را فقط خودتان نمی‌دهید.دوستان هر کلمه ای که در این مقاله بیان کردم، دارای اهمیت ویژه در پوزیشن معمار و تحلیل گر نرم افزار بود. دوستانی که میخواهند در این مسیر قدم بگذارند یا میخواهند با واقعیت های مسیر رو به رو شوند، دوباره مقاله را بخوانند. با تشکر</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 22 Feb 2026 14:28:29 +0330</pubDate>
            </item>
                    <item>
                <title>معرفی Apache Lucene</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D9%85%D8%B9%D8%B1%D9%81%DB%8C-apache-lucene-aavxceyqpci4</link>
                <description>هسته‌ای که خیلی از موتورهای جستجو روش ایستادن؛سلام. وقتی با حجم زیادی دیتا سر و کار داشته باشیم و بخواهیم روش جستجوی درست‌وحسابی پیاده کنیم، احتمالاً یا مستقیم یا غیرمستقیم کارمون به Lucene خواهد خورد.Lucene در اصل یه کتابخونه‌ی جستجوی متن (Full-Text Search) هست که توسط Apache توسعه داده می‌شه و تمرکزش روی اینه که «جستجو سریع، دقیق و قابل‌کنترل» باشه. نه بیشتر، نه کمتر. یعنی خودش ادعا نمی‌کنه یه محصول آماده‌ست، بلکه ابزار میده دستتمون تا خودمون سیستم جستجویی که میخواهیم رو بسازیم.Lucene به زبان Java نوشته شده و از همون اول هم با این ذهنیت طراحی شده که بتونه روی حجم خیلی زیاد داده جواب بده. چیزی که تو مستندات رسمی خیلی روش تأکید شده اینه که Lucene قراره هسته‌ی جستجو باشه، نه کل سیستم. یعنی خبری از UI، REST API یا دیپلوی آماده نیست؛ اینا چیزاییه که باید خودمون بسازیم یا ابزارهای بالادستی برامون فراهم کنند. معماری lucenceLucene دقیقاً چه کاری انجام میده؟Lucene کارش دو تا چیز اصلیه:ایندکس‌کردن و جستجو کردن.اول داده‌ها (معمولاً متن) رو می‌گیری، بهش میگی چجوری تحلیل بشن (Analyzer)، بعد Lucene ازشون یه ساختار بهینه می‌سازه که اسمش هست Index. بعدش هر وقت کاربر یا سیستم یه Query می‌فرسته، Lucene خیلی سریع میره سراغ همون ایندکس و نتایج مرتبط رو برمی‌گردونه. نکته‌ی مهم اینه که Lucene اصلاً قرار نیست مثل دیتابیس رکورد به رکورد بگرده؛ کل فلسفه‌اش اینه که از قبل همه‌چی رو آماده کرده.موضوع Inverted Index؛ قلب تپنده‌ی Luceneهسته‌ی اصلی Lucene چیزی به اسم Inverted Index هست. اگر بریم برای بررسی عمیق موضوع:به‌جای اینکه بگه «این سند چه کلماتی داره»، می‌گه «این کلمه تو کدوم سندها اومده».مثلاً به‌جای اینکه برای کلمه‌ی «معماری» کل دیتاست رو بگرده، مستقیم می‌دونه این کلمه تو چه سندهایی وجود داره و حتی چند بار تکرار شده. همین نگاه معکوسه که باعث می‌شه Lucene بتونه روی میلیون‌ها سند هم جستجوی سریع انجام بده، بدون اینکه به CPU و I/O فشار زیادی بیاد. میدونه که «aardvark» در اسناد 1، 5، 400 و 900 وجود دارهAnalyzer؛ جایی که متن رو می‌فهمیمLucene فرض نمی‌کنه متن خام همون چیزیه که باید ایندکس بشه. قبل از ایندکس، متن میره توی یه مرحله به اسم Analysis. اینجا اتفاقاتی مثل اینا می‌افته:شکستن متن به Tokenحذف Stop Wordهانرمال‌سازی حروفStemming یا LemmatizationStemming یعنی اینکه کلمه رو با یه‌سری قواعد مکانیکی کوتاه کنی تا به یه ریشه‌ی تقریبی برسی. مثل این میمونه که واژه «running» رو تبدیل میکنه به «run» یا واژه «connection» رو تبدیل میکنه به «connect».Lemmatization یه قدم جلوتره. اینجا سیستم سعی می‌کنه کلمه رو به شکل پایه‌ی واقعی زبان (lemma) برسونه، با در نظر گرفتن:نقش دستوری (اسم، فعل، صفت)ساختار زبانیگاهی context جملهمثل این میمونه که واژه «better» رو تبدیل میکنه به «good». اینجا خروجی حتماً یه کلمه‌ی معتبر زبانیه. کندتر از stemming هست و اینکه Lucene به صورت پیش فرض از Stemming استفاده میکنه. همه‌ی اینا با چیزی به اسم Analyzer کنترل می‌شه. چیزی که مستندات Lucene روش خیلی تأکید دارن اینه که انتخاب Analyzer درست، نصف کیفیت جستجوی شماست. اگه اینجا اشتباه کنی، بهترین Queryها هم نجاتمون نمیدن. باید دقت کافی رو داشته باشیم. Document ها، لیست Stop Word و Inverted indexQuery در Lucene فقط «جستجو» نیستبرخلاف چیزی که خیلی‌ها فکر می‌کنن، Query تو Lucene فقط یه match ساده نیست. Query می‌تونه شامل کلی منطق باشه:منطق phrase queryمنطق fuzzy searchمنطق  wildcardمنطق range queryمنطق Boolean logicLucene این Queryها رو می‌گیره، می‌بره روی Index، بعد با الگوریتم‌های رتبه‌بندی (مثل BM25) نتایج رو امتیازدهی می‌کنه. یعنی خروجی صرفاً «پیدا شد / نشد» نیست؛ یه لیست مرتب‌شده از مرتبط‌ترین نتایجه. یکم بیشتر در مورد الگوریتم BM25  صحبت کنیم بچه ها. BM25 (که اسم کامل‌ترش Okapi BM25 هست) یه الگوریتم رتبه‌بندی نتایج جستجوئه.یعنی وقتی کاربر یه Query می‌زنه و چند تا سند match می‌شن، BM25 تصمیم می‌گیره:«کدوم نتیجه واقعاً به درد این کاربر می‌خوره و باید بالاتر نمایش داده بشه؟»تو دنیای واقعی، این یعنی تفاوت بین:«یه چیزی پیدا شد»و «همونی که دنبالش بودم پیدا شد»خب Lucene داره از BM25 استفاده میکنه و دوستانی که میخوان اطلاعات بیشتری در این حوزه کسب کنند، پیشنهاد میکنم این رو بررسی کنند. Segmentها؛ دلیل سرعت و مقیاس‌پذیریIndex تو Lucene یه فایل بزرگ یک‌تکه نیست. از چند تا Segment تشکیل شده که هر کدوم مستقلن. این طراحی باعث می‌شه:نوشتن و خواندن همزمان راحت‌تر بشهایندکس‌سازی Incremental باشهPerformance تو حجم بالا حفظ بشهLucene خودش مدیریت merge شدن segmentها رو انجام میده، ولی مستندات رسمی بارها می‌گن که اگه تو محیط production هستی، باید بدونی این mergeها چه زمانی و با چه هزینه‌ای انجام می‌شن.Lucene قراره کِی استفاده بشه؟ما معمولا Lucene رو باید در جایی استفاده کنیم که:دیتاهامون زیاده، جستجو مهم‌تر از CRUD ساده‌ست، می‌خواییم روی relevance و ranking کنترل داشته باشیم، حاضر هستیم معماری جستجو رو خودمون طراحی کنی از ابتدا. به همین خاطره که خیلی از سیستم‌های معروف‌تر مثل Elasticsearch یا Solr، در واقع اومدن روی Lucene سوار شدن و لایه‌های بالادستی بهش اضافه کردن.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 22 Feb 2026 13:32:55 +0330</pubDate>
            </item>
                    <item>
                <title>جبر رابطه‌ای در پایگاه داده</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%AC%D8%A8%D8%B1-%D8%B1%D8%A7%D8%A8%D8%B7%D9%87-%D8%A7%DB%8C-%D8%AF%D8%B1-%D9%BE%D8%A7%DB%8C%DA%AF%D8%A7%D9%87-%D8%AF%D8%A7%D8%AF%D9%87-dzovhibvllal</link>
                <description>بیایید ببینیم دیتابیس واقعاً چطور فکر می‌کندسلام. اول میخوام یک موضوعی رو بیان کنم اینکه این مقاله کمی طولانی هست و در سه قسمت اصلی تقسیم بندی شده است. پس اگر معمار سیستم های پایگاه داده هستید و یا علاقه زیادی به مباحث پایگاه داده دارید، این مقاله برای شما مفید خواهد بود.در قسمت اول: مشروحی بر چیستی موضوع رو خواهیم داشت. در قسمت دوم: تعاریف دقیق کلید واژه ها رو خواهیم داشت. در قسمت سوم: به بررسی مقاله آقای Edgar Frank Codd مطروحه در سال 1970خواهیم پرداخت.اگر در مورد آقای کاد اطلاعات کافی ندارید، پیشنهاد میکنم این مقاله رو حتما بررسی کنید.قسمت اول: مشروحی بر چیستی موضوع؛دوستان اگر چند سالی با دیتابیس‌های رابطه‌ای سر و کله زده باشید، احتمالاً SQL شده رفیق شفیق‌تان. کوئری می‌زنیم، دیتا می‌گیریم، کار راه می‌افتد و تمام. اما معمولاً یک سؤال مهم را از خودمان نمی‌پرسیم: «پایگاه داده این دستوراتی که من نوشتم را چطور می‌فهمد؟»جواب کوتاه این است: نه با SQL، بلکه با چیزی عمیق‌تر به اسم جبر رابطه‌ای.ایده‌ی جبر رابطه‌ای اولین‌بار توسط Edgar Frank Codd در مقاله‌ی معروفش در سال ۱۹۷۰ مطرح شد؛ زمانی که هنوز خبری از SQL به شکل امروزی‌اش نبود. آقای کاد دنبال یک زبان برنامه‌نویسی نبود؛ دنبال یک مدل فکری بود. مدلی که به ما اجازه بده درباره داده‌ها بدون وابستگی به فایل، دیسک و جزئیات فیزیکی فکر کنیم.برای شروع، باید یک سوءتفاهم رایج را کنار بگذاریم:در مدل رابطه‌ای، «جدول» فقط یک جدول نیست. چیزی که ما بهش می‌گیم جدول، از دید کاد یک Relation است. Relation یعنی یک رابطه‌ی ریاضی؛ چیزی شبیه یک مجموعه. داخل این مجموعه، هر سطر یک Tuple است. اگر بخواهم خیلی خودمونی بگم، Tuple یعنی «یک رکورد کامل». هر ستون هم یک Attribute است؛ یعنی یک ویژگی از داده، مثل نام، سن یا ایمیل.نکته‌ی مهم اینجاست که Relation مجموعه است، نه لیست. یعنی ترتیب سطرها مهم نیست و تکرار معنی ندارد. شاید در SQL این‌ها را حس نکنیم، ولی در ذهن جبر رابطه‌ای، این‌ها اصول پایه‌اند.حالا که داده را مجموعه دیدیم، طبیعی است که بخواهیم روی آن عملیات انجام بدهیم. این‌جاست که جبر رابطه‌ای وارد بازی می‌شود. جبر رابطه‌ای مجموعه‌ای از عملگرهاست که روی Relationها کار می‌کنند و یک ویژگی خیلی مهم دارند: هر عملی که انجام می‌دهیم، خروجی‌اش باز هم یک Relation است. آقای کاد روی این موضوع خیلی تأکید داشت، چون همین ویژگی است که اجازه می‌دهد عملیات‌ها را ترکیب کنیم و بهینه‌سازی منطقی انجام بدهیم.مثلاً عملگر Selection را در نظر بگیر. Selection یعنی انتخاب بعضی سطرها بر اساس یک شرط. اگر بخواهم ساده بگویم، همان کاری که WHERE در SQL می‌کند. فرض کن یک Relation داریم به اسم Students. وقتی می‌گوییم «دانشجوهایی که معدل‌شان بالای ۱۸ است»، در جبر رابطه‌ای داریم یک Selection انجام می‌دهیم. خروجی این کار نه یک لیست، نه یک فایل، بلکه یک Relation جدید است که فقط بعضی از Tupleها را دارد.یا عملگر Projection. Projection یعنی انتخاب بعضی ستون‌ها. مثلاً می‌گویی «از جدول دانشجوها فقط نام و ایمیل را می‌خواهم». این دقیقاً Projection است. باز هم خروجی یک Relation جدید است؛ با Attributeهای کمتر، ولی همچنان یک Relation کامل.علائم عملگر ها و معانی اونها در جبر رابطه ای پایگاه دادهجایی که داستان جالب‌تر می‌شود، وقتی چند Relation را با هم ترکیب می‌کنیم. مثلاً Cartesian Product که معمولاً اسمش ترسناک به نظر می‌رسد، در اصل یعنی ترکیب هر Tuple از یک Relation با هر Tuple از Relation دیگر. Joinهایی که ما هر روز می‌نویسیم، در نگاه جبر رابطه‌ای، چیزی نیستند جز ضرب دکارتی به اضافه‌ی Selection. اگر ضرب دکارتی، جبر، رابطه یا جبر رابطه ای رو دقیق نمیتونیم درک کنیم معانیش رو، معنیش این نیست باید این فیلد رو رها کنیم. در بخش بعدی (قسمت 2)، سعی کردم تعاریف دقیق از این کلید واژه ها رو داشته باشیم. آقای کاد در مقاله‌های بعدی‌اش (اوایل دهه‌ی ۷۰ میلادی) دقیقاً روی همین تجزیه‌ی Join تأکید می‌کند تا نشان بدهد این‌ها مفاهیم مستقل نیستند، بلکه از چند عمل ساده ساخته شده‌اند.یک نکته‌ی مهم این وسط هست که معمولاً کمتر بهش توجه می‌کنیم: SQL خودِ جبر رابطه‌ای نیست. SQL از جبر رابطه‌ای الهام گرفته، ولی کاملاً با آن یکی نیست. SQL تکرار دارد، ترتیب دارد، NULL دارد و به پیاده‌سازی وابسته است. اما جبر رابطه‌ای کاملاً صوری و تمیز است. در واقع، وقتی شما یک کوئری SQL می‌نویسید، موتور پایگاه داده آن را به یک نمایش داخلی شبیه به جبر رابطه‌ای تبدیل می‌کند و بعد تازه می‌رود سراغ اجرا.و این دقیقاً همان چیزی است که آقای کاد دنبالش بود. او در مقالات سال‌های ۱۹۷۰ تا ۱۹۷۲ بارها روی مفهوم استقلال منطقی داده تأکید می‌کند. یعنی برنامه‌نویس باید بتواند بگوید «چه دیتایی می‌خواهم»، نه اینکه مجبور باشد بداند «دیتا دقیقاً کجای دیسک و با چه ساختاری ذخیره شده». جبر رابطه‌ای ابزار این نوع فکر کردن است. البته این موضوع برای معمارها نیست ها. معمار پایگاه داده باید دقیق بدونه که سیستم چگونه کار میکنه. برنامه نویس ما، تاکید دارم که صرفاً برنامه نویس و توسعه دهنده ما نیاز به عمیق شدن زیاد در این حوزه ندارد.اگر بخواهم تجربه‌ی شخصی‌ام را بگم، جبر رابطه‌ای چیزی نیست که هر روز بنشینیم و فرمول‌هایش را بنویسیم. اما وقتی آن را بفهمید، یک اتفاق جالب می‌افتد:کوئری‌های بد را زودتر تشخیص می‌دهید، Joinهای بی‌منطق توی ذوق‌تان می‌زند، و طراحی دیتابیس برایتان از «حس شهودی» تبدیل می‌شود به «تصمیم آگاهانه».در نهایت، جبر رابطه‌ای میراث فکری کسی است که قبل از همه فهمید پایگاه داده فقط محل ذخیره‌ی اطلاعات نیست، بلکه یک سیستم فکری است. اگر بخواهیم معماری داده را جدی بگیریم، راهی نداریم جز اینکه حداقل یک بار، عمیق و درست، این زبان زیرساختی را بفهمیم؛ زبانی که پایگاه داده واقعاً با آن فکر می‌کند.قسمت دوم: حالا بریم مفاهیم پایه و کلید واژه ها رو بررسی کنیم؛اول: «جبر» یعنی چی؟وقتی از «جبر» حرف می‌زنیم، منظورمان یک سری عمل و قانون است که روی یک‌سری اشیاء مشخص انجام می‌شود و نتیجه‌ی قابل پیش‌بینی می‌دهد.مثلاً در جبر عددی، ما عدد داریم و عملگرهایی مثل جمع و ضرب. در جبر رابطه‌ای هم دقیقاً همین اتفاق می‌افتد، فقط به‌جای عدد، با «رابطه» کار می‌کنیم.پس جبر یعنی:مجموعه‌ای از عملگرها + قوانینی که مشخص می‌کنند این عملگرها چطور روی داده‌ها اعمال شوند.دوم: «رابطه» یعنی چی؟اینجا معمولاً اولین سوءتفاهم شکل می‌گیرد.رابطه از دید پایگاه داده رابطه‌ای فقط یک جدول ظاهری نیست.در تعریف رسمی، رابطه یک مجموعه از تاپل‌هاست.Tuple (تاپل) یعنی یک رکورد کامل؛ چیزی که ما معمولاً بهش می‌گیم «یک سطر»Attribute (ویژگی) یعنی یک ستون؛ مثل نام، سن، ایمیلکل رابطه یعنی یک مجموعه از این تاپل‌هایک نکته‌ی مهم رو داشته باشیم اینجا اینکه رابطه مجموعه است، نه لیست. یعنی ترتیب سطرها اهمیتی نداره و تکرار مفهومی ندارد (حتی اگر در SQL ببینیم). این نگاه دقیقاً همان چیزی است که آقای کاد روی آن تأکید داشت.سوم: تعریف دقیق «جبر رابطه‌ای»حالا که جبر و رابطه را جداگانه فهمیدیم، تعریف مشهور جبر رابطه‌ای خیلی تمیز می‌شود. من اینطور میگم:جبر رابطه‌ای مجموعه‌ای از عملگرهای صوری است که روی روابط تعریف می‌شوند و نتیجه‌ی هر عملگر نیز یک رابطه است.این جمله شاید ساده به نظر برسد، اما یک مفهوم بسیار مهم داخلش خوابیده:خاصیت بسته‌بودن (Closure)یعنی هر کاری روی داده انجام بدیم، باز هم در دنیای Relation باقی می‌مانیم. همین ویژگی است که امکان ترکیب عملیات، بازنویسی و بهینه‌سازی را می‌دهد.چهارم: جبر رابطه‌ای در پایگاه داده یعنی چه؟در سیستم‌های پایگاه داده رابطه‌ای، جبر رابطه‌ای زبان اجرایی نیست؛ زبان فکری است. یعنی چی؟ یعنی اینکه شما با SQL حرف می‌زنید، اما پایگاه داده در لایه‌های داخلی، کوئری شما را به چیزی شبیه جبر رابطه‌ای تبدیل می‌کند و بعد تصمیم می‌گیرد چطور آن را اجرا کند.به بیان ساده‌تر:SQL چیزی است که شما می‌نویسید،جبر رابطه‌ای چیزی است که دیتابیس می‌فهمد.این دقیقاً همون چیزی است که آقای کاد در مقاله‌ معروفش در سال ۱۹۷۰ و مقالات بعدی‌اش در اوایل دهه‌ی ۷۰ میلادی مطرح کرد؛ برای رسیدن به استقلال منطقی داده. اصلاً موضوع داره به صراحت در مقاله بیان میشه.خب حالا بریم یک مثال واقعی داشته باشیم برای درک بهتر موضوع؛فرض کنیم یک Relation داریم به اسم Students با این Attributeها:StudentID, Name, Age, GPASelection (انتخاب)Selection یعنی فیلتر کردن تاپل‌ها بر اساس شرط.اگر بگیم:«دانشجوهایی که معدل‌شان بالای ۱۸ است»از دید جبر رابطه‌ای:ما داریم روی Relation Students یک Selection انجام می‌دهیم و خروجی‌اش یک Relation جدید است که فقط بعضی تاپل‌ها را دارد.از نظر ذهنی خیلی شبیه این است:SELECT * FROM Students WHERE GPA &gt; 18;Projection (تصویر)Projection یعنی انتخاب بعضی Attributeها.مثلاً می‌گیم:«از دانشجوها فقط نام و معدل را می‌خواهم»در این حالت:تعداد ستون‌ها کم می‌شودولی همچنان خروجی یک Relation معتبر استمعادل ذهنی SQL:SELECT Name, GPA FROM Students;Union (اجتماع)Union یعنی ترکیب دو Relation هم‌ساختار.فرض کنیم:PassedStudentsExcellentStudentsاگر Union بگیریم:همه‌ی دانشجوهایی که یا پاس شده‌اند یا ممتازند، در یک Relation جدید جمع می‌شوند.Difference (تفاضل)Difference یعنی کم کردن یک Relation از Relation دیگر.مثلاً:«دانشجوهایی که ثبت‌نام کرده‌اند ولی هنوز پاس نشده‌اند»از نظر مفهومی:یک Relation را از دیگری کم می‌کنیم و خروجی باز هم یک Relation است.Cartesian Product (ضرب دکارتی)دوستان اینجا معمولاً همه می‌ترسند، ولی در اصل مفهومش ساده است. همون موضوعی که در بخش قبلی گفتم یک مثال میزنیم تا راحت تر بشه فهمش.اگر Relation Students و Relation Courses را ضرب دکارتی کنیم:هر دانشجو با هر درس ترکیب می‌شودخروجی شامل تمام ترکیب‌های ممکن استJoinهایی که هر روز می‌نویسیم، در واقع:ضرب دکارتی + Selection هستندکاد دقیقاً برای همین این عملگر را پایه‌ای در نظر گرفت.Rename (تغییر نام)Rename برای وقتی است که:اسم Relation یا Attributeها را عوض می‌کنیمتا در ترکیب عملیات‌ها دچار ابهام نشویماین عملگر ساده، ولی در جبر رابطه‌ای بسیار حیاتی است.خب حالا اطلاعات بالا رو داشته باشیم. میخوام یک مثال دیگر بزنم ببینیم موضوع چی هست. فرض میکنیم دو تا جدول داریم به نام های Students برای نگهداری اطلاعات دانشجو ها مشتمل بر ستون های شناسه، نام و رشته. جدول دیگری داریم بنام Enrollments برای نگهداری اطلاعات دروس دانشجو ها مشتمل بر ستون های شناسه، شناسه ارتباطی دانشجو، درس و نمره.حالا بریم سراغ اطلاعات موجود در جداول:در جدول Students داریم: 1) شناسه: 1 | نام: علی | رشته: کامپیوتر 2) شناسه: 2 | نام: سارا | رشته: برق3) شناسه: 3 | نام: سحر | رشته: کامپیوتردر جدول Enrollments داریم: 1) دانشجو: 1 | درس: پایگاه داده | نمره: 182) دانشجو: 2 | درس: سیستم عامل | نمره: 153) دانشجو: 3 | درس: پایگاه داده | نمره: 19سوال: اسم دانشجوهایی که رشته‌شون کامپیوتر هست و درس پایگاه داده رو گرفتن رو پیدا کن.SELECT S.name
FROM Students S
JOIN Enrollments E ON S.sid = E.sid
WHERE S.major = &#039;CS&#039;
  AND E.course = &#039;DB&#039;;توجه داشته باشیم که name یعنی نام دانشجو، CS یعنی رشته کامپیوتر Computer Science و DB یعنی درس پایگاه داده و sid شناسه دانشجو ها میباشد.حالا میریم معادل در جبر رابطه‌ای (Relational Algebra) ها رو داشته باشیم:انتخاب دانشجویان رشته کامپیوتر: 
σ major=′CS′​(Students)انتخاب ثبت‌ نام‌های درس پایگاه داده
σ course=′DB′​(Enrollments)جوین روی شناسه ها
σ major=′CS′​(Students) ⋈ Students.sid=Enrollments.sid​ σ course=′DB′​(Enrollments)پروجکشن روی نام ها
π name​(σ major=′CS′​(Students) ⋈ Students.sid=Enrollments.sid​ σ course=′DB′​(Enrollments))دوستان خواهش میکنم عنایت ویژه بفرمایید ببینید چه اتفاقی در حال رخ دادن هست. معادل و تطبیق مفهومی SQL و جبر رابطه‌ای رو باهم داشته باشیم:WHERE در SQL معادل σ (selection) در جبر رابطه ایSELECT ستون‌ها در SQL معادل π (projection) در جبر رابطه ایJOIN در SQL معادل ⨝ (join) در جبر رابطه ایFROM در SQL معادل رابطه‌های ورودی در جبر رابطه ایپس در نتیجه اگر یک معمار با مطالعه موضوعات فوق بخواهد برای خودش یک جمع بندی داشته باشه، میگه:SQL در اصل یک زبان اعلانی (Declarative) است،اما در پشت صحنه، موتور دیتابیس کوئری را به جبر رابطه‌ای تبدیل می‌کند.یعنی:ما در SQL میگیم«چی می‌خوام» و دیتابیس با جبر رابطه‌ای تصمیم می‌گیره «چطوری بهش برسم»جمع‌بندی بخش دوم رو داشته باشیم؛جبر رابطه‌ای به ما یاد می‌دهد چطور درباره داده فکر کنیم، نه فقط چطور از آن اطلاعات بکشیم بیرون. این همان دیدی است که آقای کاد بیش از پنجاه سال پیش مطرح کرد و هنوز هم ستون فقرات پایگاه داده‌های رابطه‌ای است. اگر این لایه را بفهمید، SQL برایتان شفاف‌تر می‌شود، طراحی دیتابیس‌تان منطقی‌تر می‌شود و مهم‌تر از همه، دیگر با پایگاه داده «کورکورانه» کار نمی‌کنید.قسمت سوم: بررسی مقاله مطروحه در سال 1970؛این مقاله اساساً می‌گه:کاربر نباید درگیر این باشه که داده‌ها توی کامپیوتر چطوری ذخیره شدن.آقای ادگار کاد از همون اول دست می‌ذاره روی یه مشکل جدی سیستم‌های دیتابیس قدیمی:اگه ساختار ذخیره‌سازی داده‌ها عوض بشه (مثلاً ترتیب، ایندکس، یا مسیر دسترسی)، کلی برنامه و گزارش از کار می‌افتن و این فاجعه‌ست.مشکل دیتابیس‌های قدیمی چی بود؟سیستم‌های قدیمی (درختی و شبکه‌ای مثل IMS و IDS) سه تا وابستگی خطرناک داشتن:وابستگی به ترتیب داده‌هابرنامه‌ها فرض می‌کردن داده‌ها به یه ترتیب خاص ذخیره شدن. ترتیب عوض می‌شد؟ برنامه می‌ترکید.وابستگی به ایندکس‌هاایندکس که باید فقط برای سرعت باشه، عملاً می‌شد جزئی از منطق برنامه.وابستگی به مسیر دسترسی (Access Path)برنامه‌ها دقیقاً می‌دونستن از چه مسیری به داده برسن.ساختار عوض می‌شد؟ برنامه دیگه نمی‌فهمید داده کجاست.راه‌حل آقای کاد: مدل رابطه‌ایاقای کاد پیشنهاد میده داده‌ها رو نه به شکل درخت و شبکه، بلکه به شکل Relation (رابطه) ببینیم؛ چیزی شبیه جدول:هر سطر = یک رکوردهر ستون = یک ویژگیترتیب سطرها مهم نیستحتی ترتیب ستون‌ها هم برای کاربر نباید مهم باشهمیگه کاربر فقط باید بدونه:اسم جدول چیهستون‌هاش چی‌انمعنی داده‌ها چیهو نه این‌که «چطوری ذخیره شدن». خیلی روی این موضوع تاکید داره.کلیدهای اصلی و خارجیآقای کاد خیلی شفاف مفاهیمی رو تعریف می‌کنه که امروز بدیهی‌ان:کلید اصلی (Primary Key): چیزی که هر رکورد رو یکتا می‌کنهکلید خارجی (Foreign Key): اشاره به کلید اصلی یه جدول دیگهو می‌گه رابطه‌ها می‌تونن به هم ارجاع بدن، بدون این‌که ساختار فیزیکی به کاربر تحمیل بشه. همین حرف شده امروز استاندارد اصلی پایگاه داده های رابطه ای.نرمال‌سازی (Normal Form)یکی از بخش‌های مهم مقاله همینه:آقای کاد می‌گه:جدول خوب، جدولی‌ هست که توش ستون‌های چندمقداری و تو‌در‌تو نداشته باشیم.راه‌حل:داده‌های تودرتو رو جدا کنکلیدها رو بیار پایینجدول‌ها رو ساده و اتمیک کننتیجه چی میشه اون موقع؟ مشخص هست دیگه؛ذخیره‌سازی ساده‌تر میشهانتقال داده راحت‌تر میشهناسازگاری کمتر به وجود میادزبان پرس‌وجوی ایده‌آل (همون کوئری گیری خودمون)آقای کاد یه ایده‌ی جسورانه میده:یه زبان عمومی برای کار با داده‌ها، بر پایه منطق و Predicate Calculusچیزی که بعدها الهام‌بخش SQL شد.ویژگی مهمش؟هر رابطه رو می‌تونی از هر سمتی پرس‌وجو کنیلازم نیست مسیر دسترسی رو حفظ باشیفقط بگو چی می‌خوای، نه چطور بهش برسیافزونگی و ناسازگاری داده‌هاآقای کاد بین دو نوع افزونگی فرق می‌ذاره:افزونگی قوی: داده‌ای که کاملاً از داده‌های دیگه قابل محاسبه‌ستافزونگی ضعیف: داده‌ای که همیشه وابسته‌ست، ولی دقیقاً قابل محاسبه نیستو تأکید می‌کنه:سیستم باید بتونه ناسازگاری‌ها رو تشخیص بده، حتی اگه موقت باشن.در نهایت من یک جمع بندی داشته باشماین مقاله پایه‌ی دیتابیس‌های مدرنه. حرف اصلیش اینه:کاربر نباید اسیر جزئیات ذخیره‌سازی بشهداده باید مستقل از برنامه باشهرابطه‌ها از مسیرها مهم‌ترنسادگی منطقی، از بهینه‌سازی فیزیکی مهم‌ترهتقریباً هر چیزی که امروز تو دیتابیس‌های رابطه‌ای بدیهیه، اولین‌بار تو همین مقاله گفته شده. معماران و تحلیل گران عزیزمون، این اطلاعات پایه، حتما در کَرییر کاری شما تاثیر گذار خواهند بود.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 22 Feb 2026 12:42:21 +0330</pubDate>
            </item>
                    <item>
                <title>Event-Driven در نرم افزار</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/event-driven-%D8%AF%D8%B1-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-utucodxodqvq</link>
                <description>Event-Driven Architecture؛ ستون فقرات سیستم‌های توزیع‌شده مدرنسلام دوستان؛ در این مقاله موضوع Event-Driven Architecture رو بررسی میکنیم. احتمالاً این مقاله برای افراد غیرفنی زیاد جالب نباشه و مخاطب خاصش، معمار ها و تحلیل گر ها، توسعه دهنده و علاقه مندان به برنامه نویسی خواهد بود.با رشد سیستم‌ها، افزایش نیاز به مقیاس‌پذیری و حرکت به سمت معماری‌های توزیع‌شده، الگوهای سنتی request/response و coupling مستقیم بین سرویس‌ها به‌تدریج به گلوگاه تبدیل می‌شوند. در چنین فضایی، Event-Driven Architecture (EDA) نه به‌عنوان یک انتخاب فانتزی، بلکه به‌عنوان یک ضرورت معماری مطرح می‌شود. EDA مدلی است که در آن سیستم‌ها به‌جای فراخوانی مستقیم یکدیگر، با انتشار و مصرف Eventها با هم تعامل می‌کنند.در این مقاله، Event-Driven Architecture را به‌صورت کاملاً فنی و عمیق بررسی می‌کنیم؛ از مدل ذهنی و مفاهیم پایه گرفته تا پیاده‌سازی واقعی با ابزارهای رایج. هدف این است که اگر بخواهیم یک سیستم واقعی مبتنی بر EDA طراحی و پیاده‌سازی کنیم، بتوانیم از مفاهیم پایه ای که در اینجا خواهم گفت، استفاده کنیم.مسئله اصلی؛ چرا معماری‌های سنتی مقیاس‌پذیر نیستند؟در معماری‌های synchronous، هر سرویس برای انجام کار خود به پاسخ سرویس‌های دیگر وابسته است. این وابستگی زنجیره‌ای باعث افزایش latency، شکنندگی سیستم و propagation خطا می‌شود. اگر یکی از سرویس‌ها down شود یا کند پاسخ دهد، کل زنجیره تحت تأثیر قرار می‌گیرد.علاوه بر این، coupling زمانی (temporal coupling) مشکل بزرگی است. سرویس‌ها باید هم‌زمان در دسترس باشند تا یک سناریوی بیزینسی اجرا شود. Event-Driven Architecture دقیقاً برای شکستن این وابستگی طراحی شده است.Event-Driven Architecture چیست؟ابتدا میخوام یک تعریف دقیق داشته باشیم. Event-Driven Architecture سبکی از معماری است که در آن Event به‌ عنوان واحد اصلی ارتباط بین اجزای سیستم استفاده می‌شود. Event بیانگر این است که «چیزی در سیستم اتفاق افتاده است»، نه اینکه «چه کاری باید انجام شود».در EDA، Producer یک Event را منتشر می‌کند، بدون اینکه بداند چه کسی یا چند Consumer آن را دریافت خواهند کرد. Consumerها هم بر اساس Eventهایی که دریافت می‌کنند، واکنش نشان می‌دهند. این مدل باعث loose coupling، scalability بالا و انعطاف‌پذیری در توسعه می‌شود.Event چیست و چه چیزی Event نیست؟با توجه به اینکه باید بدونیم Event دقیقا به چه معنایی هست، میخوام جمله دقیقی رو بیان کنم. Event یک واقعیت immutable است که در گذشته رخ داده و قابل تغییر نیست. نام‌گذاری Event بسیار مهم است و معمولاً باید به صورت past tense باشد، مثل OrderCreated یا PaymentCompleted. یعنی جریانی که در گذشته رخ داده است.در مقابل، Command یا Request بیانگر نیت انجام یک کار است. اشتباه رایج این است که Commandها را به‌عنوان Event منتشر کنیم. این کار مرز مسئولیت‌ها را مخدوش می‌کند و coupling منطقی ایجاد می‌کند. معمار ها، تحلیل گر ها و توسعه دهنده ها باید دقت کافی رو داشته باشند.اجزای اصلی Event-Driven ArchitectureEDA معمولاً از چند جزء کلیدی تشکیل می‌شود. Producer که Event را تولید می‌کند، Broker یا Message Bus که Event را منتقل می‌کند و Consumerهایی که Event را مصرف می‌کنند. هر کدام از این اجزا مسئولیت مشخص و محدودی دارند.Broker نقش بسیار مهمی در تضمین ordering، delivery و durability Eventها دارد. انتخاب Broker مناسب تأثیر مستقیمی بر قابلیت اطمینان سیستم دارد.Message Broker؛ قلب تپنده EDAپیاده‌سازی EDA بدون Message Broker عملاً غیرممکن است. ابزارهایی مثل Apache Kafka، RabbitMQ و Pulsar رایج‌ترین گزینه‌ها هستند. Kafka معمولاً برای throughput بالا و event streamهای بزرگ استفاده می‌شود، در حالی که RabbitMQ بیشتر برای messaging کلاسیک و routing پیچیده کاربرد دارد.در معماری Event-Driven، باید تفاوت بین queue و topic را به‌خوبی درک کرد. Queue معمولاً برای load balancing استفاده می‌شود، اما topic امکان fan-out و مصرف چندگانه Event را فراهم می‌کند. در مورد این بخش بیشتر صحبت خواهیم کرد.Event Schema و ContractEventها contract بین سرویس‌ها هستند. تغییر نادرست در schema Event می‌تواند چندین سرویس را هم‌زمان بشکند. به همین دلیل، versioning و backward compatibility در Eventها حیاتی است.استفاده از schema registry (مثلاً در Kafka) و فرمت‌هایی مثل Avro یا Protobuf به‌شدت توصیه می‌شود. Event باید self-descriptive باشد و حداقل اطلاعات لازم برای Consumer را فراهم کند.احتمالاً برخی دوستان ندونن بحث Avro چی هست پس همینجا یک اشاره کوچیکی داشته باشم بهش که Avro یک فرمت serialization باینری هست و مزیتش این است که schema جدا از payload ذخیره می‌شود و فقط ID آن داخل پیام قرار می‌گیرد. این کار باعث کاهش حجم پیام می‌شود. موضوع Protobuf هم که احتمالاً با gRPC کار کرده باشند، آشنا هستند دیگه. مال گوگل هست و ساختار strongly typed داره. معمار های با تجربه مون میدونن که در سیستم های high-throughput ، معمولا یا Avro یا protobuf استفاده میشه.بزارید این رو هم بگم بریم سراغ موضوعات بعدی. اگر نمیدونید schema registry چی هست در کافکا، Schema Registry یک سرویس مرکزی است که:ساختار (Schema) هر Event را ذخیره می‌کندVersionهای مختلف آن را نگه می‌داردقبل از publish شدن Event، اعتبار آن را بررسی می‌کند (مهم هست خیلی)سازگاری (compatibility) نسخه جدید با نسخه‌های قبلی را enforce می‌کند. حالا دیگه نمیخوام خیلی وارد مباحث Backward، Forward بشم. Backward میگه نسخه جدید باید بتواند داده‌های نسخه قبلی را بخواند اون یکی هم برعکش رو میگه.Delivery Semantics؛ از At-Most-Once تا Exactly-Onceبریم سراغ سمانتیک های تحویل و ببینیم که موضوع چی هست. در EDA باید صراحتاً مشخص شود که semantics تحویل Event چیست. At-most-once ساده ولی غیرقابل‌اعتماد است. At-least-once رایج‌ترین انتخاب است، اما نیازمند idempotent consumerهاست. Exactly-once پیچیده و معمولاً پرهزینه است و فقط در سناریوهای خاص ارزش دارد.طراحی Consumerها باید بر اساس at-least-once انجام شود و duplicate Eventها به‌عنوان واقعیت سیستم پذیرفته شوند.Eventual Consistency؛ واقعیت اجتناب‌ناپذیرEDA معمولاً به consistency آنی منجر نمی‌شود. بین انتشار Event و واکنش Consumerها تأخیر وجود دارد. این موضوع باید از ابتدا در طراحی بیزینسی پذیرفته شود. Eventual Consistency trade-off آگاهانه‌ای برای دستیابی به availability و scalability است که معمار ما باید حواسش باشه.نمایش وضعیت موقت، handling stateهای intermediate و طراحی UX مناسب بخشی از پیامدهای این انتخاب معماری هستند.طراحی Consumerها؛ Stateless یا Stateful؟Consumerها می‌توانند stateless یا stateful باشند. Consumerهای stateless ساده‌تر و مقیاس‌پذیرترند، اما در برخی سناریوها نیاز به نگه‌داشت state وجود دارد. در این حالت، مدیریت offset و persistence state اهمیت زیادی پیدا می‌کند. همچنین error handling و retry باید با دقت طراحی شوند تا از infinite loop جلوگیری شود.EDA و CQRSEvent-Driven Architecture به‌صورت طبیعی با CQRS هم‌راستا است. Commandها باعث تغییر state می‌شوند و Eventها نتیجه این تغییرات را منتشر می‌کنند. Read Modelها معمولاً با مصرف Eventها ساخته و به‌روزرسانی می‌شوند.این ترکیب امکان scale مستقل read و write را فراهم می‌کند و برای سیستم‌های با read-heavy workload بسیار مناسب است.مثال واقعی؛ سیستم فروش آنلاین Event-Drivenدر یک سیستم فروش آنلاین، Order Service بعد از ایجاد سفارش، OrderCreatedEvent منتشر می‌کند. Payment Service با دریافت این Event فرآیند پرداخت را آغاز می‌کند. Inventory Service موجودی را به‌روزرسانی می‌کند و Notification Service ایمیل یا پیام ارسال می‌کند.Order Service هیچ اطلاعی از Consumerها ندارد و همین موضوع باعث می‌شود اضافه یا حذف سرویس‌های جدید بدون تغییر در Producer انجام شود.Observability در Event-Driven ArchitectureDebug کردن EDA سخت‌تر از معماری synchronous است. Trace کردن یک Event در چند سرویس نیازمند logging ساختاریافته، correlation id و ابزارهای observability مثل OpenTelemetry است.بدون observability مناسب، EDA به‌سرعت به یک black box تبدیل می‌شود و واقعا نمیشه دقیق فهمید چه اتفاقاتی داره در داخل سیستم رخ میده. همیشه به معمار ها و تحلیل گر ها میگم که موضوع observability باید جدی در نظر گرفته بشه منتها کو گوش شنوا 😄چالش‌ها و Anti-Pattern هااستفاده افراطی از Event، انتشار Eventهای بسیار granular یا برعکس بیش‌ازحد coarse، و تبدیل Event Broker به دیتابیس از anti-pattern های رایج هستند. این موضوع رو هم باید دقت داشته باشیم روش.EDA باید با هدف مشخص و در جای درست استفاده شود، نه به‌عنوان پاسخ همه مشکلات.جمع‌بندیEvent-Driven Architecture یکی از پایه‌ای‌ترین الگوهای معماری برای ساخت سیستم‌های مدرن، scalable و resilient است. این معماری با حذف coupling مستقیم، امکان رشد مستقل سرویس‌ها و واکنش‌پذیری بالا را فراهم می‌کند. حالا خیلی از عزیزان میان و این موضوع رو با SAGA هم ترکیب میکنن و یه سیستم ترتمیزی میاد بیرون ازش. اگر در مورد SAGA اطلاعات بیشتری نیاز دارید، میتونید این مقاله رو مطالعه کنید. یک Cheat Sheet کلی هم در زیر قرار میدم برای پترن های رایج مثل outbox و event sourcing و aggregation.Cheat Sheet | Event-Driven Architectureاگر سیستم شما نیاز به مقیاس‌پذیری، انعطاف‌پذیری و توسعه‌پذیری بلندمدت دارد، EDA نه یک انتخاب اختیاری، بلکه یک تصمیم استراتژیک معماری است.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Wed, 11 Feb 2026 09:24:00 +0330</pubDate>
            </item>
                    <item>
                <title>الگوی SAGA در نرم افزار</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%A7%D9%84%DA%AF%D9%88%DB%8C-saga-%D8%AF%D8%B1-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-c8p1wtyal0gw</link>
                <description>SAGA Pattern؛ مدیریت تراکنش‌های توزیع‌شده از تئوری تا پیاده‌سازی عملیسلام دوستان. میخوام مقدمه ای در مورد SAGA بدم و سپس بریم جلو. احتمالاً این مقاله برای افراد غیرفنی زیاد جالب نباشه چون خیلی تخصصی داریم در مورد این پترن، یوزکیس ها، Event ها و Message ها صحبت میکنیم و اساساً مخاطب هدف، معمار ها و تحلیل گران نرم افزار، توسعه دهندگان و علاقه مندان به این موضوعات است.شروع کنیم. بسم الله.با حرکت سیستم‌ها به سمت معماری مایکروسرویس و Event-Driven، یکی از اولین مفاهیمی که به بن‌بست می‌رسد، «تراکنش» به معنای کلاسیک آن است. دیگر خبری از یک دیتابیس واحد و Transactionهای ACID نیست که بتوان با یک commit یا rollback همه‌چیز را کنترل کرد. در چنین فضایی، نیاز به الگویی داریم که بتواند تراکنش‌های بلندمدت و توزیع‌شده را مدیریت کند؛ جایی که چند سرویس مستقل باید در نهایت به یک نتیجه بیزینسی سازگار برسند. اینجاست که SAGA Pattern وارد می‌شود.SAGA صرفاً یک الگوی تئوریک نیست، بلکه ستون فقرات بسیاری از سیستم‌های بزرگ و واقعی است. در این مقاله، سعی خواهم کرد SAGA را عمیق، فنی و کاملاً عملی بررسی کنیم؛ از مدل ذهنی و مفاهیم پایه تا پیاده‌سازی واقعی با ابزارهایی مثل Axon Framework و دیگر ابزار ها. مسئولیت پوزیشن های مختلف رو هم درگیر خواهم کرد تا درک موضوع راحت تر بشه. یعنی مسئولیت های معمار و تحلیل گر نرم افزار رو به همراه مسئولیت های توسعه دهنده ها، معماران و ادمین های پایگاه داده و ... بررسی میکنیم.SAGA Patternمسئله اصلی؛ چرا Transaction کلاسیک جواب نمی‌دهد؟در یک سیستم توزیع‌شده، هر سرویس دیتابیس خودش را دارد. فرض کنید ثبت سفارش شامل چند مرحله است: ایجاد سفارش، پرداخت، رزرو موجودی و ارسال. هر کدام از این مراحل در سرویس جداگانه‌ای انجام می‌شود. اگر مرحله سوم شکست بخورد، دیگر نمی‌توان به‌سادگی Payment را rollback کرد، چون آن تراکنش مدت‌ها پیش commit شده است.استفاده از Distributed Transaction و Two-Phase Commit در تئوری ممکن است، اما در عمل باعث coupling شدید، کاهش availability و مشکلات جدی در scale می‌شود. اگر بخواهید، میتونید اطلاعات بیشتری در مورد این موضوعات (تئوری CAP در پایگاه داده) در این مقاله بخونید. SAGA دقیقاً برای حل این مشکل طراحی شده است.SAGA چیست؟ تعریف دقیق و فنیSAGA یک تراکنش بیزینسی بلندمدت است که از چندین Local Transaction تشکیل می‌شود. هر Local Transaction در محدوده یک سرویس اجرا می‌شود و دیتابیس همان سرویس را تغییر می‌دهد. اگر تمام مراحل با موفقیت انجام شوند، SAGA کامل می‌شود. اما اگر یکی از مراحل شکست بخورد، SAGA با اجرای Compensating Transaction‌ها، اثر مراحل قبلی را خنثی می‌کند.نکته کلیدی این است که Compensating Transaction الزاماً rollback فنی نیست، بلکه یک عملیات بیزینسی معکوس است. مثلاً Refund کردن پرداخت، نه undo کردن یک row در دیتابیس.مدل ذهنی SAGA؛ State Machine بیزینسیاز دید فنی، SAGA را می‌توان به‌عنوان یک State Machine در نظر گرفت. هر SAGA یک state دارد و با دریافت Eventها بین stateها جابه‌جا می‌شود. این state نشان‌دهنده پیشرفت فرآیند بیزینسی است، نه وضعیت دیتابیس.برای مثال، یک OrderSaga می‌تواند stateهایی مثل CREATED، PAID، INVENTORY_RESERVED و COMPLETED داشته باشد. هر transition با یک Event رخ می‌دهد و ممکن است باعث ارسال Command به سرویس دیگر شود.انواع SAGA؛ Orchestration در مقابل ChoreographySAGA معمولاً به دو سبک اصلی پیاده‌سازی می‌شود. در مدل Choreography، هیچ موجودیت مرکزی وجود ندارد. هر سرویس به Eventهای سایر سرویس‌ها گوش می‌دهد و بر اساس آن تصمیم می‌گیرد. این مدل ساده‌تر به نظر می‌رسد، اما با بزرگ شدن سیستم، جریان بیزینسی پراکنده و سخت‌قابل‌درک می‌شود.Choreography Based SAGAدر مقابل، مدل Orchestration یک Coordinator مرکزی دارد که معمولاً خود SAGA است. این Coordinator تصمیم می‌گیرد مرحله بعدی چیست و چه Commandی باید ارسال شود. این مدل کنترل، مانیتورینگ و Debug بهتری فراهم می‌کند و در سیستم‌های پیچیده انتخاب رایج‌تری است.Orchestration Based SAGASAGA و Event-Driven ArchitectureSAGA به‌شدت با Event-Driven Architecture گره خورده است. ارتباط بین مراحل SAGA معمولاً از طریق Event انجام می‌شود. یک سرویس پس از انجام Local Transaction، Event مربوطه را منتشر می‌کند و SAGA با دریافت آن Event تصمیم می‌گیرد قدم بعدی چیست.این رویکرد باعث loose coupling بین سرویس‌ها می‌شود و امکان scale مستقل هر سرویس را فراهم می‌کند.Compensating Transaction؛ قلب تحمل خطا در SAGAمهم‌ترین بخش SAGA، طراحی Compensating Transaction است. اگر این بخش به‌درستی طراحی نشود، کل SAGA عملاً بی‌معنا می‌شود. Compensating Transaction باید idempotent باشد و بتواند در شرایط retry و failure به‌درستی کار کند. اگر در مورد idempotency میخواهید اطلاعات بیشتری کسب کنید، در این مقاله، مفاهیم پایه رو مورد بررسی قرار دادیم.همچنین باید پذیرفت که SAGA معمولاً به Eventual Consistency می‌رسد، نه Consistency آنی. این یک trade-off آگاهانه برای دستیابی به availability و scalability است. پیاده‌سازی SAGA با Axon FrameworkAxon Framework یکی از فریم‌ورک‌هایی است که SAGA را به‌صورت first-class پشتیبانی می‌کند. در Axon، SAGA با annotation تعریف می‌شود و lifecycle آن بر اساس Eventها مدیریت می‌شود.هر SAGA instance معمولاً با یک Event شروع می‌شود، مثلاً Axon.OrderCreatedEvent .  این Event را با یک association key به SAGA متصل می‌کند. از آن لحظه به بعد، هر Event مرتبط می‌تواند state داخلی SAGA را تغییر دهد و باعث ارسال Command جدید شود.State داخلی SAGA می‌تواند در دیتابیس ذخیره شود یا حتی Event Sourced باشد، بسته به نیاز سیستم.مثال واقعی؛ Order Processing Sagaفرض کنید کاربر سفارشی ثبت می‌کند. OrderCreatedEvent منتشر می‌شود و OrderSaga شروع می‌شود. Saga با ارسال ProcessPaymentCommand پرداخت را آغاز می‌کند. اگر PaymentSucceededEvent دریافت شود، Saga وارد مرحله رزرو موجودی می‌شود. اگر PaymentFailedEvent رخ دهد، Saga مستقیماً پایان می‌یابد.اگر در مرحله رزرو موجودی خطا رخ دهد، Saga با ارسال RefundPaymentCommand اثر مرحله پرداخت را جبران می‌کند. در نهایت، سیستم بدون هیچ Transaction توزیع‌شده‌ای به وضعیت بیزینسی سازگار می‌رسد.Persistence و Reliability در SAGAاز آنجا که SAGA معمولاً طول عمر بالایی دارد، persistence آن حیاتی است. State SAGA باید بعد از crash یا restart سیستم قابل بازیابی باشد. بسیاری از فریم‌ورک‌ها، از جمله Axon، این persistence را به‌صورت built-in فراهم می‌کنند. همچنین Message Delivery باید حداقل once باشد و SAGA باید برای duplicate Eventها آماده باشد.چالش‌ها و Anti-PatternهاSAGA اگر اشتباه استفاده شود، می‌تواند به پیچیدگی بیش از حد منجر شود. استفاده از SAGA برای عملیات ساده، طراحی Compensating ضعیف یا تبدیل SAGA به God Object از جمله anti-pattern های رایج هستند.SAGA باید نماینده یک فرآیند بیزینسی مشخص باشد، نه جایگزین مستقیم Transaction دیتابیس.جمع‌بندیSAGA Pattern راه‌حل استاندارد و عملی برای مدیریت تراکنش‌های توزیع‌شده در سیستم‌های مدرن است. این الگو با پذیرش Eventual Consistency و استفاده از Compensating Transaction، امکان ساخت سیستم‌هایی scalable، resilient و قابل توسعه را فراهم می‌کند.اگر سیستم و پروژه ما شامل چند سرویس مستقل با فرآیندهای بیزینسی پیچیده است، SAGA نه یک انتخاب، بلکه یک ضرورت معماری است و معمار ما باید در مرحله معماری و تحلیل، اون رو در نظر بگیرد.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Wed, 11 Feb 2026 08:54:09 +0330</pubDate>
            </item>
                    <item>
                <title>اسناد SRS ،BRS و FRS در مهندسی نرم‌افزار</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%A7%D8%B3%D9%86%D8%A7%D8%AF-srs-brs-%D9%88-frs-%D8%AF%D8%B1-%D9%85%D9%87%D9%86%D8%AF%D8%B3%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-mshzwi9ccmhi</link>
                <description>سلام. اگر در فضای مهندسی نرم‌افزار، تحلیل سیستم یا مدیریت پروژه فعالیت داشته باشید، احتمالاً بارها با مفاهیمی مثل SRS، BRS و FRS مواجه شده‌اید. اسنادی که در تئوری نقش مشخص و تفکیک‌شده‌ای دارند، اما در عمل یا با یکدیگر اشتباه گرفته می‌شوند یا به‌دلیل محدودیت زمان و منابع، برخی از آن‌ها نادیده گرفته می‌شوند.در این مقاله تلاش خواهم کرد به این موضوع بپردازم که این سه سند چه هستند، چه تفاوت‌هایی با یکدیگر دارند و به‌طور خاص سند BRS چه نقشی در فرآیند نیازسنجی و امکان‌سنجی پیش از تدوین SRS ایفا می‌کند. هدف ارائه‌ی تعاریف صرفاً تئوریک نیست، بلکه تمرکز بر درک کاربردی این اسناد در پروژه‌های واقعی نرم‌افزاری است.بررسی، مطالعه، تحلیل و ایجاد اسناد و مستندسازی در مهندسی نرم افزارBRS؛ نقطه‌ی شروع درک نیاز کسب‌وکارBRS (Business Requirements Specification) معمولاً اولین سند رسمی در مسیر شکل‌گیری یک محصول نرم‌افزاری محسوب می‌شود. تمرکز این سند نه بر سیستم و جزئیات فنی، بلکه بر نیازهای کسب‌وکار است. BRS مشخص می‌کند چرا یک نرم‌افزار باید توسعه داده شود و قرار است چه مسئله‌ای را در سطح بیزنس حل کند.در این سند به موضوعاتی مانند اهداف کلان، چالش‌های فعلی کسب‌وکار، انتظارات ذی‌نفع‌ها و معیارهای موفقیت پروژه پرداخته می‌شود. زبان BRS عمداً غیر فنی انتخاب می‌شود تا مدیران، کارفرما و سایر تصمیم‌گیرندگان بتوانند بدون درگیری با اصطلاحات تخصصی، آن را بررسی و تأیید کنند.اهمیت BRS در این است که پایه‌ی اصلی نیازسنجی و امکان‌سنجی پروژه را شکل می‌دهد. در این مرحله مشخص می‌شود آیا نیاز مطرح‌شده واقعی است، آیا اجرای آن از نظر اقتصادی و عملی توجیه دارد و اولویت‌ها از دید کسب‌وکار چگونه تعریف می‌شوند. در بسیاری از پروژه‌ها، ضعف در BRS باعث می‌شود محصول نهایی از نظر فنی قابل قبول باشد، اما مسئله‌ی اصلی کسب‌وکار را به‌درستی پوشش ندهد.SRS؛ تبدیل نیاز بیزنس به نیازمندی نرم‌افزاریپس از شفاف شدن نیازهای کسب‌وکار در قالب BRS، نوبت به تدوین SRS (Software Requirements Specification) می‌رسد. این سند نقش پل ارتباطی بین دیدگاه بیزنس و تیم فنی را ایفا می‌کند.SRS به‌صورت دقیق مشخص می‌کند که سیستم نرم‌افزاری چه قابلیت‌هایی باید داشته باشد، چه رفتارهایی از آن انتظار می‌رود و چه محدودیت‌هایی بر آن حاکم است. در این مرحله وارد جزئیات می‌شویم، اما همچنان تلاش می‌شود نیازمندی‌ها تا حد امکان مستقل از تکنولوژی و پیاده‌سازی بیان شوند.یک SRS مناسب باید شفاف، بدون ابهام و قابل تست باشد؛ به‌گونه‌ای که تیم توسعه، تیم تست و حتی اعضای جدید پروژه بتوانند با مراجعه به آن، درک مشترکی از سیستم داشته باشند. اگر BRS پاسخ‌گوی «چرایی» پروژه باشد، SRS به «چیستی» سیستم پاسخ می‌دهد.FRS؛ تشریح دقیق رفتارهای عملکردیFRS (Functional Requirements Specification) سطح جزئی‌تری از نیازمندی‌ها را پوشش می‌دهد و معمولاً زمانی اهمیت بیشتری پیدا می‌کند که پروژه پیچیدگی بالاتری داشته باشد یا رفتار هر قابلیت نیاز به تشریح دقیق‌تری داشته باشد.در FRS، تمرکز بر نحوه‌ی عملکرد هر قابلیت است؛ از ورودی‌ها و خروجی‌ها گرفته تا قوانین اعتبارسنجی، سناریوها و وابستگی‌ها. مخاطب اصلی این سند توسعه‌دهندگان هستند و به همین دلیل زبان آن فنی‌تر و اجرایی‌تر است. در بسیاری از پروژه‌ها، FRS به‌عنوان سندی مجزا تدوین نمی‌شود و محتوای آن در قالب بخش‌های عملکردی SRS ارائه می‌گردد.نقش BRS پیش از تدوین SRSیکی از خطاهای رایج در پروژه‌های نرم‌افزاری، شروع مستقیم تدوین SRS بدون داشتن یک BRS دقیق و تأییدشده است. این موضوع معمولاً در ادامه‌ی پروژه باعث تغییرات گسترده، بازنگری نیازمندی‌ها و حتی اختلاف نظر میان ذی‌نفع‌ها و تیم فنی می‌شود.وجود BRS پیش از SRS کمک می‌کند نیازها از منظر کسب‌وکار به‌درستی تحلیل شوند، محدوده‌ی پروژه واقع‌بینانه تعریف شود و امکان‌سنجی فنی و اقتصادی در زمان مناسب انجام گیرد. به بیان ساده، BRS ریسک طراحی و پیاده‌سازی راه‌حل برای مسئله‌ای نادرست را به‌طور قابل توجهی کاهش می‌دهد.جمع‌بندیدر یک نگاه کلی می‌توان گفت BRS جهت و هدف پروژه را مشخص می‌کند، SRS چارچوب و قابلیت‌های سیستم را تعریف می‌کند و FRS به تشریح دقیق نحوه‌ی عملکرد این قابلیت‌ها می‌پردازد. هرچه پروژه بزرگ‌تر و پیچیده‌تر باشد، اهمیت تفکیک و تدوین صحیح این اسناد بیشتر می‌شود. اگرچه در پروژه‌های کوچک ممکن است برخی از این اسناد با یکدیگر ادغام شوند، اما حذف یا نادیده گرفتن BRS معمولاً ریسک‌های جدی در ادامه‌ی مسیر پروژه ایجاد می‌کند.</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Wed, 11 Feb 2026 07:36:19 +0330</pubDate>
            </item>
                    <item>
                <title>امکان‌سنجی و نیازسنجی در مهندسی نرم‌افزار</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%A7%D9%85%DA%A9%D8%A7%D9%86-%D8%B3%D9%86%D8%AC%DB%8C-%D9%88-%D9%86%DB%8C%D8%A7%D8%B2%D8%B3%D9%86%D8%AC%DB%8C-%D8%AF%D8%B1-%D9%85%D9%87%D9%86%D8%AF%D8%B3%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-ungkhflvusub</link>
                <description>چیزهایی که قبل از نوشتن SRS باید جدی بگیریمسلام عزیزان؛ تقریباً همه‌ی ما حداقل یک بار توی پروژه‌ای بودیم که خیلی پرانرژی شروع شد، اما وسط راه یا به بن‌بست خورد یا محصول نهایی چیزی نبود که کارفرما واقعاً می‌خواست. جالب اینجاست که در بیشتر این شکست‌ها مشکل نه تکنولوژی بوده، نه تیم، نه حتی زمان‌بندی؛ مشکل از خیلی قبل‌تر شروع شده، جایی قبل از اینکه حتی یک خط از سند SRS نوشته شود. جایی به نام «نیازسنجی و امکان‌سنجی».فرایند امکان‌سنجی و نیازسنجی در مهندسی نرم‌افزاردر مهندسی نرم‌افزار، قبل از اینکه وارد فاز تحلیل رسمی نیازمندی‌ها بشویم، معمار و تحلیل‌گر نرم‌افزار باید یک قدم عقب‌تر بایستند و از خودشان بپرسند: آیا اصلاً این پروژه شدنی است؟ و اگر شدنی است، دقیقاً چه نیازی قرار است برطرف شود؟ این دو سؤال ساده، هسته‌ی اصلی امکان‌سنجی و نیازسنجی را تشکیل می‌دهند، اما پاسخ دادن به آن‌ها اصلاً ساده نیست.نیازسنجی، برخلاف تصور رایج، فقط لیست کردن خواسته‌های کارفرما نیست. خیلی وقت‌ها چیزی که کارفرما بیان می‌کند، راه‌حل ذهنی اوست نه مسئله‌ی واقعی. اینجاست که نقش تحلیل‌گر نرم‌افزار پررنگ می‌شود؛ کسی که بتواند با سؤال‌های درست، گفتگوهای هدفمند و حتی گاهی به چالش کشیدن فرضیات اولیه، به نیاز واقعی کسب‌وکار برسد. نیازی که اگر درست فهمیده نشود، بهترین SRS دنیا هم فقط یک سند خوش‌فرم ولی بی‌خاصیت خواهد بود.از آن طرف، امکان‌سنجی بیشتر به زمین واقعیت‌ها وصل است. اینکه آیا با منابع فعلی، محدودیت‌های زمانی، بودجه، تیم، فناوری و زیرساخت موجود، می‌توان این نیاز را به یک محصول قابل استفاده تبدیل کرد یا نه. معمار نرم‌افزار اینجا نقش کلیدی دارد؛ کسی که باید تصویر کلان سیستم را ببیند و تشخیص دهد آیا این ایده با این شرایط، عملی است یا فقط روی کاغذ قشنگ به نظر می‌رسد.نکته‌ی مهم اینجاست که امکان‌سنجی و نیازسنجی کاملاً به هم گره خورده‌اند. گاهی در فرآیند امکان‌سنجی مشخص می‌شود که بخشی از نیازها باید بازتعریف شوند، ساده‌تر شوند یا حتی حذف شوند. این اتفاق نه شکست است و نه عقب‌گرد؛ اتفاقاً نشانه‌ی یک فرآیند بالغ و حرفه‌ای است که قبل از ورود به فاز تولید، جلوی هزینه‌های سنگین آینده را می‌گیرد.قبل از تولید SRS، تحلیل‌گر و معمار نرم‌افزار باید به یک درک مشترک با ذی‌نفعان برسند. درکی که فقط شامل «چه چیزی بسازیم» نباشد، بلکه «چرا می‌سازیم»، «برای چه کسی»، و «با چه محدودیت‌هایی» را هم پوشش دهد. اگر این لایه‌ی مفهومی شکل نگیرد، SRS بیشتر شبیه ترجمه‌ی عجولانه‌ی حرف‌ها می‌شود تا یک سند مهندسی.واقعیت این است که خیلی از مشکلات پروژه‌ها نه در کدنویسی، نه در تست، بلکه در همین فاز خاکستریِ قبل از SRS شکل می‌گیرند. فازی که معمولاً عجله داریم زود از آن رد شویم تا برسیم به بخش‌های «باحال‌تر» پروژه. اما تجربه نشان داده هر ساعتی که اینجا با دقت و حوصله صرف شود، می‌تواند ده‌ها ساعت دوباره‌کاری و تنش را در ادامه‌ی مسیر کم کند.در نهایت، امکان‌سنجی و نیازسنجی بیشتر از اینکه یک فعالیت مستندسازی باشند، یک فعالیت انسانی‌اند. پر از گفتگو، شنیدن، تحلیل، تردید و تصمیم‌گیری. شاید به همین دلیل است که هیچ وقت نمی‌شود آن‌ها را کاملاً به یک قالب یا چک‌لیست خشک محدود کرد. اینجا جایی است که مهندسی نرم‌افزار، واقعاً مهندسی می‌شود؛ ترکیبی از منطق، تجربه و درک انسان‌ها.برای ملموس‌تر شدن نقش امکان‌سنجی و نیازسنجی، بد نیست به دو سناریوی رایج در دنیای واقعی نگاه کنیم؛ سناریوهایی که تقریباً همه‌ی ما حداقل یکی از آن‌ها را تجربه کرده‌ایم.در سناریوی اول؛کارفرما یک موجود بیرونی است؛ یک سازمان، استارتاپ یا کسب‌وکار که با یک ایده یا درخواست سراغ تیم نرم‌افزاری می‌آید. معمولاً کارفرما با یک تصویر ذهنی نسبتاً مشخص وارد می‌شود: «یک سیستم شبیه فلان»، «یک اپ مثل بهمان» یا «چیزی که این مشکل را حل کند». در این حالت، اگر تیم تحلیل بدون نیازسنجی عمیق وارد نوشتن SRS شود، احتمال زیادی وجود دارد که سند نهایی صرفاً بازنویسی خواسته‌های اولیه‌ی کارفرما باشد، نه بازتاب نیاز واقعی او.اینجا نیازسنجی یعنی کشف مسئله‌ی اصلی پشت درخواست. شاید کارفرما اپلیکیشن می‌خواهد، اما مشکل واقعی‌اش فرآیند ناکارآمد داخلی است. شاید داشبورد مدیریتی می‌خواهد، اما داده‌ی قابل اتکا ندارد. هم‌زمان، امکان‌سنجی هم وارد بازی می‌شود؛ اینکه آیا با بودجه، زمان و سطح بلوغ سازمان کارفرما، پیاده‌سازی چنین سیستمی منطقی است یا نه. خیلی وقت‌ها خروجی درست این فاز، حتی می‌تواند پیشنهاد یک راه‌حل ساده‌تر یا فازبندی پروژه باشد، چیزی که اگر بعداً و وسط توسعه کشف شود، هزینه‌اش چند برابر خواهد بود.در سناریوی دوم؛کارفرما خود شرکت است؛ یعنی تیم نرم‌افزار قرار است روی یک محصول داخلی یا یک محصول بازارمحور کار کند. در نگاه اول ممکن است فکر کنیم نیازسنجی اینجا ساده‌تر است، چون «خودمان هستیم و خودمان». اما تجربه نشان داده این سناریو گاهی حتی پیچیده‌تر هم می‌شود. چون فرضیات نانوشته زیادند و همه فکر می‌کنند بقیه دقیقاً همان چیزی را می‌فهمند که خودشان در ذهن دارند.در این حالت، نیازسنجی بیشتر به شفاف‌سازی دیدگاه‌ها برمی‌گردد. اینکه این محصول دقیقاً چه مشکلی را حل می‌کند، مخاطب اصلی‌اش کیست، و قرار است چه ارزشی ایجاد کند. امکان‌سنجی هم فقط فنی نیست؛ باید دید آیا این محصول با استراتژی شرکت هم‌راستاست، آیا منابع انسانی لازم برای نگه‌داری آن در بلندمدت وجود دارد، و آیا زمان ورود به بازار منطقی انتخاب شده یا نه. خیلی از محصول‌های داخلی شکست می‌خورند نه به‌خاطر بد بودن ایده، بلکه چون این سؤال‌ها قبل از شروع جدی گرفته نشده‌اند.در هر دو سناریو، یک نکته مشترک وجود دارد:اگر امکان‌سنجی و نیازسنجی به‌درستی انجام نشوند، SRS بیشتر شبیه یک تعهدنامه‌ی پرریسک می‌شود تا یک سند راهنما. اما اگر این فاز با دقت و گفت‌وگوی واقعی جلو برود، SRS می‌تواند نتیجه‌ی یک فهم مشترک و محکم باشد؛ فهمی که هم تیم فنی و هم ذی‌نفعان روی آن ایستاده‌اند.این همه از اسناد SRS صحبت کردیم باهم. معماران و تحلیل گران عزیز میدانند؛ ما یکسری اسناد دیگری داریم تحت عناوین BRS و FRS که به نوعی در فرایند امکان سنجی و نیازسنجی تولید میشوند. در این مقاله بیشتر در مورد این اسناد و مقایسه اونها صحبت کردم.امیدوارم مفید بوده باشه ...</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Wed, 11 Feb 2026 07:13:08 +0330</pubDate>
            </item>
                    <item>
                <title>تفاوت REST، gRPC و GraphQL</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%D8%AA%D9%81%D8%A7%D9%88%D8%AA-rest-grpc-%D9%88-graphql-o4ilqsl2p8qx</link>
                <description>کدام معماری API برای ما مناسب‌تر است؟اگر چند سالی است که با توسعه‌ی نرم‌افزار، مخصوصاً بک‌اند یا سیستم‌های توزیع‌شده سر و کار دارید، احتمالاً اسم REST، GraphQL و gRPC بارها به گوشتان خورده است. بعضی وقت‌ها حتی این سؤال پیش می‌آید که «خب، همه‌شون API هستن، دقیقاً فرقشون چیه؟» یا «آیا GraphQL قراره جای REST رو بگیره؟» یا «gRPC اصلاً به درد وب می‌خوره یا فقط برای سیستم‌های خاصه؟»در این مقاله سعی می‌کنم بدون اغراق، اما عمیق و فنی، این سه رویکرد را بررسی کنم؛ از فلسفه‌ی طراحی گرفته تا جزئیات فنی، مزایا، محدودیت‌ها و سناریوهای واقعی استفاده.Rest | graphQL | gRPCREST؛ استاندارد قدیمی، سادهREST یا Representational State Transfer در اصل یک سبک معماری است، نه یک تکنولوژی مشخص. یعنی REST به شما نمی‌گوید حتماً از چه کتابخانه یا پروتکلی استفاده کنید، بلکه یک سری اصول و قرارداد تعریف می‌کند برای این‌که کلاینت و سرور بتوانند به شکل ساده و قابل پیش‌بینی با هم حرف بزنند.در REST همه‌چیز حول مفهوم «Resource» می‌چرخد. شما یک منبع دارید، مثلاً user یا order، و این منبع از طریق URL قابل دسترسی است. عملیات‌ها هم معمولاً با HTTP Methodها مشخص می‌شوند؛ GET برای خواندن، POST برای ساختن، PUT/PATCH برای به‌روزرسانی و DELETE برای حذف. این سادگی باعث شده REST به انتخاب پیش‌فرض دنیای وب تبدیل شود.از نظر فنی، REST معمولاً روی HTTP/1.1 یا HTTP/2 پیاده‌سازی می‌شود و رایج‌ترین فرمت تبادل داده هم JSON است. همین انتخاب‌ها باعث شده REST بسیار قابل دیباگ باشد؛ شما به‌راحتی می‌توانید با curl یا Postman درخواست بزنید، پاسخ را ببینید و حتی در مرورگر تستش کنید.اما همین سادگی، محدودیت‌هایی هم ایجاد می‌کند. یکی از مشکلات معروف REST مسئله‌ی Over-fetching و Under-fetching است. یعنی یا دیتای بیشتری از نیازتان می‌گیرید یا مجبور می‌شوید برای گرفتن یک داده‌ی کامل، چندین درخواست مختلف بفرستید. مخصوصاً در اپلیکیشن‌های موبایل یا فرانت‌اندهای پیچیده، این موضوع می‌تواند آزاردهنده باشد.از نظر نسخه‌بندی هم REST معمولاً به ورژن‌بندی در URL یا Header متکی است (مثلاً /v1/users). این کار جواب می‌دهد، اما وقتی API بزرگ می‌شود، مدیریت نسخه‌ها می‌تواند پیچیده شود.به طور خلاصه REST هنوز هم انتخاب بسیار خوبی است وقتی:API ساده و قابل فهم میخواهیم درست کنیمبا وب و HTTP سر و کار داریمتیم بزرگ است و خوانایی و استاندارد مهم استPerformance خیلی بحرانی نیستمثال REST APIفرض کنیم یک API ساده با Node.js و Express داریم.EndpointGET /users/:id
پیاده‌سازی سمت سرورimport express from &quot;express&quot;;

const app = express();

app.get(&quot;/users/:id&quot;, (req, res) =&gt; {
  const userId = req.params.id;

  // این رو فرض کنیم دیتابیسه برگردونده برامون
  const user = {
    id: userId,
    name: &quot;Mojtaba&quot;,
    email: &quot;mojtaba@example.com&quot;,
    age: 35,
    posts: 15
  };

  res.json(user);
});

app.listen(3000, () =&gt; {
  console.log(&quot;REST API running on port 3000&quot;);
});
درخواست از سمت کلاینتGET /users/1 HTTP/1.1
Host: api.example.comپاسخ{
  &quot;id&quot;: &quot;1&quot;,
  &quot;name&quot;: &quot;Mojtaba&quot;,
  &quot;email&quot;: &quot;Mojtaba@example.com&quot;,
  &quot;age&quot;: 35,
  &quot;posts&quot;: 15
}در REST، شکل پاسخ توسط سرور تعیین میشه. حتی اگر کلاینت فقط name و email را بخواهد، کل آبجکت برمیگرده.GraphQL؛ کنترل کامل داده در دست کلاینتGraphQL توسط فیسبوک معرفی شد تا یکی از مشکلات اساسی REST را حل کند:این‌که کلاینت دقیقاً همان دیتایی را بگیرد که نیاز دارد، نه بیشتر و نه کمتر.در GraphQL برخلاف REST، ما چند endpoint مختلف نداریم؛ معمولاً فقط یک endpoint وجود دارد. کلاینت داخل request خودش مشخص می‌کند چه فیلدهایی را از چه آبجکت‌هایی می‌خواهد. سرور هم دقیقاً همان ساختار را برمی‌گرداند.این رویکرد از نظر تجربه‌ی توسعه، مخصوصاً در فرانت‌اند، فوق‌العاده هستش. فرانت‌اند دیگر وابسته به تصمیم‌های بک‌اند درباره‌ی شکل response نیست. اگر فردا نیاز به یک فیلد جدید داشته باشیم، کافی است query را تغییر دهیم، بدون این‌که API جدیدی ساخته شود. (این از نظر تجربی خیلی موضوع مهمی است)GraphQL یک Schema strongly typed دارد. یعنی از قبل مشخص است چه typeهایی داریم، چه فیلدهایی، چه ورودی‌هایی و چه خروجی‌هایی. همین موضوع باعث می‌شود tooling خیلی قوی‌ای شکل بگیرد؛ از auto-complete در IDE گرفته تا validation قبل از اجرا و هر آن چیزی که جریان ما رو تحت تاثیر بتونه قرار بده.اما این قدرت، هزینه هم داره. پیاده‌سازی GraphQL در بک‌اند معمولاً پیچیده‌تر از REST است. باید حواسمون به performance باشه، چون یک query بد میتونه منجر به تعداد زیادی call به دیتابیس بشه (مشکل معروف N+1). این مشکل رو در گروه فنی تلگرامی Dev Experience (@devexperiences) شرح دادم. همچنین caching در GraphQL برخلاف REST که روی HTTP Cache سوار می‌شود، نیاز به راهکارهای اختصاصی دارد. (در مقاله بعدی بیشتر بهش خواهم پرداخت موضوع کش رو)از نظر امنیت هم باید دقت بیشتری کرد؛ چون کلاینت می‌تواند queryهای پیچیده بنویسد، معمولاً محدودیت عمق (query depth) یا complexity تعریف می‌شود.GraphQL انتخاب مناسبی است وقتی:فرانت‌اند پیچیده و پویا داریمچند کلاینت مختلف (وب، موبایل و ...) داریمتغییرات مداوم در نیازهای داده وجود داردتیم توان مدیریت پیچیدگی بک‌اند را داردمثال GraphQLدر GraphQL همان سناریو قبلی که نوشیم واسه REST را داریم، اما کنترل داده دست کلاینت هستش.Schemaimport { buildSchema } from &quot;graphql&quot;;

export const schema = buildSchema(`
  type User {
    id: ID!
    name: String!
    email: String!
    age: Int
    posts: Int
  }

  type Query {
    user(id: ID!): User
  }
`);
Resolverexport const root = {
  user: ({ id }) =&gt; {
    return {
      id,
      name: &quot;Mojtaba&quot;,
      email: &quot;mojtaba@example.com&quot;,
      age: 35,
      posts: 15
    };
  }
};
Query از سمت کلاینتquery {
  user(id: &quot;1&quot;) {
    name
    email
  }
}
پاسخ{
  &quot;data&quot;: {
    &quot;user&quot;: {
      &quot;name&quot;: &quot;Mojtaba&quot;,
      &quot;email&quot;: &quot;mojtaba@example.com&quot;
    }
  }
}
اینجا دقیقاً همان چیزی که درخواست شده برگشته؛نه age داریم، نه posts.این همان جایی هست که GraphQL مشکل over-fetching را حل می‌کند.gRPC؛ ارتباط سریع، فشرده و مخصوص سیستم‌های توزیع‌شدهgRPC بیشتر از این‌که برای وب عمومی طراحی شده باشد، برای ارتباط بین سرویس‌ها (Microservices) ساخته شده است. این تکنولوژی توسط گوگل توسعه داده شده و تمرکز اصلی‌اش روی performance، type safety و ارتباطات پایدار است.gRPC به‌جای JSON از Protocol Buffers (Protobuf) استفاده می‌کند؛ یک فرمت باینری فشرده و بسیار سریع. قرارداد ارتباطی (Service و Messageها) در فایل‌های .proto تعریف می‌شود و بعد از روی آن‌ها کد کلاینت و سرور به زبان‌های مختلف به‌صورت خودکار تولید می‌شود.از نظر شبکه، gRPC روی HTTP/2 سوار است و قابلیت‌هایی مثل multiplexing، streaming (یک‌طرفه یا دوطرفه) و connection پایدار را به‌صورت built-in دارد. این ویژگی‌ها باعث می‌شود gRPC برای سیستم‌هایی با latency بالا یا حجم بالای درخواست فوق‌العاده باشد.اما gRPC برای استفاده‌ی مستقیم در مرورگر محدودیت دارد. مرورگرها به‌صورت native از gRPC پشتیبانی نمی‌کنند (مگر با gRPC-Web که خودش داستان جداگانه‌ای داره و باید در یک پست دیگه حتما راجبش بحث و گفتگو کنیم). همچنین دیباگ کردن gRPC نسبت به REST سخت‌تر است؛ چون داده‌ها باینری هستند و با چشم دیده نمی‌شوند.gRPC معمولاً انتخاب اول نیست برای public API، اما برای ارتباط داخلی بین سرویس‌ها بسیار محبوب است.gRPC بهترین گزینه است وقتی:Performance و latency حیاتی هست برامونمعماری Microservice داریم و یا حداقل شبه میکروسرویسارتباط server-to-server داریم در پروژهtype safety و قرارداد مشخص مهم است برامونمثال gRPCدر gRPC اول قرارداد ارتباطی را تعریف می‌کنیم و بعد از روی آن کد تولید می‌شود.فایل protosyntax = &quot;proto3&quot;;

package user;

service UserService {
  rpc GetUser (UserRequest) returns (UserResponse);
}

message UserRequest {
  string id = 1;
}

message UserResponse {
  string id = 1;
  string name = 2;
  string email = 3;
  int32 age = 4;
  int32 posts = 5;
}
پیاده‌سازی سرور (Node.js)import grpc from &quot;@grpc/grpc-js&quot;;
import protoLoader from &quot;@grpc/proto-loader&quot;;

const packageDefinition = protoLoader.loadSync(&quot;user.proto&quot;);
const userProto = grpc.loadPackageDefinition(packageDefinition).user;

function getUser(call, callback) {
  callback(null, {
    id: call.request.id,
    name: &quot;Mojtaba&quot;,
    email: &quot;mojtaba@example.com&quot;,
    age: 35,
    posts: 15
  });
}

const server = new grpc.Server();
server.addService(userProto.UserService.service, { getUser });

server.bindAsync(
  &quot;0.0.0.0:50051&quot;,
  grpc.ServerCredentials.createInsecure(),
  () =&gt; server.start()
);
کلاینت gRPCconst client = new userProto.UserService(
  &quot;localhost:50051&quot;,
  grpc.credentials.createInsecure()
);

client.getUser({ id: &quot;1&quot; }, (err, response) =&gt; {
  console.log(response);
});
پاسخ (باینری در شبکه، ولی آبجکت در کد){
  id: &#039;1&#039;,
  name: &#039;Mojtaba&#039;,
  email: &#039;mojtaba@example.com&#039;,
  age: 35,
  posts: 15
}
در gRPC:قرارداد کاملاً type-safe استدیتا باینری و بسیار سریع منتقل می‌شودمناسب ارتباط service-to-service است، نه مصرف مستقیم در مرورگرمن اگر بخوام جمع کنم موضوع رو ...واقعیت این است که هیچ‌کدام «بهتر مطلق» نیستند. REST، GraphQL و gRPC هر کدام برای مسئله‌ای خاص طراحی شده. خیلی از سیستم‌های حرفه‌ای امروزی حتی از ترکیب این‌ها استفاده می‌کنند؛ مثلاً GraphQL برای فرانت‌اند، gRPC برای ارتباط داخلی سرویس‌ها و REST برای APIهای عمومی.سؤال اصلی همیشه این است:مسئله‌ی من چیست و کدام ابزار بهترین پاسخ را می‌دهد؟اگر این سؤال را درست بپرسیم، انتخاب معماری API هم معمولاً خودش را نشان می‌دهد.REST: ساده، خوانا، مناسب APIهای عمومیGraphQL: انعطاف‌پذیر، کلاینت‌محور، مناسب فرانت‌اندهای پیچیدهgRPC: سریع، تایپ‌سیف، عالی برای میکروسرویس‌ها</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Tue, 03 Feb 2026 14:31:07 +0330</pubDate>
            </item>
                    <item>
                <title>کلاس‌های Rich و Anemic؛ وقتی کلاس فقط نگهدارنده دیتا نیست</title>
                <link>https://virgool.io/@s.mojtaba-hashemi/%DA%A9%D9%84%D8%A7%D8%B3-%D9%87%D8%A7%DB%8C-rich-%D9%88-anemic-%D9%88%D9%82%D8%AA%DB%8C-%DA%A9%D9%84%D8%A7%D8%B3-%D9%81%D9%82%D8%B7-%D9%86%DA%AF%D9%87%D8%AF%D8%A7%D8%B1%D9%86%D8%AF%D9%87-%D8%AF%DB%8C%D8%AA%D8%A7-%D9%86%DB%8C%D8%B3%D8%AA-wy7ulaslwg5p</link>
                <description>سلام؛ اگر مدتی با برنامه‌نویسی شی‌گرا کار کرده باشیم، احتمالاً به کلاس‌هایی برخورد کردیم که فقط چند تا فیلد دارن و کلی getter و setter. این کلاس‌ها معمولاً هیچ تصمیمی نمی‌گیرن، هیچ رفتاری ندارن و صرفاً یه بسته برای جابه‌جایی دیتا هستن. اینجاست که ناخودآگاه این سؤال پیش میاد که آیا این چیزی که نوشتیم واقعاً یه «شیء» به حساب میاد یا نه؟ بحث کلاس‌های Anemic و Rich دقیقاً از همین نقطه شروع میشه.Rich vs Anemic | OOP &amp; DDD Conceptsدر این مقاله، به این موضوع خواهیم پرداخت و اساساً بررسی میکنیم که ویژگی های این دو جریان چه تاثیری در کل سیستم خواهند داشت. بریم سراغ اصل مطلب.ابتدا میخوام این موضوع رو باهم داشته باشیم که واژه های Rich و Anemic برای توصیف وضعیت یک کلاس به کاربرده میشه. اگر کلاس ما بسیار ساده و صرفا دارای property و getter setter باشه (همون موضوعی که در اول مقاله بیان شد) میگیم کلاسه Anemic هست ولی در مقابل اگر کلاس ما دارای منطق باشه و این منطق ها رو از طریق متد ها بیاییم و داخل کلاس بنویسیم، این کلاس میشه Rich. حالا بریم دقیق تر بررسی کنیم ببینیم یعنی چی این موضوع.Anemic Model؛ کلاس‌هایی که کم‌خون شدن 😄همون طور که گفتیم، Anemic Model به مدلی گفته میشه که توش کلاس‌ها تقریباً هیچ منطق خاصی ندارن. مسئولیتشون فقط نگهداری داده‌ست و تمام قوانین و تصمیم‌ها میرن توی سرویس‌ها. در ظاهر شاید تمیز به نظر بیاد، اما کم‌کم ساختار کد از شی‌گرایی فاصله می‌گیره.مثلاً یه کلاس حساب بانکی رو در نظر بگیریم که فقط موجودی رو نگه می‌داره و هیچ ایده‌ای نداره برداشت پول یعنی چی:class BankAccount {
     private int balance;

     public int getBalance() {
         return balance;
     }

     public void setBalance(int balance) {
         this.balance = balance; 
    } 
} میاییم و میگیم، منطق برداشت پول جایی بیرون از خود حساب خواهیم نوشت:class BankAccountService { 
     
     public void withdraw(BankAccount account, int amount) {
         if (amount &lt;= 0) {
             throw new IllegalArgumentException();
         }

         if (account.getBalance() &lt; amount) {
             throw new RuntimeException(&quot;Not enough balance&quot;);
         }

          account.setBalance(account.getBalance() - amount);
     }
 } در این حالت، کلاس BankAccount هیچ کنترلی روی وضعیت خودش نداره. هر جایی از سیستم می‌تونه موجودی رو مستقیم تغییر بده، بدون اینکه قوانین رعایت بشه. این مدل طراحی کم‌کم باعث میشه منطق دامنه پخش بشه و کد بیشتر شبیه برنامه‌نویسی رویه‌ای بشه تا شی‌گرا. (معمار هامون باید دقت داشته باشند در اینجا که اول کار، چه تصمیمی گرفته میشه و به برنامه نویس ها و توسعه دهنده ها ابلاغ میشه)Rich Model؛ وقتی شیء مسئول خودش استدر مقابل Anemic Model، رویکرد Rich Model قرار داره. توی این مدل، کلاس‌ها فقط نگهدارنده‌ی دیتا نیستن؛ بلکه رفتار و قوانین مربوط به خودشون رو هم می‌شناسن و اجرا می‌کنن. یعنی هر شیء مسئول اینه که اجازه نده به وضعیت نامعتبر بره.همون مثال حساب بانکی رو این بار به شکل Rich ببینیم:class BankAccount {
     private int balance;

     public BankAccount(int initialBalance) {
         if (initialBalance &lt; 0) {
             throw new IllegalArgumentException();
         }

         this.balance = initialBalance;
     }

     public void withdraw(int amount) {
         if (amount &lt;= 0) {
             throw new IllegalArgumentException();
         }

         if (balance &lt; amount) {
             throw new RuntimeException(&quot;Not enough balance&quot;);
         }

         balance -= amount;
     }

     public int getBalance() {
         return balance;
     }
 } اینجا حساب بانکی خودش می‌دونه برداشت پول یعنی چی و چه قوانینی داره. سرویس فقط هماهنگ‌کننده‌ست و کار خاصی جز صدا زدن متد انجام نمی‌ده. نتیجه کدی میشه که هم خواناتر و هم امن‌تره.چرا با وجود این همه ایراد، Anemic Model هنوز استفاده میشه؟واقعیت اینه که Anemic Model خیلی وقت‌ها انتخاب بدی نیست. فریم‌ورک‌هایی مثل Spring و JPA (من خودم جاوایی ام چون 😄) به‌طور ناخودآگاه ما رو به این سمت هل میدن. از طرفی برای پروژه‌های ساده‌ی CRUD، این مدل سریع‌تر جواب می‌ده و پیچیدگی ذهنی کمتری داره. اما مشکل معمولاً از جایی شروع میشه که پروژه رشد می‌کنه، قوانین بیشتر میشن و منطق دامنه پیچیده‌تر میشه. اون موقع سرویس‌ها چاق میشن، کلاس‌ها لاغر می‌مونن و تغییر دادن قوانین تبدیل به کار پرریسکی میشه. (همون طور که بالا هم گفتم، معمار ما باید اول کار، تصمیم درست رو بگیره و بر اساس استک و وضعیت کلی پروژه، بدونه که رویکرد ما در پروژه نسبت به کلاس هامون، چی خواهد بود)Rich Model و ارتباطش با DDDاگه با Domain-Driven Design آشنا باشیم، احتمالاً شنیدیم که میگن موجودیت‌ها باید «رفتار» داشته باشن. Rich Model دقیقاً با همین طرز فکر هم‌راستاست. توی این رویکرد، entityها مسئول حفظ invariantها هستن و اجازه نمیدن سیستم وارد وضعیت اشتباه بشه. اگر با کلید واژه های DDD آشنا نیستی، یه سر به اینجا بزن.یرای مثال، فعال‌سازی یک کاربر بهتره تصمیم خود کاربر باشه، نه یه سرویس بیرونی که هر کاری دلش خواست با وضعیتش بکنه. بریم این رو یه کد برنیم و ببینیم چی به چی هست ...این کلاس ما الان یک کلاس Anemic هست که منطق اون در یه سرویس بیرونی هست:class User {
    private String email;
    private boolean active;

    // getter &amp; setter

}class UserService {
    public void activate(User user) {

        if (user.isActive()) {

            throw new RuntimeException(&quot;Already active&quot;);
        }

        user.setActive(true);
    }
}تغییر رویکرد میدیم و اون رو به Rich تبدیل میکنیم:class User {
    private String email;
    private boolean active;

    public void activate() {

        if (active) {

            throw new RuntimeException(&quot;Already active&quot;);
        }

        active = true;
    }
}جمع‌بندیدر نهایت، Rich و Anemic بیشتر از اینکه خوب یا بد مطلق باشن، دو تا انتخاب طراحی هستن که باید با توجه به نیاز پروژه انتخاب بشن: Anemic Model برای پروژه‌های ساده و دیتامحور می‌تونه کافی و حتی منطقی باشه Rich Model وقتی ارزش خودش رو نشون می‌ده که منطق دامنه مهمه و قراره سیستم در طول زمان رشد کنه اگه قراره فقط دیتا جابه‌جا کنی، Anemic اذیتت نمی‌کنه. ولی اگه قراره منطق بسازی، قوانین رو نگه داری و سیستم قابل توسعه داشته باشی، Rich Model انتخاب عاقلانه‌تریه.در مقالات بعدی، بیشتر در مورد این مفاهیم صحبت خواهیم کرد ...</description>
                <category>میر مجتبی هاشمی جنتی</category>
                <author>میر مجتبی هاشمی جنتی</author>
                <pubDate>Sun, 25 Jan 2026 07:31:17 +0330</pubDate>
            </item>
            </channel>
</rss>