<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های Saeid Noormohammadi</title>
        <link>https://virgool.io/feed/@heysaeid92</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-14 19:15:48</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3535170/avatar/3OkfDb.jpg?height=120&amp;width=120</url>
            <title>Saeid Noormohammadi</title>
            <link>https://virgool.io/@heysaeid92</link>
        </image>

                    <item>
                <title>نگاهی به تغییرات مهم Apache Kafka 4.1</title>
                <link>https://virgool.io/@heysaeid92/%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D9%87-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-%D9%85%D9%87%D9%85-apache-kafka-41-ixxulmkl2tse</link>
                <description>چند وقت پیش بود که درباره تغییرات مهم نسخه 4.0 کافکا نوشتم. از حذف وابستگی به ZooKeeper با پیش‌فرض شدن KRaft گرفته تا بهبود پروتکل Consumer Group تو KIP-848 و معرفی اولیه Queues for Kafka تو KIP-932. حالا تقریبا یک ماهی میشه که نسخه 4.1.0 Kafka اومده و یک سری بهبودهای کاربردی داشته که نمیشه به‌ راحتی ازشون گذشت. تو این مطلب میخوایم مهم‌ترین تغییرات این نسخه رو باهم مرور کنیم.۱. Queues for Kafka (KIP-932): یه قدم به جلوتو نسخه 4.0 قابلیت Queues for Kafka تو KIP-932 معرفی شد و حالا تو 4.1 به حالت preview رسیده. اما هنوز برای استفاده تو محیط‌ های پروداکشن آماده نیستش، ولی میتونیم کار باهاش رو شروع و تستش کنیم. این بهمون اجازه میده که shared group ها را بر روی تاپیک ها تعریف و استفاده کنیم.۲. پروتکل جدید Streams Rebalance (KIP-1071)یکی از تغییرات جذاب این نسخه معرفی پروتکل Streams Rebalance تو KIP-1071 هستش که هنوز تو فاز early access. به صورت کلی این پروتکل رو پایه KIP-848 ساخته شده و تمرکزش رو بهبود تخصیص تسک ها و مدیریت تاپیک های داخلی تو Kafka Streams هستش. به زبون ساده یعنی هماهنگی بین تسک ها حالا ساده تر و بهتر انجام میشه. البته هنوز برای محیط پروداکشن پیشنهاد  نمیشه.۳. Mechanism for plugins and connectors to register metrics (KIP-877)یه تغییر کاربردی دیگه امکان ثبت متریک های سفارشی برای پلاگین ها و کانکتورها از طریق اینترفیس Monitorable هستش. حالا کلاینت های Produce,  Consumer و Admin راحت تر میتونن متریک‌های خودشون رو ثبت کنن. این متریک ها با تگ های مشخص پلاگین به صورت خودکار اینجکت میشن و با فرمتkafka.CLIENT:type=plugins نمایش داده میشن.۴. Consistent error handling for Transactions (KIP-1050)یک کار خوب دیگه ای که انجام شده، اومدن تو KIP-1050 لاجیک مدیریت خطاها تو AP های مربوط به transactions ها رو آپدیت کردن. یعنی اینکه الان یک چارچوب یکپارچه برای مدیریت خطاهای transaction ها داریم.۵. Extend Consumer#close with an option to leave the group or not (KIP-1092)تغییر بعدی تو این نسخه اضافه شدن متد Consumer.close(CloseOptions) هستش که بهمون اجازه میده مشخص کنیم consumer موقع بسته شدن از گروهش خارج بشه یا نه. این برای Kafka Streams خیلی کاربردی هستش. به کمکش میتونیم به شکل بهتری زمان بندی rebalance رو کنترل کنیم. و اینکه متد قدیمی Consumer.close(Duration) دپریکیت شده، پس بهتره به متد جدید مهاجرت کنیم.۶. Trigger rebalance on rack topology changes (KIP-1101)KIP-1101 هم اومده تخصیص پارتیشن های حساس به Rack رو بهینه تر کرده و مصرف حافظه رو به شکل خوبی پایین آورده. حالا میتونیم تو consumer group ها بدون نگرانی از محدودیت های حافظه تعداد زیادی عضو داشته باشیم که تو سیستم های بزرگ خیلی به کار میاد.۷. Unifying Kafka Consumer Topic Metrics (KIP-1109)قبلا متریک های تاپیک ها تو consumer ها نقطه های اسم تاپیک رو با underline تغییر میدان که خب بعضی وقت ها باعث گیج شدن میشد. تو 4.1 این مورد تغییر کرده و متریک ها با اسم اصلی تاپیک ها هم منتشر میشن. با توجه به اینکه تو نسخه 5.0 قراره متریک های قدیمی حذف بشن، پیشنهاد میشه که به متریک های جدید مهاجرت کنیم.۸. Add Deadlock Protection on Producer Network Thread (KIP-1118)یه مشکل قدیمی هم که تو Producer ها داشتیم این بود که اگه KafkaProducer.flush() رو داخل callback متد send() صدا میزدیم، ممکن بود سیستم قفل کنه. تو 4.1 این مشکل با raise شدن exception حل شده.۹. Add support for OAuth jwt-bearer grant type (KIP-1139)حالا کافکا علاوه بر client_credentials از grant type نوع jwt-bearer برای OAuth هم پشتیبانی میکنه که نیاز به توضیحات بیشتری نداره!۱۰. Add transactional ID pattern filter to ListTransactions API (KIP-1152)API که برای لیست کردن transaction ها (ListTransactions) داشتیم، حالا با تغییری که داشته میتونه بر اساس پترن ID transaction فیلتر کنه. خب تو محیط هایی که تعداد transaction ها زیاده، این کمک میکنه لازم نباشه همه رو لیست کنیم و بعد سمت کلاینت فیلترشون کنیم.۱۱. بهبودهای مربوط به Kafka Connectتو بحث Kafka Connect هم دوتا تغییر KIP-891 و KIP-877 داشتیم که به صورت خلاصه میتونیم چندتا نسخه از یک پلاگین کانکتور رو همزمان نصب کنیم و کانکتورها و تسک ها میتونن متریک های مربوط به خودشون رو از طریق context ثبت کنند که به مانیتورینگ بهتر کمک میکنه.Confluent - Mickael Maison</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 09 Oct 2025 16:04:01 +0330</pubDate>
            </item>
                    <item>
                <title>انعطاف بیش از حد در طراحی نرم افزار، پیچیدگی و دردسر ناخواسته</title>
                <link>https://virgool.io/@heysaeid92/%D8%A7%D9%86%D8%B9%D8%B7%D8%A7%D9%81-%D8%A8%DB%8C%D8%B4-%D8%A7%D8%B2-%D8%AD%D8%AF-%D8%AF%D8%B1-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%D9%BE%DB%8C%DA%86%DB%8C%D8%AF%DA%AF%DB%8C-%D9%88-%D8%AF%D8%B1%D8%AF%D8%B3%D8%B1-%D9%86%D8%A7%D8%AE%D9%88%D8%A7%D8%B3%D8%AA%D9%87-b3e4zpes59up</link>
                <description>توی دنیای طراحی نرم افزار یه وسوسه بزرگ وجود داره: اینکه همه چیز رو داینامیک کنیم. یعنی چی؟ یعنی قوانین قابل تغییر باشن، رفتارها رو بشه کانفیگ کرد و ساختارها رو هم بتونیم توی زمان اجرا تغییر بدیم. خب تو نگاه اول هر چیزی که به جای یه تصمیم قطعی &quot;انعطاف پذیر&quot; باشه، خیلی هوشمندانه و آینده نگرانه به نظر میاد. اما داریم عدم قطعیت تولید میکنیم - وای از وقتی که این انعطاف بدون تفکر و بدون مرز استفاده بشه. پشت این ظاهر قشنگ یه چیز ترسناک هستش.سیستم هایی که همه چیزشون قابل کانفیگ هستش، بیشتر اوقات دیگه هیچ تضمینی ندارن. هیچ چیزی توی اونها ثابت نیست و هر تغییری دقیقا مثل این میمونه که داریم با سیم کشی پشت یه دستگاه روشن بازی میکنیم! کم کم به جای یه سیستم مهندسی شده چیزی داریم که پیچیده و غیرقابل پیش بینی هستش. به این فکر کنید که چقدر اوضاع میتونه از کنترلمون خارج بشه!بعضی چیزها باید ثابت و غیرقابل تغییر بمونن. اینکه یه چیزی سفت و سخت باشه، گاهی نه یک ضعف بلکه یه قدرت واقعی در طراحی هستش. با قفل کردن و ثابت نگه داشتن بعضی از تصمیم ها در واقع داریم برای بقیه بخش های سیستم امنیت، سادگی و اعتماد ایجاد میکنیم.پس دفعه بعدی که خواستیم یه چیزی رو &quot;داینامیک&quot; کنیم، یه لحظه صبر کنیم و خوب درموردش فکر کنیم.- انعطاف پذیری همیشه ارزشمند نیست – بعضی وقت ها خودش منشا دردسره.- بعضی تصمیم ها باید سخت گیرانه و غیرقابل تغییر باشن.- گاهی کمی انعطاف ناپذیری، بهترین لطفیه که میتونیم در حق سیستم و هم تیمی هامون کنیم!برای مثال فکر کنید قراره برای ایرانسل یا همراه اول یک سیستم مدیریت کمپین های تبلیغاتی طراحی کنیم. هدفمون اینه که تیم مارکتینگ بتونه بدون کمک گرفتن از تیم فنی هر نوع کمپینی رو با هر منطق دلخواهی تعریف و اجرا کنه(به عبارتی وابسته به تیم فنی نباشه). مثلا بخواد سناریو زیر رو تعریف کنه:کاربرایی که تو 1 ماه گذشته سیم کارت غیرفعال داشتن، ساکن شهر تهران هستن پیامک تبلیغاتی A براشون ارسال بشه یا اینکه بسته تشویقی A براشون فعال بشه.خب در ظاهر همچین چیزی هم برای تیم فنی و هم مارکتینگ خیلی جذابه. ولی وقتی وارد فاز اجرا بشیم، مشکلات خودشون رو نشون میدن. چون برای اینکه همچین چیزی رو پیاده سازی و همچین انعطافی رو داشته باشیم، باید کلی از اطلاعات جزئی و قابل فیتلر رو در لحظه تو دیتابیس داشته باشیم. از طرف دیگه هم نیاز به یهRule Engine داریم که بتونه این شرط های پیچیده و داینامیک رو روی میلیون ها رکورد اجرا کنه. خب اینجا تازه اولین مشکل خودش رو نشونه میده: فشار سنگین روی دیتابیس و زیرساخت.اما مشکل اصلی از جایی شروع میشه که تیم مارکتینگ چون دید فنی نداره شروع میکنه به ساخت کمپین ‌هایی که یا کانفلیکت دارن یا از نظر منطقی غیرقابل پیاده سازی هستن، این باعث رفتارهای غیرقابل پیش بینی میشه. برای مثال ممکنه یک پیامکی برای یک کاربر دوبار ارسال بشه و برای شخص دیگه ای ارسال نشه، چون شرط ها اشتباه ترکیب شدن. حالا فکر کنید که بخوایم دلیلش رو پیدا کنیم! ما میمونیم و کلی قوانین و روابط پیچیده‌. از طرف دیگه این سیستم عملا قابل تست نیست. چون هیچ تضمینی وجود نداره که قوانین جدیدی که تیم مارکتینگ از طریق UI تعریف میکنه، از نظر منطقی درست باشن یا تاثیرشون روی سایر کمپین ها در نظر گرفته شده باشه.اما در مقابل داینامیک بودن وقتی مدل های ثابت و قابل ترکیب برای تارگت ها و پیشنهادها تعریف کنیم – مثل دسته بندی های از پیش تعریف شده‌ مثل مشتری وفادار و پیشنهادهایی هم مثل بسته رایگان(و...) - چون این مدل ها از قبل بررسی، تست و مانیتور شدن احتمال به مشکل خوردنشون کمتره، همچنین اگر مشکلی هم پیش بیاد دقیقا میدونیم چه چیزی رو باید بررسی کنیم. از طرف دیگه هزینه پیاده سازی و نگهداریشم پایین میاد.در نتیجه انعطاف بی حد‌و‌مرز و بدون چارچوب باعث پیچیدگی، باگ، هزینه زیرساختی بالا و تجربه کاربری ضعیف میشه.</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 22 May 2025 19:53:06 +0330</pubDate>
            </item>
                    <item>
                <title>وقتی نامعلوم ها به سراغ شما می آیند: مدیریت غافلگیری در سیستم ها</title>
                <link>https://virgool.io/@heysaeid92/%D9%88%D9%82%D8%AA%DB%8C-%D9%86%D8%A7%D9%85%D8%B9%D9%84%D9%88%D9%85-%D9%87%D8%A7-%D8%A8%D9%87-%D8%B3%D8%B1%D8%A7%D8%BA-%D8%B4%D9%85%D8%A7-%D9%85%DB%8C-%D8%A2%DB%8C%D9%86%D8%AF-%D9%85%D8%AF%DB%8C%D8%B1%DB%8C%D8%AA-%D8%BA%D8%A7%D9%81%D9%84%DA%AF%DB%8C%D8%B1%DB%8C-%D8%AF%D8%B1-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7-yuetyxyuajcp</link>
                <description>تا حالا شده فکر کنید همه چیز تحت کنترله، کدها دقیق نوشته شدن و هیچ چیز غیر منتظره ای نمی تونه اتفاق بیفته؟ بعد یهویی از جایی که اصلاً انتظارش رو نداشتید، همه چیز به هم بریزه؟ یک مشکل عجیب و غریب، یه مشکل پیش بینی نشده، یا حتی یک اتفاق غیرقابل تصور. این لحظه رو احتمالا اکثر ما تجربه کردیم و این دقیقا همون چیزیه که بهش میگیم &quot;سورپرایززززز (غافلگیری)&quot;بیشتر مردم غافلگیری ها را دوست ندارند - به خصوص غافلگیری های منفی! شرکت ها معمولا از غافلگیری ها متنفرند. اکثر مدیران از غافلگیری بیزارند، چون این غافلگیری ها برنامه های دقیق آن ها را برهم می زند و ریسک های غیرمنتظره ای دارند. همچنین کارمندها نیز معمولا از غافلگیری ها متنفرند، چرا که اغلب به معنای کار اضافی و استرس زا است و گاهی حتی امنیت شغلی آن ها را به خطر می اندازد.اما هرچقدر هم تلاش کنیم، غافلگیری ها اتفاق می افتند. البته افرادی هم هستند که فکر می کنند اگر به اندازه کافی برنامه ریزی کنیم، آن ها اتفاق نمی افتند. اینجاست که مدل known-unknown وارد می شه. مدلی که کمک می کنه متوجه بشیم چرا حتی بهترین برنامه ریزی ها هم نمی تونه ما رو از غافلگیری های اجتناب ناپذیر محافظت کنه و چطور می شه با این واقعیت کنار اومد.معلوم های معلوم (Known knowns): چیزهایی که می دانیم و از وجودشان آگاهیم. این ها دانش صریح ما هستند. معمولا این موارد را در برنامه ریزی خود لحاظ می کنیم. هرچه برنامه ریزی دقیق تر باشد، لیست &quot;معلوم های معلوم&quot; ما کامل تر خواهد بود.معلوم های نامعلوم (Unknown knowns): چیزهایی که به طور ضمنی می دانیم اما از وجودشان آگاه نیستیم. این ها دانش ضمنی ما هستند. اگر مشکلی پیش بیایید معمولا حس ششم ما را به سمت درست هدایت می کنند. ممکن است برخی از این موارد را در برنامه ریزی خود لحاظ کنیم، اما به دلیل سختی تبدیل دانش ضمنی به دانش صریح، احتمالا تعدادی از آن ها را از دست بدهیم.نامعلوم های معلوم (Known unknowns): چیزهایی که نمی دانیم اما از ندانستنشان آگاهیم. اگر سخت کار کنیم، ممکن است برخی از موارد را شناسایی کرده و آن ها را به &quot;معلوم های معلوم&quot; تبدیل کنیم. شاید دیگران بتوانند به پر کردن بخشی از شکاف ها کمک کنند. با این حال، احتمال زیادی وجود دارد که برخی از آن ها را از دست بدهیم.نامعلوم های نامعلوم (Unknown unknowns): چیزهایی که نمی دانیم و از ندانستنشان هم آگاه نیستیم. فرقی ندارد چقدر تلاش کنیم، باز هم آن ها را از دست می دهیم.اگر واقعا سخت تلاش کنیم و خوش شانس باشیم، شاید بتوانیم تمام اتفاقات و موقعیت های نامطلوبی که در سه بخش اول پنهان هستند را شناسایی کنیم. اما معمولا این کار را نمی کنیم. معمولا حتی با سخت ترین تلاش ها، برخی از این موارد را از دست می دهیم. برای مثال سعی کنید تمام اقلام موجود در آشپزخانه تان را از حفظ فهرست کنید. احتمالا چند مورد را فراموش خواهید کرد، معلوم های نامعلوم یا نامعلوم های معلوم.مدیریت غافلگیری ها1- پذیرش واقعیت و تغییر ذهنیتتو اولین قدم باید بپذیریم که غافلگیری ها اجتناب ناپذیر هستند. یعنی اینکه قبول کنیم هیچ سیستمی بدون نقص نیست و همیشه شرایطی وجود داره که ممکنه پیش بینی نشده باشه. برای مثال وقتی Netflix شروع به استفاده از Chaos Monkey کرد، هدفش این بود که با ایحاد مشکلات عمدی در سرورها، تیم ها رو برای غافلگیری های احتمالی آماده کنه. خب این کار به تیم ها کمک کرد که به جای ترسیدن از خطاها، یک واکنش سریع و موثر داشته باشند.اطلاعات بیشتر درمورد Chaos Monkey:  lnkd . in / diHuQ5T52- آماده سازی برای ناشناخته هابا اینکه نمی تونیم همه ناشناخته ها رو شناسایی کنیم، ولی میتونیم سیستم هایی رو طراحی کنیم که آماده مواجهه با این اتفاقات باشن.Game Day Exercises: مشابه شبیه سازی مشکلات در دنیای واقعی، تیم ها می تونن سناریوهایی مثل قطع کانکشن به دیتابیس یا مشکل در سیستم های وابسته رو شبی سازی کنن تا آمادگی بیشتری پیدا کنن.فرهنگ Blameless: وقتی یک باگ پیش بینی نشده باعث مشکل در سیستم میشه، تمرکز باید روی حل مسئله باشه نه پیدا کردن مقصر. این فرهنگ باعث میشه افراد بدون ترس مشکلات احتمالی رو مطرح کنن.اطلاعات بیشتر درمورد فرهنگ Blameless:  lnkd .in /dyDRR92X3- استفاده از داده ها و ابزارهابرای کاهش اثر غافلگیری ها، می تونیم از ابزارهایی مثل Datadog برای مانیتور کردن و Post-Mortem برای بررسی دلایل اصلی و مستند سازی مشکل بعد از هر غافلگیری برای کاهش احتمال تکرارش استفاده کنیم.4- طراحی انعطاف پذیر و ماژولارباید سیستم ها رو طوری طراحی کنیم که هنگام وقوع مشکلات، کل سیستم با مشکل مواجه نشه. مثلا با استفاده از Resilience Pattern هایی مثل Circuit Breaker از افزایش خطاها جلوگیری کنیم. یا با طراحی ماژولار، در صورت بروز مشکل در یک قسمت از انتقال اون به بخش های دیگه جلوگیری کنیم.اطلاعات بیشتر درمورد Circuit Breaker Pattern:  lnkd .in /d2wAtuAW5- تست و یادگیری مداومتست های مستمر و یادگیری از گذشته، بهترین ابزارهای ما برای کاهش تاثیرات هستن.Chaos Engineering: ابزارهایی مثل Gremlin یا Chaos Monkey میتونن سناریوهای اختلال رو شبی سازی کنن و سیستم رو در برابر شرایط پیش بینی نشده مقاوم تر کنن.بهبود مداوم: مستندسازی مشکلات و به روزرسانی فرآیندها به ما کمک میکنه که برای چالش های آینده آماده تر باشیم.برای مثال تیم Dev ممکنه بعد از بروز یه مشکل، تست های جدیدی رو اضافه کنه که اون سناریو رو پوشش بدهدر پایان،  باید بدانیم که در دنیای نرم افزار، غافلگیری ها همیشه بخشی از واقعیت هستن. اما با پذیرش این واقعیت، آمادهسازی مناسب، استفاده از ابزارها و طراحی سیستم های مقاوم، می تونیم اثر این غافلگیری ها رو به حداقل برسونیم. مهم تر از همه، باید از هر غافلگیری به عنوان فرصتی برای یادگیری و رشد استفاده کنیم، چون تنها راه پیشرفت در دنیای ناشناخته ها، پذیرش و مدیریت اون هاست.در نهایت، غافلگیری ها را نمیتوان حذف کرد، اما میتوان از آنها برای ساختن سیستم هایی مقاوم تر و تیم هایی قوی تر استفاده کرد.</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Mon, 12 May 2025 11:36:14 +0330</pubDate>
            </item>
                    <item>
                <title>Share Group در Kafka (Queues for Kafka)</title>
                <link>https://virgool.io/@heysaeid92/share-group-%D8%AF%D8%B1-kafka-queues-for-kafka-lrhfr6tqlzco</link>
                <description>Apache Kafka یک Event-Streaming Platform اپن سورس و بسیار محبوب است که ترکیب Horizontal Scaling و Strong Ordering آن را به ابزار قدرتمندی برای ایجاد معماری های مدرن، Reactive و Event-Driven تبدیل کرده است. طی سال هایی که با کاربران Kafka کار کرده ام چالش اصلی که بیشتر اوقات به آن اشاره می کنند مربوط به Consumer Groupها و افزایش تعداد Consumerها است.Consumer Groupها برای تحویل مرتب جریان رویدادها به یک گروه از Consumerها طراحی شده اند. در این روش Kafka بررسی می کند که Consumerها در یک گروه به چه Topicهایی مشترک شده اند و Partitionهای این تاپیک ها را میان اعضای گروه توزیع می کند. هر Consumer در یک گروه دسترسی انحصاری به پارتیشن هایی که به آن اختصاص داده شده دارد. یعنی اینکه حداقل باید به تعداد Consumerها، پارتیشن وجود داشته باشد. در نتیجه برخی از کاربران دست به Over-Partitioning می زنند تا بتوانند تعداد بیشتری Consumer را اضافه کنند و با Peak Load مقابله کنند. این کار برای افزایش Throughput و Ordering بسیار مفید می باشد، اما بسیاری از افراد همیشه به این سطح از تضمین های Kafka نیازی ندارند. خیلی ها فقط چون کافکا این قابلیت رو دارد از آن استفاده می کنند، حتی وقتی نیاز خاصی به آن ندارند!Queueها برای KafkaاKIP-932 یک نوع جدید از گروه ها به نام Share Groupها را معرفی می کند. این گروه ها جایگزین Consumer Groupها نیستند، بلکه یک گزینه جدید هستند که به کاربران این قابلیت را می دهند تا بر اساس Consumption Behavior مورد نظرشان یکی از این دو روش را انتخاب کنندShare Group در Kafkaدر یک Share Group، Consumerها بهصورت Cooperative با یکدیگر کار می کنند، درست مانند چیزی که در Traditional Message Queueها دیده اید. شما می توانید Consumerها را طوری طراحی کنید که با استفاده از این گروهها، داده ها را از Topicها دریافت کنند. در این روش دیگر نیازی نیست نگران پارتیشن ها باشید. فقط کافی است تعداد Consumerها را افزایش دهید تا مقیاس پذیری بیشتر شود(البته به شکل منطقی). این کار دقیقا مانند حالتی است که در یک Message Queue چندین Consumer هم زمان از پیام ها استفاده می کنند.نحوه عملکرد Share Groupدر یک Share Group همه ی Consumerها به تمام پارتیشن ها دسترسی دارند، اما پیام ها بین آن ها تقسیم می شوند، یعنی هر پیام فقط توسط یکی از Consumerها پردازش می شود. این روش بسیار شبیه به چیزی است که در JMS بهعنوان Durable Shared Subscription می شناسیم.Acknowledgement و پردازش داده هاConsumerها می توانند دریافت رکوردها را به صورت جداگانه تایید کنند، اما معمولا این کار را به صورت Batch انجام می دهند که باعث بهبود Efficiency می شود.Queue در Share Group چطور کار می کند؟وقتی از Share Group استفاده می کنیم، رفتار سیستم خیلی شبیه به Message Queue خواهد بود. در یک Message Queue پیام ها همیشه در وضعیت های مختلفی قرار دارند، حتی اگر آن ها را به شکل مستقیم مشاهده نکنیم.فرض کنید یک سیستم Message Queue داریم که از JMS API پشتیبانی می کند. وقتی یک پیام در صف قرار می گیرد، اول قابل دریافت هست. بعد از اینکه یکی از Consumerها آن را پردازش کرد، از نظر منطقی از Queue حذف می شود، اما هنوز به صورت فیزیکی حذف نشده و برای بقیه قابل مشاهده نمی باشد. وقتی Consumer دریافت پیام رو تایید کند، پیام به شکلی واقعی حذف می شود. پس در این فرآیند هر پیام چندین وضعیت مختلف رو تجربه می کند.حالا Queues for Kafka هم تقریبا همین ایده را دارد. این ویژگی وضعیت رکوردهای در حال تحویل (In-Flight Records) را مدیریت می کند. در این مدل Share Groupها مسئولیت کنترل و تحویل این رکوردها را دارند، درست مانند چیزی که در یک Message Queue سنتی اتفاق می افتد.مدیریت رکوردهای In-Flight در Kafkaهر Share-Partition یکسری رکورد In-Flight دارد که با دو مقدار Start Offset و End Offset مشخص می شوند. وقتی یک Consumer پیام ها را دریافت و پردازش می کند، Start Offset به جلو حرکت کرده و همزمان End Offset هم جلوتر می رود.این فاصله بین Start Offset و End Offset همیشه یک حد مشخصی دارد تا تعداد پیام های در حال پردازش کنترل شود و Resource Management بهینه تر باشد. در واقع می توانیم این بخش را مثل یک Sliding Window در نظر بگیریم که همراه با پردازش داده ها حرکت می کند.در حالت ایده آل این Sliding Window همیشه نزدیک به انتهای پارتیشن قرار دارد، یعنی Consumerها همگام با تولید داده های جدید پیام ها را پردازش می کنند و هیچ تاخیری در روند پردازش داده ها وجود ندارد.مدیریت وضعیت تحویل رکوردهاوقتی یک Consumer در یک Share Group یک رکورد را دریافت می کند، آن رکورد به طور موقت در اختیارش قرار می گیرد. یعنی رکورد یک وضعیت جدید پیدا می کند که این وضعیت موقتی بوده و به طور پیش فرض ۳۰ ثانیه زمان می برد تا پردازش شده و تایید دریافتش ارسال شود.اگر Consumer پیام را پردازش کرده و تایید بدهد، رکورد به وضعیت بعدی می رود و کارش تمام می شود. اما اگر Consumer کرش کند یا نتواند پیام را پردازش کند، آن رکورد دوباره در Queue قرار می گیرد و یک Consumer دیگر سعی می کند آن را پردازش کند. Kafka تعداد Retryها رو دنبال کرده و به طور پیش فرض هر رکورد 5 بار شانس پردازش دارد. اگر بعد از این تلاش ها باز هم پردازش نشود، آرشیو شده و دیگر تحویل داده نمی شود.این مکانیزم باعث می شود که پیام های خراب باعث کرش کل سیستم نشوند و فقط یک اختلال موقتی ایجاد کنند.چندین سوال درباره Queues for Kafkaچرا Kafka یک مفهوم جدا به اسم Queue معرفی نکرد؟خب Kafka نمی خواست یک چیز جدید به اسم Queue را در کنار Topic اضافه کند. به همین خاطر در KIP-932 تصمیم گرفته شد که Share Groupها معرفی شوند. یعنی یک روش جدید برای مصرف رکوردها از Topicها، بدون اینکه نیازی به تغییر در Producerها باشد.اگر دو Share Group به یک Topic متصل شوند، چی اتفاقی می افتد؟در این حالت عملا دو Queue مستقل خواهیم داشت که هر کدام از آن ها رکوردهای خودشان رو مدیریت می کنند. یعنی هر گروه به صورت جداگانه پیام ها را پردازش می کند و با گروه دیگر تداخل نخواهد داشت.آیا میتوان Consumer Groupها و Share Groupها را بر روی یک Topic استفاده کرد؟بله، این کار قابل انجام است.Share Groupها مدل Point-to-Point می باشند یا Publish/Subscribe؟از نظر JMS این روش Publish/Subscribe محسوب می شود. اما اگر فقط یک Share Group به یک Topic متصل باشد و هیچ Consumer Group دیگری وجود نداشته باشد، از نظر رفتاری بیشتر شبیه به Point-to-Point عمل می کند.آیا Share Groupها از Ordering پشتیبانی می کنند؟خیر، پیام ها به صورت Unordered تحویل داده می شوند. البته Ordering بر اساس Key-Based Ordering می تواند در آینده یک تغییر کاربردی باشد، اما در KIP-932 وجود ندارد. احتمالا در آینده در یک KIP دیگر بررسی شود.آیا Share Groupها از Exactly-Once Semantics پشتیبانی می کنند؟در حال حاضر خیر. تحویل پیام ها به صورت At-Least-Once انجام می شود. البته پیاده سازی آن را در آینده ممکن می باشد.آیا کاربران سیستم هایی مانند ActiveMQ می توانند به راحتی به Kafka مهاجرت کنند؟نه به این سرعت! Kafka الان می تواند بسیاری از سناریوهایی که قبلا نیاز به یک Message Queue جداگانه داشتند رو پوشش دهد، اما هنوز باید یک Kafka Client Application برای مصرف پیام ها نوشت. اگر صرفا برای مدیریت Queueها یک MQ Broker در کنار Kafka داشتید، شاید دیگر نیازی به آن نداشته باشید، ولی این به معماری سیستم بستگی دارد.KIP-932: https://cwiki. apache. org/confluence/display/KAFKA/KIP-932%3A+Queues+for+KafkaAndrew Schofield - Medium: https://lnkd. in/eVPfCpX4KAFKA-16092: https://issues.apache. org/jira/browse/KAFKA-16092</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Sun, 11 May 2025 14:24:54 +0330</pubDate>
            </item>
                    <item>
                <title>کافکا بدون ZooKeeper: نگاهی به مهم ترین تغییرات نسخه 4.0</title>
                <link>https://virgool.io/@heysaeid92/%DA%A9%D8%A7%D9%81%DA%A9%D8%A7-%D8%A8%D8%AF%D9%88%D9%86-zookeeper-%D9%86%DA%AF%D8%A7%D9%87%DB%8C-%D8%A8%D9%87-%D9%85%D9%87%D9%85-%D8%AA%D8%B1%DB%8C%D9%86-%D8%AA%D8%BA%DB%8C%DB%8C%D8%B1%D8%A7%D8%AA-%D9%86%D8%B3%D8%AE%D9%87-40-rgaflvcvwnk0</link>
                <description>تو نسخه جدید Kafka 4.0 که اخیرا منتشر شده، مجموعه ای از ویژگی ها و بهبودهای جدید معرفی شدن که به نظرم مهم ترینش، عملکرد پیش فرض در حالت KRaft هست. خب این تغییر، وابستگی Kafka به Apache ZooKeeper رو به طور کامل حذف میکنه.تا قبل از این نسخه، استفاده از ZooKeeper تو کافکا حالت پیش فرض و رایج بود، درسته که KRaft قبلا معرفی شده ولی اختیاری بود و خیلی از سیستم ها همچنان با ZooKeeper پیاده سازی میشدن. تجربه شخصی من هم مثل بیشتر دوستان تو مدیریت ZooKeeper همیشه با چالش و دردسر همراه بود. ZooKeeper رو سال ها به عنوان یکی از مولفه های کلیدی معماری Kafka برای مدیریت متادیتا، هماهنگی بین بروکرها و... استفاده می کردیم. ولی خب هم زمان یه لایه‌ از پیچیدگی و نگهداری اضافه رو همراه خودش داشت. حذف این وابستگی باعث شده دیپلوی راحت تر انجام بشه و مقیاس پذیری هم به شکل خوبی بهبود پیدا کنه(به ويژه تو سناریوهایی که تعداد پارتیشن ها خیلی زیاد میشن (مثلا بالای ۱۰۰ هزار).آقای Lalit Moharana که یکی از اعضای AWS Community Builder، تو لینکدین نوشته بود:با انتشار نسخه 4.0، ZooKeeper کنار میره و یک همکاری 14 ساله به پایان میرسه. این تغییر با حذف یک سیستم مجزا (ZooKeeper)، معماری Kafka رو ساده تر میکنه، مقیاس پذیری رو بهبود میده و راه رو برای یک آینده ای خودکفا هموار میکنه. همه این ها به لطف جادوی پروتکل Raft در KRaft هستش.اما چرا اصلا این تغییر اتفاق افتاده؟ چون سربار و محدودیت های ZooKeeper (مثلا در مقیاس بیش از ۱۰۰ هزار پارتیشن) دیگه نمی تونستن با رشد Kafka هماهنگ بمونن. در عوض KRaft یک سیستم یکپارچه هستش که میلیون ها پارتیشن رو پشتیبانی میکنه و بازیابی سریع تری هم داره.یکی دیگه از تغییراتی خوبی که انجام شده، معرفی پروتکل جدید Consumer Group توی KIP-848 هستش. این پروتکل عملکرد rebalance رو به شکل خیلی خوبی بهبود داده و اون توقف های طولانی (stop-the-world) آزار دهنده رو تا حد زیادی برطرف کرده. البته این قابلیت فقط سمت سرور به صورت پیش فرض فعال و برای کلاینت ها لازمه که group.protocol=consumer تنظیم بشه.یکی دیگه از قابلیت‌ های خوب این نسخه که به صورت early access معرفی شده، KIP-932 (Queues for Kafka) هست که امکان تعریف shared groups ها روی topic های Kafka فراهم میکنه. در مورد این قابلیت قبلا به شکل کامل نوشتم:https:// lnkd .in/dgjXC7Mdدر نهایت، یه نکته جالب دیگه هم تغییر نسخه مورد نیاز Java برای Kafka هست:کKafka Clients و Streams حالا حداقل به Java 11 نیاز دارنکKafka Brokers و Connect هم باید با Java 17 اجرا بشنKIP-848: https:// lnkd .in/dGgUfiUeKRaft Simplifies Architecture: https:// lnkd .in/dKcbnbXQ</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Wed, 09 Apr 2025 23:29:23 +0330</pubDate>
            </item>
                    <item>
                <title>وقتی گذشته جلوی آینده رو میگیره - Frozen Caveman Antipattern</title>
                <link>https://virgool.io/@heysaeid92/%D9%88%D9%82%D8%AA%DB%8C-%DA%AF%D8%B0%D8%B4%D8%AA%D9%87-%D8%AC%D9%84%D9%88%DB%8C-%D8%A2%DB%8C%D9%86%D8%AF%D9%87-%D8%B1%D9%88-%D9%85%DB%8C%DA%AF%DB%8C%D8%B1%D9%87-frozen-caveman-antipattern-ob7zuktohxyj</link>
                <description>تصویر از سایت deviq می باشدشاید شما هم این تجربه رو داشته باشید که در یک پروژه برای انجام یک کاری بخواید از یه روش متفاوت و جدید استفاده کنید، اما مدیر یا یکی از اعضای ارشد تیم اصرار داره که باید همون روش قدیمی رو اجرا کنید، فقط چون &quot;قبلا جواب داده&quot;! حتی اگه اون روش دیگه برای شرایط جدید مناسب نباشه، باز هم مقاومت در برابر تغییر باعث میشه که تیم توی همون مسیر تکراری بمونه. این دقیقا همون جاییه که Frozen Caveman به وجود میاد. یه طرز فکر قدیمی که معمولا جلوی پیشرفت رو میگیره و باعث میشه تیم به جای حرکت رو به جلو توی گذشته گیر کنه(درست مثل یه غارنشین که بعد از هزاران سال از دل یخ ها بیرون اومده اما هنوز نمیتونه با دنیای مدرن کنار بیاد!).این مشکل زمانی اتفاق می افته که بعضی از افراد مخصوصا کسایی که تجربه ی بیشتری دارن دیگه یادگیری رو متوقف می کنن - این افراد توی سازمان ها کم نیستن، مخصوصا اونایی که مدت زیادیه توی یه سازمان کار می کنن. چیزی که یه زمانی یاد گرفتن براشون تبدیل به یه قانون طلایی میشه و دیگه حاضر نیستن روش های جدید رو امتحان کنن. مثلا فرض کنید یه نفر سال ها با Monolithic Applications کار کرده، حالا شرکت میخواد به Microservices مهاجرت کنه(با فرض اینکه مناسب تر هستش). ولی اون شخص به جای بررسی این موضوع و یادگیری موارد جدید، سعی می کنه همه چیز رو همون طوری که همیشه انجام می داده، پیاده سازی کنه. نتیجه کار؟ کلی وقت تلف میشه و بهره وری سیستم پایین میاد و اون معماری جدید عملا تبدیل میشه به یه نسخه ی تکراری از سیستم قدیمی (البته این فقط یه مثال بود برای روشن تر شدن موضوع!). این طرز فکر فقط روند کار تیم رو کند نمی کنه بلکه رو تصمیمات کلیدی هم تاثیر منفی داره. افرادی که توی این تله افتادن معمولا به جای درک مزایای واقعی ابزارها و روش های جدید، فقط سعی می کنن اون ها رو توی چارچوب الگوهای قدیمی خودشون جا بدن. نتیجه اینه که تغییرات به جای اینکه باعث پیشرفت بشن، فقط به یه نسخه ی پر زحمت تر از همون سیستم قدیمی تبدیل میشن. حالا اگه سازمان هم به یادگیری و رشد مهارت های جدید اهمیت نده مشکل عمیق تر و پیچیده تر میشه.البته باید توجه داشته باشیم که این مشکل فقط مخصوص افراد ارشد یا مدیران نیست. هر کسی در هر جایگاهی ممکنه توی تله این طرز فکر بیفته. تفاوت اینجاست که افراد ارشد و با تجربه به دلیل تاثیرگذاری بیشتری که روی تیم دارن، نقش مهم تری در این موضوع دارن. اما در نهایت مهمه که همه ی ما صرف نظر از موقعیتمون، ذهنیتمون رو باز نگه داریم و همیشه به دنبال یادگیری و پیشرفت باشیم.اطلاعات بیشتر: https:// deviq .com/antipatterns/frozen-caveman</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Sat, 15 Feb 2025 17:41:06 +0330</pubDate>
            </item>
                    <item>
                <title>زبان زمان در طراحی نرم افزار - گذشته، حال و آینده!</title>
                <link>https://virgool.io/@heysaeid92/%D8%B2%D8%A8%D8%A7%D9%86-%D8%B2%D9%85%D8%A7%D9%86-%D8%AF%D8%B1-%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-%DA%AF%D8%B0%D8%B4%D8%AA%D9%87-%D8%AD%D8%A7%D9%84-%D9%88-%D8%A2%DB%8C%D9%86%D8%AF%D9%87-setjufo0yile</link>
                <description>در طراحی نرم افزار یکی از اصول جالب نگاه به داده ها از منظر زمان است. به زبان ساده تمام چیزی که نرم افزار انجام می دهد این است که اطلاعات را در گذر زمان منتقل می کند، چه بین افراد و چه بین بخش های مختلف یک سیستم. با توجه به مفهوم زمان داده ها به سه بخش گذشته، حال، و آینده تقسیم می شوند. به همین شکل داده ها نیز در سه دسته Commandها، Eventها و State قرار می گیرند.Commandها در واقع نشانه دهنده چیزی هستند که کاربران می خواهند در آینده اتفاق بیفتد. یک Command نوعی از داده است که هدفش نشان دادن &quot;قصد&quot; یا &quot;خواسته&quot; است. اما چیزی که این داده را خاص می کند ناپایداری ذاتی آن است. چرا؟ چون آینده قابل پیش بینی نیست. خواسته ممکن است تغییر کند یا شاید اصلا انجام نشود. زمان هم اینجا نقش مهمی دارد، چون وقتی سیستم تصمیمی بگیرد، ممکن است Command هم بی اعتبار شود.در مقابل رویدادها داستان دیگری دارند. رویدادها نماینده گذشته هستند. آن ها چیزی را ثبت می کنند که قبلا اتفاق افتاده و دیگر قابل تغییر نیست. همین ویژگی باعث می شود که رویدادها ذاتا پایدار باشند. اگر قبول کنیم که &quot;آنچه رخ داده است، رخ داده است&quot;، می توانیم به رویدادها به عنوان یک &quot;منبع حقیقت پایدار&quot; در طراحی سیستم ها نگاه کنیم.اما State، یا همان وضعیت فعلی، به حال مربوط می شود. این نوع داده نمایشی از لحظه فعلی است. یک اسنپ شات از هرچیزی که در حال حاضر وجود دارد. نکته مهم درباره State این است که با گذر زمان تغییر می کند. گاهی سریع و گاهی آرام. State چیزی است که سیستم باید آن را در لحظه نگه دارد، اما در عین حال همیشه امکان تغییر دارد.این سه دسته از داده نه تنها بر اساس زمان، بلکه از نظر ویژگی های پایداری نیز تفاوت های مهمی دارند. Commandها ناپایدار هستند، چون آینده نامشخص است. رویدادها پایدارند، چون گذشته غیرقابل تغییر است. State جایی بین این دو قرار دارد، همواره درحال تغییر است، اما در لحظه ای که ثبت می شود ثابت و پایدار به نظر می رسد.این سه مفهوم بیش از یک الگوی ذهنی هستند. آن ها اساس بسیاری از تکنیک های مدل سازی در طراحی نرم افزار هستند. برای مثال در نرم افزار اغلب از رنگ ها برای نمایش این دسته ها استفاده می شود: Commandها آبی، رویدادها نارنجی و State سبز. این رنگ ها به طور ناخودآگاه حس پایداری یا پویایی هر دسته را القا می کنند.اگر کمی دقیق تر به سیستم های امروزی نگاه کنیم، می بینیم که این تقسیم بندی چقدر کاربردی و مهم است. در معماری‌های Event-Driven، رویدادها مرکز اصلی توجه هستند و به‌عنوان Source of Truth عمل می کنند. سیستم های مبتنی بر CQRS از این سه نوع به صورت تفکیک شده برای مدیریت عملیات و گزارش گیری استفاده می کنند. یا حتی در Temporal Databases این سه مفهوم پایه گذار نحوه ذخیره و مدیریت داده ها هستند.در پایان، باید بدانیم که نگاه از منظز زمان به داده ها نه تنها درک ما را در طراحی نرم افزار بهبود می بخشد، بلکه باعث می شود معماری های مقیاس پذیرتر، قابل فهم تر و انعطاف پذیرتر بسازیم. می توانیم گذشته را از رویدادها داشته باشیم، آینده رو با Command ها برنامه ریزی کنیم و با State ها در لحظه کار کنیم. این سه بخش پویایی زمان را به دنیای نرم افزار می آورند و آن را زنده تر می کنند.</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Wed, 29 Jan 2025 11:32:11 +0330</pubDate>
            </item>
                    <item>
                <title>طراحی انتزاع های قابل اعتماد بر روی انتزاع های غیرقابل اعتماد</title>
                <link>https://virgool.io/@heysaeid92/%D8%B7%D8%B1%D8%A7%D8%AD%DB%8C-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9-%D9%87%D8%A7%DB%8C-%D9%82%D8%A7%D8%A8%D9%84-%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF-%D8%A8%D8%B1-%D8%B1%D9%88%DB%8C-%D8%A7%D9%86%D8%AA%D8%B2%D8%A7%D8%B9-%D9%87%D8%A7%DB%8C-%D8%BA%DB%8C%D8%B1%D9%82%D8%A7%D8%A8%D9%84-%D8%A7%D8%B9%D8%AA%D9%85%D8%A7%D8%AF-hxzwa0prukef</link>
                <description>در توسعه نرم افزار طراحی انتزاع هایی که بتوان به آن ها اعتماد کرد یکی از چالش های بزرگ و حیاتی است. این موضوع زمانی پیچیده تر میشود که ساب سیستم پایه ذاتا غیرقابل اعتماد باشد. چنین شرایطی معمولا هنگام تعامل با Third-Party Services، APIهای قدیمی، سیستم های توزیع شده یا شبکه هایی با رفتار ناپایدار به وجود می آید. برای طراحی انتزاع های قابل اعتماد نیاز به درک عمیق از چالش ها و به‌کارگیری پترن ها و تکنیک هایی است که قابلیت اطمینان سیستم را افزایش دهند.یکی از مهم ترین جنبه های طراحی در این شرایط شناخت رفتار ساب سیستم و تحلیل دقیق نقاط شکست احتمالی آن است. هر سیستم غیرقابل اعتماد Failure Patternهای خاص خود را دارد که باید شناسایی و مستند شوند. برای مثال سیستم های وابسته به شبکه معمولا با مشکلاتی مانند Latency ،Data Loss یا Timeout مواجه می شوند. طراحی انتزاع باید به شکلی باشد که این مشکلات پیش بینی و با استفاده از تکنیک هایی مانند Retry و Timeout مدیریت شوند. استفاده از پترن Circuit Breaker نیز در مواقعی که خطاهای متوالی رخ می دهند می تواند به قطع ارتباط موقت با ساب سیستم معیوب کمک کرده و از افزایش بیش ازحد فشار به آن جلوگیری کند.مدیریت خطاها نیز یکی دیگر از جنبه های مهم در طراحی انتزاع های قابل اعتماد است. یک انتزاع مناسب باید بتواند خطاهای ساب سیستم را به شکلی مشخص و ساده به کاربران مشخص کند. طراحی سیستم باید شامل مکانیزم های Error Handling استاندارد باشد که خطاها را دسته بندی کرده و آن ها را با پیام های معنادار و مشخص (مثل Error Code و Error Template) به کاربران منتقل کند. همچنین طراحی Recovery Pathها از جمله استفاده از Default Valueها یا داده های کش شده می تواند حس اطمینان بیشتری به کاربران القا کند و آن را بهبود دهد.در بسیاری از موارد طراحی انتزاع قابل اعتماد به معنای محدود کردن وابستگی ها به ساب سیستم است. هرچه انتزاع کمتر به رفتار داخلی ساب سیستم متکی باشد، پایداری و قابلیت پیش بینی آن افزایش می یابد. استفاده از پترن هایی مانند Adapter یا Abstraction Layers می تواند به کاهش این وابستگی ها کمک کند. به این شکل حتی اگر ساب سیستم دچار تغییر یا خرابی شود کاربران انتزاع همچنان می توانند از آن بدون وقفه یا مشکلات جدی استفاده کنند.یکی از ویژگی های اصلی یک انتزاع موفق این است که حتی در شرایط بحرانی رفتاری پایدار و قابل پیش بینی ارائه دهد. این مسئله نیازمند طراحی دقیق برای شرایط شکست است. شبیه سازی سناریوهای مختلف از جمله قطعی شبکه، بازگشت داده های نامعتبر یا افزایش غیرمنتظره لود سیستم می تواند به شناسایی نقاط ضعف کمک کند. با انجام چنین تست هایی و بهبود مستمر انتزاع، می توان سیستمی ساخت که در برابر مشکلات واقعی مقاوم باشد. برای این کار می توانیم از Chaos Engineering و Fault Injection Testing استفاده کنیم.در پایان باید بدانیم که اعتماد در نرم افزار چیزی نیست که به طور تصادفی به وجود بیایید، بلکه با طراحی مناسب و دقیق ساخته می شود.</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Tue, 28 Jan 2025 11:18:23 +0330</pubDate>
            </item>
                    <item>
                <title>چرا و چگونه سیستم ها را دپریکیت کنیم؟ - بخش سوم</title>
                <link>https://virgool.io/@heysaeid92/%DA%86%D8%B1%D8%A7-%D9%88-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7-%D8%B1%D8%A7-%D8%AF%D9%BE%D8%B1%DB%8C%DA%A9%DB%8C%D8%AA-%DA%A9%D9%86%DB%8C%D9%85-%D8%A8%D8%AE%D8%B4-%D8%B3%D9%88%D9%85-kmf82rjh9x5p</link>
                <description>در بخش قبلی درباره چالش های دپریکیت کردن سیستم ها صحبت کردیم. متوجه شدیم چرا وابستگی های پنهان و استفاده های پیش بینی نشده از سیستم های قدیمی، فرایند حذف آن ها را پیچیده می کند. همچنین به اهمیت برنامه ریزی دقیق، تعیین زمان بندی مشخص، و مدیریت منابع برای موفقیت این فرایند اشاره کردیم و مثال هایی از تجربه گوگل در مدیریت تدریجی دپریکیشن را داشتیم.بخش دوم: https://vrgl.ir/IHsVPدپریکیت کردن سیستم ها یک فرایند واحد نیست و شامل طیفی از رویکردها می‌ باشد. این فرایند می تواند از «امیدواریم روزی این سیستم را خاموش کنیم» تا «فردا این سیستم به طور کامل از دسترس خارج می شود، مشتریان آماده باشند» متغیر باشد. به طور کلی می توان آن را به دو دسته اصلی تقسیم کرد:Advisory Deprecationدر این رویکرد، هیچ مهلت یا اجبار مشخصی برای کنار گذاشتن سیستم قدیمی مشخص نمی شود و معمولا منابع محدودی برای آن اختصاص داده می شود. این روش بیشتر برای معرفی سیستم های جدید و تشویق کاربران در شرایطی که سیستم جدید قابلیت های بهتری ارائه می دهد مناسب است.  سیستم جدید باید از ابتدا آماده استفاده باشد و قابلیت پشتیبانی کافی و نامحدود را داشته باشد. ابزارهای سلف سرویس و اطلاع رسانی می توانند کاربران را برای مهاجرت تشویق کنند، اما تجربه نشان داده است که صرف هشدار دادن یا ارائه مزایای جزئی معمولا کافی نیست. سیستم قدیمی همچنان نیاز به نگهداری خواهد داشت، مگر اینکه برنامه های کامل تری برای تشویق کاربران به مهاجرت داشته باشیم.Hope is not a strategy.Compulsory Deprecationدر این روش تاریخ مشخصی برای حذف سیستم تعیین می شود و کاربران موظفند تا آن زمان به سیستم جدید مهاجرت کنند. اگر این مهاجرت انجام نشود، دسترسی کاربران به سیستم قدیمی قطع می شود. موفقیت این روش به تشکیل تیم های تخصصی، زمان بندی دقیق و اختصاص منابع کافی بستگی دارد.یکی از نکات مهم در این فرایند، تعیین مکانیزم هایی برای اعمال قانون است. تیم مسئول باید اختیار کامل برای قطع دسترسی کاربران پس از اطلاع رسانی های کافی را داشته باشد. اما این فرایند نباید ظالمانه به نظر برسد و لازم است همراه با پشتیبانی مناسب انجام شود. برای مثال در گوگل از رویکردی تدریجی استفاده می شود که شامل قطعی های برنامه ریزی شده و افزایش تدریجی مدت این قطعی ها است. این روش به تیم ها کمک می کند وابستگی های خود را شناسایی و حذف کنند.هشدارهای مرتبط با دپریکیت کردن چه در Advisory Deprecation و چه در Compulsory Deprecation ابزار مهمی برای علامت گذاری سیستم های قدیمی و تشویق آن ها به مهاجرت هستند. اما این هشدارها تنها زمانی موثر خواهند بود که به درستی طراحی شوند:قابل اجرا: هشدار باید شامل راهکارهای عملی باشد که کاربران با مهارت متوسط نیز بتوانند آن را اجرا کنند.  زمان بندی مناسب: هشدار باید دقیقا زمانی نمایش داده شود که کاربر با موضوع مرتبط درگیر است، مانند هنگام کد نویسی یا استفاده از سیستم قدیمی.  اما باید مراقب باشیم که تعداد زیاد هشدارها منجر به کلافگی ناشی از هشدار نشود، چون این اتفاق باعث می شود کاربران نسبت به هشدارها بی تفاوت شوند. هشدارهای دقیق و به موقع می توانند سرعت مهاجرت را افزایش دهند، اما به تنهایی برای کاهش وابستگی به سیستم های قدیمی کافی نیستند و نیازمند اقدامات بیشتری هستند.یکی از چالش های مهم در فرایند دپریکیشن، تعیین مالکیت برای پروژه های قدیمی است. اگر پروژه ای مالک مشخصی نداشته باشد، احتمال پیشرفت در فرایند دپریکیشن بسیار پایین خواهد بود، حتی اگر هشدارهای زیادی صادر شود. در سازمان های بزرگ معمولا پروژه هایی وجود دارند که همچنان استفاده می شوند اما مالک مشخصی ندارند. گاهی این وضعیت به دلیل انتقال مالک پروژه به سیستم های جایگزین رخ می دهد. بدون تعیین مالکیت پروژه ها در حالت تعلیق باقی می مانند و فرایند دپریکیشن دچار اختلال می شود.منبع: کتاب Software Engineering at Google</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Sun, 12 Jan 2025 17:17:49 +0330</pubDate>
            </item>
                    <item>
                <title>چرا و چگونه سیستم ها را دپریکیت کنیم؟ - بخش دوم</title>
                <link>https://virgool.io/@heysaeid92/%DA%86%D8%B1%D8%A7-%D9%88-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7-%D8%B1%D8%A7-%D8%AF%D9%BE%D8%B1%DB%8C%DA%A9%DB%8C%D8%AA-%DA%A9%D9%86%DB%8C%D9%85-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-t02h383682gg</link>
                <description>در بخش اول متوجه شدیم که چرا دپریکیت کردن سیستم های قدیمی مهم است، چگونه این فرایند می تواند سرعت توسعه را افزایش دهد، و چرا کد را باید به عنوان بدهی در نظر گرفت. همچنین به اهمیت برنامه ریزی از ابتدا برای ساده تر کردن حذف سیستم ها اشاره کردیم.بخش اول: https://vrgl.ir/a2UQzقانون Hyrum می گوید هرچه شمار کاربران یک سیستم بیشتر باشد، احتمال استفاده آن ها از سیستم به روش های غیر منتظره بیشتر است. این موضوع فرایند دپریکیت کردن و حذف سیستم را به شدت پیچیده می کند. در این شرایط، چیزی که در ظاهر کار می کند، در واقع تضمینی برای عملکرد صحیح ندارد. حذف یک سیستم در این شرایط تغییری اساسی است که نه تنها در آن رفتار سیستم را تغییر می دهیم، بلکه آن را به طور کامل از بین می بریم. این تغییر معمولا وابستگی های پنهان و پیش بینی نشده زیادی را نمایان می کند.معمولا تا زمانی که یک سیستم جدیدتر با کارکرد مشابه یا بهتر آماده نشود، دپریکیت کردن سیستم های قدیمی ممکن نیست. سیستم جدید همیشه تفاوت هایی با سیستم قدیمی دارد، حتی اگر کارآمدتر باشد. این تفاوت ها موجب می شود پیدا کردن تطابق کامل بین سیستم قدیمی و جدید دشوار باشد و لازم است برای هر مورد استفاده خاص، راه حل متناسب با سیستم جدید پیدا کنیم. در گوگل یک شوخی قدیمی وجود دارد که می گوید دو راه برای انجام کارها وجود دارد، راهی که منسوخ شده و راهی که هنوز آماده نیست!. این اتفاق زمانی رخ می دهد که راه حل جدید تقریبا آماده باشد اما هنوز نمی تواند جایگزین سیستم قدیمی شود.دپریکیت کردن سیستم علاوه بر زمان بر بودن، هزینه بر نیز هست. تشکیل یک تیم، صرف منابع و اجرای این فرایند نیاز به تامین بودجه و برنامه ریزی دقیق دارد. در مقابل، هزینه های پنهان ناشی از حفظ سیستم های قدیمی به راحتی قابل اندازه گیری نیستند و این امر متقاعد کردن ذی نفعان برای پذیرش دپریکیشن را دشوارتر می کند. به خصوص وقتی که این فرایند ممکن است توسعه ویژگی های جدید را به تعویق بیندازد.با توجه به این سختی ها، بسیاری از سازمان ها به جای جایگزینی کامل سیستم های قدیمی، تلاش می کنند آن‌ها را به تدریج بهبود دهند. این رویکرد فرایند دپریکیشن را حذف نمی کند، اما آن را به مراحل کوچک تر و مدیریت پذیرتر تقسیم می کند. این روش علاوه بر کاهش هزینه ها، ارزش تدریجی بیشتری برای کاربران ایجاد می‌کند.گوگل به این نتیجه رسیده است که مهاجرت به سیستم های کاملا جدید فوق العاده پرهزینه است و هزینه های آن اغلب دست کم گرفته می شود. برای همین تلاش های تدریجی برای ارتقای سیستم های موجود، علاوه بر کاهش هزینه ها، امکان ارائه ارزش به کاربران را ساده تر می کند.شاید طراحی سیستم هایی که بتوان آن ها را به راحتی دپریکیت کرد، در نگاه اول عجیب به نظر برسد. اما این رویکرد در سایر رشته های مهندسی، مثل ساخت نیروگاه های هسته ای، کاملا معمول است. همان طور که برنامه ریزی برای تعطیلی یک نیروگاه از ابتدا انجام می شود، سیستم های نرم افزاری نیز می توانند با در نظر گرفتن پایان عمرشان طراحی شوند. ولی در دنیای نرم افزار این رویکرد اغلب نادیده گرفته می شود. فشار برای انتشار سریع محصولات جدید، افراد را مجبور می کند بیشتر بر ساخت و توسعه تمرکز کنند تا مدیریت پایان عمر سیستم.برای طراحی سیستم هایی که بتوان به راحتی آن ها را دپریکیت کرد، باید به این سوالات اساسی پاسخ داد:1. انتقال کاربران به سیستم جایگزین چقدر ساده است؟  2. چگونه می توان بخش هایی از سیستم را به تدریج جایگزین کرد؟  منبع: کتاب Software Engineering at Google</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Fri, 10 Jan 2025 21:43:50 +0330</pubDate>
            </item>
                    <item>
                <title>چرا و چگونه سیستم ها را دپریکیت کنیم؟ - بخش اول</title>
                <link>https://virgool.io/@heysaeid92/%DA%86%D8%B1%D8%A7-%D9%88-%DA%86%DA%AF%D9%88%D9%86%D9%87-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7-%D8%B1%D8%A7-%D8%AF%D9%BE%D8%B1%DB%8C%DA%A9%DB%8C%D8%AA-%DA%A9%D9%86%DB%8C%D9%85-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-kjmxxbtrupfs</link>
                <description>ممکن است تصور کنید نرم افزارها یک دارایی دیجیتال هستند و نیازی به نگرانی درباره گذر زمان ندارند، اما این درست نیست. حتی اگر نرم افزارها فرسوده نشوند، گذر زمان و ظهور تکنولوژی های جدید و تغییرات محیطی، سیستم های موجود را از رده خارج می کند. سیستم های قدیمی به مرور زمان از اکوسیستم پیرامون خود فاصله می گیرند و نگه داری از آن ها نیاز به تلاش بیشتر، تخصص پیچیده تر و منابع اضافی دارد. به همین دلیل، اغلب بهتر است این سیستم ها را جایگزین کنیم تا اینکه اجازه دهیم در کنار سیستم های جدید همچنان فعال بمانند.تعداد بالای سیستم های قدیمی فعال نشان می دهد که کنار گذاشتن آن ها کار ساده ای نیست. برای این کار نیاز به فرایندی منظم داریم که شامل برنامه ریزی برای مهاجرت، حذف تدریجی و در نهایت جایگزینی کامل باشد. این فرآیند که به آن &quot;دپریکیت کردن&quot; می گوییم، نیازمند تفکر دقیق و مدیریت سیستم در طول زمان است. این کار بیشتر به حوزه مهندسی نرم افزار مربوط می شود تا صرفا برنامه نویسی.اگر این فرایند به درستی انجام شود، می تواند سرعت توسعه را افزایش دهد. اما اگر اشتباه پیش برود، ممکن است هزینه ای بیشتر از حفظ سیستم قدیمی برای سازمان به همراه داشته باشد. نکته مهم این است که از همان مراحل ابتدایی طراحی سیستم، به دپریکیت کردن فکر کنیم تا این فرایند در زمان مناسب ساده تر و کم هزینه تر باشد.اساس بحث ما در دپریکیت کردن این است که به کد به عنوان یک &quot;بدهی&quot; نگاه کنیم، نه یک &quot;دارایی&quot;. کد هزینه دارد، بخشی از این هزینه هنگام ساخت پرداخت می شود، اما قسمت بیشتر آن در طول عمر سیستم صرف نگه داری، بروزرسانی و مدیریت آن می شود. بنابر این برای تصمیم گیری درباره دپریکیت کردن یک سیستم، باید هزینه ها و مزایا آن را به دقت بررسی کنیم.نکته مهم این است که صرفا قدیمی بودن سیستم، دلیل کافی برای دپریکیت کردن آن نیست. بسیاری از سیستم های قدیمی مثل LaTeX، با وجود قدیمی بودن، همچنان کارآمد هستند و به تدریج بهبود پیدا می کنند. برای همین قدیمی بودن سیستم به تنهایی معیار مناسبی برای حذف آن نیست.شاید این سوال پیش بیاید که اگر کد یک بدهی است، چرا این قدر برای نوشتن و بهبود آن تلاش می کنیم؟ پاسخ ساده است، کد به خودی خود ارزشی ندارد. آنچه ارزشمند است، فانکشنالیتی است که کد ارائه می دهد. کدی که بتواند نیاز کاربران را برطرف کند یک دارایی به حساب می آید. اگر همان فانکشنالیتی را بتوان با کدی ساده تر و قابل نگهداری تر به دست آورد، دیگر نیازی به هزاران خط کد پیچیده نیست.به همین دلیل، به جای تمرکز بر روی حجم کدها، باید به این فکر کنیم که هر خط کد چه مقدار فانکشنالیتی ارائه می دهد. یکی از بهترین راه ها برای رسیدن به این هدف، حذف کدها و سیستم هایی است که دیگر نیازی به آن ها نداریم. فرایند دپریکیت کردن راهی ارزشمند برای این کار است.حتی شرکت های بزرگ مثل گوگل همچنان در حال یادگیری بهترین روش ها برای دپریکیت کردن سیستم ها هستند. این فرایند گاهی مطابق برنامه پیش می رود و گاهی هم نه. به طور کلی، حذف سیستم های قدیمی همچنان یک چالش پیچیده و در حال پیشرفت می باشد.یکی از محدودیت ها در دپریکیت کردن، منابع و ظرفیت تیم ها و همچنین نیازهای مشتریان می باشد. برای مثال، تصور کنید اداره راه تصمیم بگیرد تمام جاده ها را یکجا تعطیل و بازسازی کند. نتیجه آن چیزی جز هرج مرج نمی باشد. برای همین سازمان ها نیاز به دقت و متمرکز کردن کار دارند.منبع: کتاب Software Engineering at Google</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 09 Jan 2025 21:49:08 +0330</pubDate>
            </item>
                    <item>
                <title>پنج نشانه‌ای که نشان می‌دهد یک معماری ضعیف ساخته‌ایم (و راهکارهای رفع آن)</title>
                <link>https://virgool.io/@heysaeid92/%D9%BE%D9%86%D8%AC-%D9%86%D8%B4%D8%A7%D9%86%D9%87-%D8%A7%DB%8C-%DA%A9%D9%87-%D9%86%D8%B4%D8%A7%D9%86-%D9%85%DB%8C-%D8%AF%D9%87%D8%AF-%DB%8C%DA%A9-%D9%85%D8%B9%D9%85%D8%A7%D8%B1%DB%8C-%D8%B6%D8%B9%DB%8C%D9%81-%D8%B3%D8%A7%D8%AE%D8%AA%D9%87-%D8%A7%DB%8C%D9%85-%D9%88-%D8%B1%D8%A7%D9%87%DA%A9%D8%A7%D8%B1%D9%87%D8%A7%DB%8C-%D8%B1%D9%81%D8%B9-%D8%A2%D9%86-pdesxpkyrtfq</link>
                <description>John Vester - dzone . comتیم های توسعه در جریان تلاش برای ارائه Value ها ممکن است ناخواسته معماری هایی ایجاد کنند که در بلندمدت محدودیت هایی را برای آنها ایجاد کند. در ابتدا همه چیز خوب به نظر می رسد، فیچرها به سرعت منتشر می شوند، تست های CI با موفقیت اجرا می شوند و پروداکت بدون مشکل کار می کند. اما در پشت این پیشرفت های ظاهری، ممکن است که پیچیدگی های کنترل نشده شکل بگیرند. ارتباطات ساده بین اجزا می توانند به وابستگی های پیچیده و درهم تنیده تبدیل شوند که چابکی را دچار مشکل و سرعت را کم می کنند. داشتن فلوهای بیش از حد پیچیده، وابستگی های غیرضروری و بدهی فنی مشکلات معماری را تشدید می کنند و تیم ها را در بدترین زمان ها در برابر شکست ها آسیب پذیر می کند.در ادامه 5 مورد مهم تاثیر گذار در این موضوع رو باهم بررسی می کنیم:Dependencies Everywhereیک شبکه پیچیده از وابستگی ها که مقیاس پذیری و به روزرسانی را به یک کابوس تبدیل می کنند.Your Architecture Isn’t as Clean as Your Code توهمی از پایه های قویYour Codebase Is a Black Boxنداشتن دید کافی برای مدیریت و بهبود سیستمNo Governance, No Control بدون داشتن قوانین و برنامه هایی برای نظارت بر آن ها، پیچدگی ها به سرعت افزایش پیدا می کنند.You’re Living in a Complete Meshهرج و مرج در ارتباطات که دیباگ و جدا کردن بخش ها را دشوار می کند.در این مطلب با مقایسه این مشکلات با اصول اثبات شده معماری، یکسری راه حل های عملی مطرح می شود که به شما کمک می کند دوباره کنترل را به دست آورید یا از اول آن را از دست ندهید. همچنین در ادامه نشان خواهیم داد ابزارهایی مانند vFunction, Micrometer یا Dash0 چگونه می توانند نقش مهمی در کنترل معماری داشته باشند.1. Dependencies Everywhereمعماری بدوابستگی ها از تله های پنهان در معماری نرم افزار هستند. وقتی سیستم ما پر از وابستگی باشد، چه آنها لایبرری های خارجی باشند، چه ماژول های به شدت مرتبط یا میکروسرویس های وابسته به یکدیگر باشند، یک شبکه پیچیده از وابستگی ها ایجاد می شود که مدیریت آن دشوار است. این وضعیت باعث سخت شدن لوکال دیباگ می شود، چون هر تغییری ممکن است بخش دیگر را ایمپکت کند. و به صورت کلی دیپلوی کردن سخت تر، ترابل شوتینگ طولانی تر و خطر شکست های زنجیرهای بیشتر می شود. در نتیجه تیم ما باید زمان بیشتری را برای حل مشکلات بگذارد و زمان کمتری برای خلاقیت دارد.یک مثال کلاسیک برای این موضوع، &quot;Domino Effect&quot; است، جایی که به روزرسانی یک وابستگی مشترک باعث ایجاد خطاهای غیرمنتظره در چندین سرویس یا بخشی از کد می شود. یک نمونه دیگر از این مشکل زمانی رخ می دهد که میکروسرویس ها به حدی به یکدیگر وابسته هستند که باید به صورت همزمان دیپلوی شوند و این کار هدف اصلی، یعنی جداسازی آنها را از بین می برد. این سطح از شکنندگی مقیاس پذیری را مختل می کند و سیستم ما را در برابر فشارها آسیب پذیر می کند.معماری خوبدر یک معماری خوب وابستگی ها را با اولویت دادن به ماژولار بودن و کاهش ارتباطات مستقیم به حداقل می رسانیم. اجزای داخلی سیستم باید ایزوله باشند و از طریق API های تعریف شده با یکدیگر ارتباط برقرار کنند، این رویکرد کدبیس ما را ساده تر، تست ها را سریع تر و دیپلوی را مطمئن تر می کند.همچنین ماژولار بودن به ما اجازه می دهد وابستگی ها را به راحتی جایگزین یا به روزرسانی کنیم. اصول طراحی خوب مانند DDD یا DIP تضمین می کنند که سیستم ها سازگار باقی بمانند و از درهم تنیدگی جلوگیری می کند. یک معماری تمیز این اعتماد به نفس را به ما می دهد تا بدون نگرانی ازخراب شدن سیستم تغییرات خود را انجام دهیم.مراقب باشیم...کاهش وابستگی ها به معنای حذف کامل آنها یا تقسیم سیستم به نانوسرویس ها نیست. شاید با داشتن یک واکنش افراطی، داشتن سرویس های کوچک به شدت جزئی یک راه حل خوب به نظر برسد، اما این کار بیشتر اوقات باعث ایجاد پیچیدگی بیشتر می شود. در این شرایط ما باید ده ها یا صدها بخش مختلف را مدیریت کنیم که هرکدام نیاز به نگهداری، مانیتور کردن و ارتباطات جداگانه دارند.به جای این کار باید دنبال تعادل باشیم. مرزهایی را برای میکروسرویس های خود تعریف کنیم که Cohesion را تقویت کند و از تکه تکه شدن غیرضروری آنها جلوگیری کند. باید به دنبال معماری باشیم که سرویس ها به صورت کاربردی باهم تعامل داشته باشند اما بیش از حد به یکدیگر وابسته نباشند. این رویکرد باعث افزایش انعطاف پذیری و تاب آوری سیستم می شود.2. Your Architecture Isn’t as Clean as Your Codeمعماری بدتمرکز بر روی متریک هایی مانند Code Quality یا Deployment Frequencies صرفا توهم موفقیت ایجاد میکنه. ابزارهای AI شاید کدی کاملا تمیز و بدون خطا تولید کنند، اما خروجی آن ها بیشتر اوقات به مشکلات عمیق تر معماری توجهی ندارند. سیستم هایی که پر از Circular Dependency ها، سرویس های Tightly Coupled یا Business Bundry های نامنسجم هستند، بدهی های فنی را انباشته می کنند که ابزارهای AI نمی توانند آن ها را برطرف کنند.سازمان هایی که به دنبال راه حل های سریع با AI هستند، اغلب متوجه می شوند که سیستم هایشان به مرور زمان غیرقابل نگهداری می شوند. نداشتن حاکمیت و نظارت بر تکامل معماری باعث کاهش سرعت تحویل و افزایش هزینه ها می شود. کد ما ممکن است در حالت جداگانه تمیز به نظر برسد، اما سیستم کلی ای که ایجاد می کنیم به یک هرج و مرج و درهم تنیدگی تبدیل می شود.معماری خوبیک معماری خوب فراتر از تمیزی کد می باشد و بر سلامت کلی و مقیاس پذیری سیستم تمرکز دارد. سازمان ها نباید فقط بر معیارهای سطحی تمرکز کنند، بلکه باید به سمت حاکمیت مبتنی بر ابزار حرکت کنند که کیفیت معماری را در زمان واقعی اندازه گیری کنند. ابزارهایی مانند vFunction برای مشاهده معماری به تیم ها امکانات زیر را می دهد:معماری Clean خود را در مقایسه با طراحی مستند، مشاهده و بررسی کنند.در هر ریلیز مشکلات معماری و فلوهای بیش از پیچیده را شناسایی کنند.از وابستگی ها نقشه برداری کنند تا بتوانند آن ها را اصلاح و استانداردسازی کنند.با مشخص کردن تسک های مشخص و قابل اجرا از از پیچیدگی های غیرضروری جلوگیری کنند.تیم های موفق سیستم هایی می سازند که در آن کد تمیز با معماری تمیز و حاکمیت مناسب همراه باشد.مراقب باشیم...باید از واکنش افراطی خودداری کنیم و حاکمیت سختگیرانه ای را ایجاد نکنیم که خلاقیت تیم را سرکوب کند. معماری باید در کنار نیازهای بیزینس رشد کند و قوانین بیش از حد می توانند توسعه را کند یا از تست ها جلوگیری کنند. در عوض باید حاکمیت به عنوان یک راهنما عمل کند، نه یک محدودیت. باید توجه داشته باشیم که هدف رسیدن به کمال نیست، بلکه حفظ انعطاف پذیری با تحت کنترل نگه داشتن بدهی های فنی و پیچیدگی ها می باشد.با در نظر گرفتن معماری به عنوان یک جنبه تکاملی و قابل مشاهده، می توانیم تا حدودی نگهداری بلندمدت را تضمین کنیم و نوآوری را بدون قربانی کردن کیفیت افزایش دهیم. کد تمیز و معماری تمیز با یکدیگر از توسعه پایدار حمایت می کنند.3. Your Codebase Is a Black Boxمعماری بدیک کدبیس بلک باکس، دشمن خاموش پروداکتیویتی است. اگر تیم ما نتواند به راحتی ساختار، وابستگی ها یا رفتار سیستم را تشخیص دهد، هر تغییری به یک قمار پرخطر تبدیل می شود. دیباگ کردن به یک جستجوی بی هدف تبدیل می شود، اضافه کردن فیچرهای جدید نیازمند عبور از یک هزارتوی از ناشناخته ها می باشد و مقیاس پذیری به حدس و گمان وابسته می شود.دلیل این مشکل، نبود شفافیت در معماری است. گستردگی کد، وابستگی های مستند نشده و رفتارهای پیچیده که در اعماق سیستم های قدیمی دفن شده اند. در چنین شراطی، تیم ها اغلب به &quot;دانش گروهی&quot; متکی هستند، در این شرایط فقط تعداد کمی از افراد ارشد واقعا می دانند سیستم چگونه کار می کند، برای همین وقتی آن ها تیم را ترک می کنند این دانش نیز با آن ها می رود. در نتیجه توسعه کند، سیستم ها شکننده و بدهی فنی به صورت تصاعدی افزایش پیدا می کند.معماری خوبدر یک معماری خوب معماری خوبشفافیت و قابل درک بودن در اولویت می باشد. ابزارهایی مانند vFunction یا Dash0 می توانند معماری ما را از سایه ها بیرون آورده و آن را شفاف کنند. این ابزارها قابلیت های Architectural Observability را فراهم می کنند که به ما امکان می دهد که کدبیس خود را تجسم کنیم و مرزهای سرویس ها، وابستگی ها و نقاط ناکارآمد را شناسایی کنیم.با استفاده از vFunction می توانیم معماری پیچیده میکروسرویس ها را به صورت Real-time مستند کنیم که این کار پیدا کردن باگ ها را آسان تر می کند و معماری به صورت کد (Architectural as Code) را با ابزارهایی مانند mermaid برای Sequence Diagram به تصویر بکشیم.این شفافیت به ما اجازه می دهد که مستقیما با بدهی معماری رو به رو شویم. با شناسایی کردن وابستگی های شدید، ماژول های قدیمی یا پیچیدگی های غیرضروری می توانیم تصمیم های آگاهانه برای بازسازی، ماژولار کردن و مقیاس پذیری بگیریم. علاوه بر آن سیستمی که به خوبی مستند و درک شده باشد، توسعه دهندگان جدید راحت تر می توانند به پروژه اضافه شوند و حتی پروژه های پیچیده نیز با گذشت زمان قابل مدیریت باقی می مانند.مراقب باشیم...اما باید توجه داشته باشیم که صرفا داشتن شفافیت مشکل را حل نمی کند. اینکه بدانیم بدهی کجا می باشد ولی اقدامی برای رفع آن نداشته باشیم، مانند تشخیص یک موتور خراب است که از تعمیر آن خودداری می کنیم.همچنین شفافیت باید با یک چارچوب حاکمیتی همراه شود تا از بازگشت مشکلات مشابه جلوگیری کند. باید دستورالعمل هایی برای معماری تعریف کنیم، استانداردهای کدنویسی را اجرا و تست های خود را پیاده سازی کنیم تا سیستم در حین رشد، قابل نگهداری و مقیاس پذیر باقی بماند. معماری خوب یک فرآیند مداوم است، نه یک تلاش یکباره.4. No Governance, No Controlمعماری بدبدون داشتن حاکمیت قوی در معماری، حتی بهترین تیم ها می توانند به شکل ناخواسته دچار هرج و مرج شوند. در نبود این استاندارها و نظارت های روشن، یکسری سیلو شکل می گیرد. هر تیم راه حل های خود را توسعه می دهد، پترن ها را به شکل ناسازگار استفاده می کند، تکنولوژی های جدید را بدون هماهنگی و همراستایی به کار می گیرد، بلک باکس ایجاد می کند یا کارها را در پروژه های مختلف تکرار می کند. با گذشت زمان این وضعیت به یک معماری تکه تکه تبدیل می شود که پر از افزونگی ها و پیچیدگی ها است.نداشتن هماهنگی می تواند باعث رشد بی رویه معماری شود، جایی که میکروسرویس ها بدون کنترل گسترش پیدا می کنند و بدهی فنی مدام افزایش پیدا می کند. بدتر از آن تشخیص و حل مشکلات به چالشی دشوار و عذابآور تبدیل می شود، زیرا هیچ درک مشترکی یا استراتژی منسجمی برای هدایت تیم ها وجود ندارد.معماری خوبحاکمیت چسبی است که معماری ما را یکپارچه نگه می دارد. یک برنامه حاکمیتی قوی، استانداردها، دستورالعمل ها و کارآمد از آنها پیروی می کند. این برنامه تضمین می کند که هر تصمیم معماری با اهداف کلی بیزینس همسو باشد و از رشد کنترل نشده میکروسرویس ها جلوگیری می کند.با استفاده از راهکار حاکمیت معماری vfunction، می توانیم مشکلات معماری را شناسایی کنیم و اطمینان حاصل کنیم که تیم ها با پترن های تعریف شده همراستا هستند. این ابزار با ارائه بینش های Real-time از طراحی سیستم، به ما کمک می کند تا بر استانداردهای معماری نظارت کنیم. برای مثال می توانیم ارتباطات مجاز بین سرویس ها و تعاملات را چک کنیم. همچنین علاوه بر آن، می توانیم با ایجاد ADR تصمیمات و مباحثی که منجر به آنها شده را مستند کنیم.مراقب باشیم...درست است که حاکمیت ضروری است، اما نباید به قیمت از دست دادن چابکی یا نوآوری تمام شود. داشتن برنامه های حاکمیتی بیش از حد سختگیرانه می تواند به باتلنک هایی تبدیل شود که توسعه را کند و از تست جلوگیری کند. در این شرایط ممکن است توسعه دهندگان احساس محدودیت کنند و به دنبال راه هایی برای دورزدن قوانین باشند که این مسئله مشکل را بدتر می کند.کلید موفقیت برای این موضوع در ایجاد تعادل است. حاکمیت باید بدون آنکه خلاقیت را سرکوب کند، باید حاکمیت را به عنوان یک نقشه روشن برای برای توسعه دهندگان در نظر بگیریم، نه بعنوان محدودیتی برای حرکت آن ها، بلکه باید آن را به عنوان ابزاری که به آنها کمک می کند هوشمندتر و سریع تر مسیر خود را پیدا کنند در نظر بگیریم.5. You’re Living in a Complete Meshمعماری بدیک شبکه سرویس که در آن سرویس ها به طور بیش از حد به یکدیگر متصل و وابسته هستند، می تواند توسعه را فلج کند. در این آنتی پترن، مسیرهای ارتباطی بین سرویس ها به قدری پیچیده می شوند که حتی تغییرات کوچک یا خرابی در یک بخش از سیستم می توانند تاثیرات زنجیرهای در کل برنامه ایجاد کنند.برای مثال، تصور کنید یک سرویس برای تکمیل یک تراکنش باید پنج سرویس دیگر را فراخوانی کند، و هرکدام از آن سرویس ها نیز به فراخوانی های بیشتر در سرویس های پایین دستی وابسته باشند. این کار باعث افزایش تاخیر، افزونگی بیشتر و پیچدگی بالای عملیات می شود.معماری خوبدر یک معماری خوب از ایجاد چنین شبکه هایی اجتناب می کنیم و بر مرزهای شفاف و تعریف شده سرویس ها و کاهش ارتباطات بین سرویس ها تمرکز داریم. سرویس ها باید وظایف مشخص و منسجمی داشته باشند تا حد امکان مستقل عمل کنند.برای کاهش وابستگی ها، از مکانیسم هایی مانند message queues و event streams استفاده میکنیم. این روش نه تنها وابستگی های مستقیم را کاهش می دهد، بلکه Fault Tolerance را نیز بهبود می بخشد و به سرویس ها اجازه می دهد در صورت عدم دسترسی سرویس های بالا دستی یا سرویس های پایین دستی به کار خود ادامه دهند. همچنین طراحی فلو ارتباطات به شکل یکطرفه (تا حد امکان) مدیریت وابستگی ها را ساده تر و سیستم را پیش بینی پذیرتر می کند.مراقب باشیم...همانطور که ارتباط بیش از حد صحیح نیست، جداسازی بیش از حد نیز می تواند باعث ایجاد مشکل شود. جداسازی کامل سرویس ها بدون نیاز صریح بیزینس می تواند باعث کارهای تکراری، Data Inconsistency و ناتوانی در اشتراک گذاری موثر قابلیت های شود. در اینجا هدف تعادل و کاهش وابستگی های غیر ضروری همراه با اطمینان از ارتباط سرویس ها در مواقع نیاز است. ابزارهایی مانند vFunction و ESLint و موارد مشابه می توانند به ما در رسیدن به این تعادل کمک کنند.معماری خود را باید مانند شبک های از بزرگراه ها تصویر کنیم: ترافیک باید صورت روان جریان داشته باشد، بدون تقاطع های غیرضروری یا بن بست. با استفاده از ابزارهای مناسب می توانیم از مشکلات یک شبکه کاملا درهم تنیده جلوگیری کنیم و معماریای مقیاس پذیر و Resilience بسازیم.منبع: John Vester - dzone . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 02 Jan 2025 10:54:36 +0330</pubDate>
            </item>
                    <item>
                <title>راه طولانی و پرپیچ‌ و خم به سوی تاب‌ آوری - بخش پنجم</title>
                <link>https://virgool.io/@heysaeid92/%D8%B1%D8%A7%D9%87-%D8%B7%D9%88%D9%84%D8%A7%D9%86%DB%8C-%D9%88-%D9%BE%D8%B1%D9%BE%DB%8C%DA%86-%D9%88-%D8%AE%D9%85-%D8%A8%D9%87-%D8%B3%D9%88%DB%8C-%D8%AA%D8%A7%D8%A8-%D8%A2%D9%88%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%D9%BE%D9%86%D8%AC%D9%85-cti9guaeknid</link>
                <description>در پست قبلی، درباره &quot;تله 100% Availability&quot; صحبت کردیم. در این پست به آنچه در مرحله Robustness خواهیم رسید، می پردازیم.بخش چهارم: https://vrgl.ir/XZgdLاین مرحله، دومین توقفگاه موقت سازمان ها در مسیر تاب آوری است. به دلیل اینکه رسیدن به آن نیازمند تغییر نگرش است و تغییر نگرش معمولا سخت و زمان بر است، تعداد کمی از شرکت ها به این مرحله می رسند. این تغییر نیازمند پذیرش این واقعیت است که شکست ها اجتناب ناپذیر هستند:ما نمی توانیم از شکست ها به شکل کامل جلوگیری کنیم، پس بیایید آن ها را بپذیریم.البته این موضوع به معنای بی توجهی برای جلوگیری از شکست نیست. بهتر است به جای تجربه یک شکست در هرساعت، تنها یک بار در هفته آن را تجربه کنیم. اما موضوع اصلی این است که نباید تنها بر پیشگیری از شکست متکی باشیم، یعنی فرض کنیم که با افزایش MTTF تنها یک بار در قرن دچار مشکل شویم!پذیرش شکست هابپذیریم امکان جلوگیری کامل از شکست ها محدود است. ما می توانیم آن ها را کاهش دهیم، اما نمی توانیم آن ها را به طور کامل حذف کنیم. برای همین بهتر است روی مدیریت شکست ها تمرکز کنیم، برای مثال کاهش اثرات آن ها یا بازیابی سریع.تفکر اصلی در این مرحلهمی خواهیم Availability را به حداکثر برسانیم. برای این کار باید بخشی از تمرکزمان را بر افزایش MTTF قرار دهیم، و از آن مهم تر باید راه هایی را برای کاهش MTTR پیدا کنیم، یعنی سریعا شکست ها را شناسایی و بازیابی کنیم یا حداقل اثرات آن ها را کاهش دهیم. سوالات مهم:- چه چیزی ممکن است با مشکل مواجه شود و چگونه می توانم به آن پاسخ دهم؟- اگر یک سرویس در دسترس نباشد، چه کاری می توانم انجام دهم؟- چگونه می توانم درخواست ها و پاسخ های نامعتبر را شناسایی و مدیریت کنم؟- چگونه می توانم سریعا باگ ها و مشکلات دیگر را برطرف کنم؟سوال اول یک سوال کلی و جامع است. اما سوالات دیگر مثال هایی برای انواع خاصی از شکست ها هستند.برای این سوالات، ما باید مجموعه از اقدامات را انجام دهیم:1- پیاده سازی جایگزین ها (Fallbacks): انجام پاسخ های جایگزین منطقی در سطح بیزینس که در صورت وقوع خطا تکنیکال، به جای مسیر اصلی درخواست انجام می شوند.2- بررسی کامل پارامترها: بررسی دقیق پارامترهای ورودی. درست است که این اقدام بدیهی به نظر می رسد، اما در بسیاری از موارد به درستی اجرا نمی شود.3- اتومات کردن Deploy: استفاده از CI/CD و ابزارهایی مانند IaC/IfC. این کار بیشتر بر سرعت تمرکز دارد تا repeatability. هر چه استقرار نسخه های جدید سریع تر انجام شود، MTTR در مواجه با خطاها کاهش پیدا می کند.4- کاهش زمان راه اندازی سیستم ها: کاهش زمان راه اندازی بخش ها می تواند MTTR را به طور قابل توجهی بهبود ببخشد، بدون اینکه فقط به Redundancy و Failover متکی باشد.5- نظارت دقیق در سطح برنامه و بیزینس: برای شناسایی زودهنگام خطاها و مدیریت آن ها قبل از اینکه به شکست تبدیل شوند.توضیح تفاوت بین Failure, Fault و Error از Robert S. Hanmer:Fault: نقص که در سیستم وجود دارد و ممکن است باعث ایجاد خطا شود. مانند یک باگ نرم افزاریError: رفتار نادرست سیستم که از درون سیستم قابل مشاهده است و ممکن است منجر به شکست شود، اما از بیرون قابل مشاهده نیست. از بیرون سیستم همچنان عمل می کند.Failure: رفتار نادرست سیستم که از بیرون قابل مشاهده است. یعنی رفتار سیستم با چیزی که باید باشد یکسان نیست.مدیریت خطا معمولا به دو روش انجام می شود:1- Error Recovery: رفع علت خطا و بازگرداندن سیستم به وضعیت عادی.2- Error Mitigation: استفاده از Graceful Degradation تا زمانی که مشکل رفع شود یا شرایط برای رفع آن فراهم شود.در بهترین حالت، خطا فورا رفع می شود و عملیات عادی ادامه می یابد بدون اینکه کسی متوجه مشکل شود. اما گاهی اوقات سیستم فاقد زمان، اطلاعات یا منابع لازم برای بازیابی فوری است.Graceful Degradationاگر سیستم نتواند فورا خطا را رفع کند، باید سرویس های خود را به صورت کنترل شده کاهش دهد:- در شرایط Overload، شاید بعضی از درخواست ها را حذف کنیم.- اگر دسترسی به دیتابیس با مشکل مواجه شود، می توانیم داده ها را از کش بخوانیم و درخواست های write را نپذیریم.FallBack Patternاین پترن می پرسد، اگر چیزی مطابق انتظار عمل نکرد، چه کاری باید انجام داد؟ برای مثال در صورت مشکل در برنامه A، برنامه B چیست؟اجرای FallBack نیازمند درگیر کردن بیزینس است. تصمیم درباره نحوه پاسخگویی سیستم به شکست های مختلف بسته به اهمیت و حساسیت آن ها متفاوت خواهد بود.- در صورت شکست در یک recommendation engine، ممکن است خطا به‌صورت بی صدا نادیده گرفته شود.- اما شکست در فرآیند پرداخت یک فروشگاه آنلاین موضوعی بسیار جدی خواهد بود.نقش بیزینس در این مرحلهیکی از تفاوت های اصلی بین پایداری و مقاومت:- در مرحله پایداری فرض بر این بود که می توان با روش های فنی از شکست ها جلوگیری کرد و نیازی به همکاری بخش بیزینس نبود.- در مرحله مقاومت مشخص است که شکست ها اجتناب ناپذیرند و باید پذیرفته شوند. این به معنای درگیر شدن بخش بیزینس برای تصمیم گیری درباره بهترین روش برای مدیریت شکست ها است.منبع: Uwe Friedrichsen - ufried . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Fri, 13 Dec 2024 20:36:45 +0330</pubDate>
            </item>
                    <item>
                <title>راه طولانی و پرپیچ‌ و خم به سوی تاب‌ آوری - بخش چهارم</title>
                <link>https://virgool.io/@heysaeid92/%D8%B1%D8%A7%D9%87-%D8%B7%D9%88%D9%84%D8%A7%D9%86%DB%8C-%D9%88-%D9%BE%D8%B1%D9%BE%DB%8C%DA%86-%D9%88-%D8%AE%D9%85-%D8%A8%D9%87-%D8%B3%D9%88%DB%8C-%D8%AA%D8%A7%D8%A8-%D8%A2%D9%88%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%DA%86%D9%87%D8%A7%D8%B1%D9%85-czgahsntmjap</link>
                <description>در بخش قبلی درباره ی سطح اول تاب آوری، پایداری صحبت کردیم. جایی که سیستم ها به ثبات نسبی می رسند اما هنوز تا تاب آوری کامل فاصله دارند. در این بخش درباره ی موضوع مهم تر، تله 100% Availability صحبت می کنیم.بخش سوم: https://vrgl.ir/6XMFjاین تله یک اشتباه رایج است که تصور می کند سیستم ها همیشه و تحت هر شرایطی در دسترس هستند. این طرز فکر معمولا از این پیش فرض نادرست ناشی می شود که مسئولیت Availability بر عهده ی تیم Ops است. در عمل این باور باعث نادیده گرفتن احتمال خرابی بخش هایی می شود که خارج از کنترل مستقیم یک تیم قرار دارند، مانند:Operating systemsRoutersMessage bussesDatabases...در طراحی های اغلب فرض می شود این ها همیشه در دسترس خواهند بود. اما این فرض اشتباه است و خرابی ها اجتناب ناپذیرند.برای مثال وقتی سرویس Kinesis در AWS دچار مشکل شد، بسیاری از شرکت‌ها به مشکل برخوردند، چون در طراحی سیستم هایشان احتمال خرابی این سرویس را پیش‌بینی نکرده بودند.این تله به یک توهم امنیت منجر می شود. طراح ها فکر می کنند که با استفاده از redundancy و روش های معمول دیگر، سیستم به 100% Availability می رسد. اما همانطور که می دانیم این مورد با اصول مهندسی قابل اعتماد در تضاد است. آقای Pat Helland میگه:Reliable systems have always been built out of unreliable components.در مقابل در توسعه ی سیستم های سازمانی معمولا برعکس عمل می شود: سیستم های غیرقابل اعتماد ساخته می شوند و انتظار دارند که infra آن ها را قابل اعتماد کند!سطح دوم: پذیرش خرابی هابرای پیشرفت در مسیر تاب آوری، باید قبول کنیم که خرابی ها اجتناب ناپذیرند. این پذیرش باعث می شود که از تلاش بیهوده برای جلوگیری از خرابی ها به سمت برنامه ریزی برای مدیریت و بهبود آن ها حرکت کنیم. آقای Michael Nygard میگه که:Continuous partial failure is the normal state of affairs.برای افزایش قابلیت Availability، از فرمول زیر استفاده می کنیم:Availability = MTTF / (MTTF + MTTR)MTTF: Mean Time To FailureMTTR: Mean Time To Recoveryدر سطح پایداری معمولا تلاش برای جلوگیری از خرابی ها هستش. هدف این که MTTF آن قدر بزرگ شود که MTTR اهمیتی نداشته باشد. اگر MTTF به 1.000.000 ساعت برسد(بیش از ۱۰۰ سال!) انتظار خرابی برای نسل های آینده می باشد و MTTR اهمیت چندانی نخواهد داشت. اما این فرض که MTTF آن قدر بزرگ است، باعث می شود که همه انتظار داشته باشند سیستم هرگز خراب نشود و این همان تله است. در نتیجه هرچند افزایش MTTF مهم است، اما این متریک حد بالایی دارد. برای همین کاهش MTTR اولویت بیشتری دارد.سطح سوم: شناخت انواع خرابی هادر اینحا به خرابی هایی فکر می کنیم که ممکن است سیستم ما را تحت تاثیر قرار دهند و اینکه چگونه می توانیم به سرعت سیستم را بازیابی کنیم. به عبارت دیگر چگونه می توانیم MTTR را کاهش دهیم. در سطح پایداری اغلب تمرکز افراد بر روی خرابی های ناشی از crash و overload است. اما خرابی ها فراتر از این دو مورد هستند. مانند:Omission failuresTiming failuresResponse failuresByzantine failuresSoftware bugsConfiguration bugs...اگر بپذیریم که خرابی ها اجتناب ناپذیرند، باید انواع خرابی ها را شناسایی کنیم و به طور خاص به این سوال پاسخ دهیم که چگونه می توانیم این خرابی ها را سریع تر شناسایی و رفع کنیم تا MTTR کاهش یابد.منبع: Uwe Friedrichsen - ufried . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Mon, 09 Dec 2024 06:32:59 +0330</pubDate>
            </item>
                    <item>
                <title>راه طولانی و پرپیچ‌ و خم به سوی تاب‌ آوری - بخش سوم</title>
                <link>https://virgool.io/@heysaeid92/%D8%B1%D8%A7%D9%87-%D8%B7%D9%88%D9%84%D8%A7%D9%86%DB%8C-%D9%88-%D9%BE%D8%B1%D9%BE%DB%8C%DA%86-%D9%88-%D8%AE%D9%85-%D8%A8%D9%87-%D8%B3%D9%88%DB%8C-%D8%AA%D8%A7%D8%A8-%D8%A2%D9%88%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%D8%B3%D9%88%D9%85-f5xtucbj9tpx</link>
                <description>در مطلب قبلی، درباره «دره تکمیل فیچرها» به عنوان نقطه شروع سفر ما به سوی تاب‌ آوری صحبت کردیم و متوجه شدیم که چنین ساختاری دیگه معمولا توصیه نمیشه. برای همین در ادامه بررسی خواهیم کرد که چرا با وجود نامناسب بودن این رویکرد همچنان شاهد چنین ساختارهایی در شرکت ها هستیم. سپس خواهیم دید که در اولین سطح تاب آوری به چه چیزی خواهیم رسید.پارت دوم:‌ https://vrgl.ir/G8BKzگذشته‌ای که هنوز زنده است!چرا هنوز این طرز فکر در شرکت‌ها وجود دارد که تیم Ops مسئول Availability است؟ در شرایطی که باقی تیم ها فقط بر روی فیچرها تمرکز دارند. اگر به سیستم ها توجه کنیم مشخص است که این طرز فکر دیگر کارساز نیست. برای درک بهتر این موضوع به گذشته برمیگردیم. در دهه ۲۰۰۰ بیشتر زیرساخت ها از برنامه های بزرگ و یک پارچه به نام مونولیتیک تشکیل شده بودن. این برنامه ها مستقل کار می کردند و اگر لازم می شد باهم ارتباط برقرار کنند، معمولا از batch updates استفاده می کردند. برای مثال سیستم A هرچند وقت یک بار یک فایل تولید می کرد و سیستم B آن دریافت و پردازش می کرد. خب در این سیستم ها اگر یک سیستم با مشکل مواجه می شد سیستم دیگری همچنان می توانست کار خودش را ادامه دهد. اما سیستم ها بسیار تغییر کرده اند. دیگر کسی نمی خواهد که یک یا چندبار در ساعت های مختلف به روزرسانی شوند. انتظار این است که همه چیز در همه جا و در لحظه در دسترس باشد. درحال حاضر سیستم ها به دو روش عمل می کنند:Pull-based: مصرف کننده اطلاعات هروقت که لازم باشد داده ها را از تولید کننده درخواست می کند.Push-based: تولید کننده هر تغییری را در لحظه برای مصرف کننده ها ارسال می کند.برای همین زیرساخت ها از سیستم های جداگانه به شبکه ای پیچیده و به Tightly Coupled تبدیل شده اند. سیستم ها دیگر فقط یک برنامه ساده نیستند، بلکه یک سیستم به یک سیستم توزیع شده بزرگ و پیچیده تبدیل شده اند که با معماری های مدرن مثل میکروسرویس ها و... کار می کنند.تیم Ops دیگر به تنهایی کافی نیستباتوجه به تغییرات دیگر نمی شود انتظار داشت تیم Ops به تنهایی مسئول Availability باشد. تاثیرات توزیع شدگی به لایه برنامه ها نفوذ کرده است و مشکلات در سطح برنامه باید توسط تیم Dev مدیریت شوند. به همین خاطر اولین سطح تاب آوری یعنی سطح پایداری مطرح می شود.ایستگاه اول: سطح پایداریپایداری اولین قدم شرکت ها در مسیر تاب آوری است. ایده اصلی این سطح آن است که هرکاری را که می توانیم باید انجام دهیم تا خرابی رخ ندهد. برای همین تیم Dev و Ops باهم همکاری می کنند:- در ابتدا تیم Ops ابزارهای زیرساختی را فراهم می کند و تیم توسعه از آنها برای جلوگیری از خرابی استفاده می کند.- در ادامه تیم Ops فیدبک می دهد که راه حل های تیم Dev چقدر موثر بوده اند و تیم Dev می تواند با استفاده از آن ها کار خود را بهبود دهد.پایداری در عمل - این سطح معمولا شامل اقدامات زیر است:- استفاده از ابزارهایی مثل Kubernetes برای ایجاد Redundancy.- پیاده سازی پترن هایی مانند Retry, Circuit breaker و ... برای مدیریت خطاها.- تنظیم محدودیت ها برای جلوگیری از overload یا استفاده از مقیاس پذیری خودکار.نقاط قوت- پیاده سازی آسان است و نیازی به تغییرات بزرگ در ساختارهای تیمی وجود ندارد.- هزینه ها نسبتا پایین است.ضعف ها- اگر سیستم توزیع شده است یا Availability بالایی نیاز داریم این سطح کافی نمی باشد.- مشکلات جدید سیستم های توزیع شده مثل پیچیدگی در تعاملات را پوشش نمی دهد.- برای سیستم های حیاتی مثل خدمات مالی مناسب نیست.در پایان, باید توجه داشته باشیم که سطح پایداری یک شروع خوب برای سفر تاب آوری است. چرا که این سطح می پذیرد تیم Ops به تنهایی نمی تواند مسئول Availability باشد و تیم Dev را هم درگیر می کند. اما اگر نیاز به Availability بسیار بالا یا مدیریت پیچیدگی سیستم های توزیع شده داریم, باید به سطح بعدی برویم. در بخش بعدی درباره &quot;تله 100% Availability&quot; صحب می کنیم و بررسی می کنیم که چگونه می توانیم از آن عبور کنیم.منبع: Uwe Friedrichsen - ufried . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 05 Dec 2024 12:34:28 +0330</pubDate>
            </item>
                    <item>
                <title>راه طولانی و پرپیچ‌ و خم به سوی تاب‌ آوری - بخش دوم</title>
                <link>https://virgool.io/@heysaeid92/%D8%B1%D8%A7%D9%87-%D8%B7%D9%88%D9%84%D8%A7%D9%86%DB%8C-%D9%88-%D9%BE%D8%B1%D9%BE%DB%8C%DA%86-%D9%88-%D8%AE%D9%85-%D8%A8%D9%87-%D8%B3%D9%88%DB%8C-%D8%AA%D8%A7%D8%A8-%D8%A2%D9%88%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%D8%AF%D9%88%D9%85-j1k6vgpi7cko</link>
                <description>در بخش اول پایه های مربوط به سفر خود را به سوی تاب آوری بنا نهادیم. با تعریف دقیق تاب آوری، متوجه شدیم که این مفهوم برای افراد مختلف ممکن است معانی متفاوتی داشته باشد. برای همین نیاز است که درک مشترکی از تاب آوری داشته باشیم تا بتوانیم به سوی یک هدف مشترک حرکت کنیم.بخش اول:‌ https://vrgl.ir/pugAkبرای توصیف این سفر از استعاره کوهنوردی استفاده می کنیم. به کمک این استعاره می توانیم درک بهتری از مسیری که پیش رو داریم داشته باشیم و بدانیم که این سفر ساده و هموار نیست. کوهنوردی نیازمند تلاش فیزیکی و ذهنی می باشد. به همین ترتیب دستیابی به تاب آوری نیز نیازمند تلاش و کوشش است. همچنین در مسیر کوهنوردی با موانع مختلفی مانند صخره ها، شیب ها و شرایط آب و هوایی مواجه می شویم. در مسیر تاب آوری نیز با موانع سازمانی، فنی و فرهنگی مواجه خواهیم شد.باید توجه داشته باشیم که این سفر ساده نخواهد بود و نیاز به تعهد دارد، زیرا با چالش های پیش بینی نشده مواجه خواهیم شد که از قبل به آن ها فکر نکرده ایم. همانطور که قبلا اشاره کردیم تغییر یکی از موانع اصلی در مسیر ما است. تغییرات در زمینه های:فناوری: نیاز به به روزرسانی سیستم ها و ابزارها.فرآیندها: بازنگری در روش های کاری و عملیاتی.فرهنگ سازمانی: تغییر نگرش ها و رفتارهای کارکنان.ارتباطات: بهبود شیوه های ارتباطی بین تیم ها و بخش ها.اما چرا تغییر دشوار است؟مقاومت در برابر تغییر: انسان ها به طور طبیعی در برابر تغییر مقاومت می کنند.عدم اطمینان: تغییر می تواند حس عدم اطمینان و نگرانی ایجاد کند.نیاز به منابع: اجرای تغییرات نیاز به منابعی مانند زمان، پول و انرژی دارد.نقطه شروع ما برای این سفر دره کامل بودن ویژگی ها می باشد! بسیاری از سازمان ها در این دره قرار دارند. برخی از این ویژگی ها:تمرکز بر تحویل فیچرها: همانطور که می دانیم سازمان ها بر تحویل سریع تر و بیشتر فیچرهای کسب و کار تمرکز دارند.جدا بودن تیم های توسعه و عملیات: تیم Dev و Ops به صورت جداگانه عمل می کنند.اهداف متفاوت: تیم Dev بر اساس تعداد فیچرهای تحویل داده شده ارزیابی می شود، درحالی که تیم Ops بر اساس پایداری و در دسترس بودن سیستم ها.خب این جدا بودن پیامدهایی مانند عدم همکاری و هماهنگی، انتقال مسئولیت‌ (گردن نگرفتن!) و کاهش کیفیت دارد. برای مثال تمرکز بر سرعت تحویل میتونه باعث کاهش کیفیت بشه(البته این تا حدودی قابل قبول هستش). همچنین در این شرایط در دسترس بودن و پایداری سیستم ها به عنوان مشکل تیم Ops دیده می شود و تیم Dev احساس نمی کنه که مسئولیتی در این مورد داره.بیایید وضعیت فعلی را با یک چارچوب ساختاریافته ارزیابی کنیم. برای درک بهتر نقاط قوت و ضعف این وضعیت از یک چارچوب ارزیابی استفاده می کنیم:1- هدف اصلی حداکثر کردن تحویل فیچرهای بیزینس با کمترین هزینه ممکن هستش.2- داشتن سوالات کلیدی مانند &quot;آیا نیازهای بیزینس به درستی پیاده سازی شده اند؟&quot; یا &quot;چگونه می توانیم فیچرها را سریع تر و با هزینه کمتر تحویل دهیم؟&quot;3- انجام اقدامات معمول مانند تست های طولانی قبل از لایو کردن برای شناسایی مشکلات احتمالی، اجرای قوانین سختگیرانه برای انتقال به عملیات به دلیل عدم اعتماد به خروجی های تیم Dev، اجرای سیستم ها به صورت پلاگین برای افزایش پایداری و...این چارچوب ارزیابی معایبی مانند تحویل سریع فیچرها و رضایت بیزینس در کوتاه مدت، معایبی مانند بار اضافی برای تیم Ops، عدم توجه به پایداری و تاب آوری و کاهش کیفیت در بلند مدت دارد.این رویکرد در محیط‌هایی با سیستم های ساده و منفرد و در شرایط غیر بحرانی ممکن است مناسب باشد. اما در سیستم‌های پیچیده و به هم پیوسته یا در محیط های حساس و بحرانی، باید از این روش اجتناب کنیم. با توجه به تغییرات در دنیای فناوری مانند افزایش پیچیدگی سیستم ها‌ و نیاز به پاسخگویی سریع به تغییرات مارکت، ادامه این رویکرد منطقی نمی باشد. اهمیت تاب آوری بیشتر شده، تهدیدات امنیتی افزایش پیدا کرده اند و خرابی سیستم ها می تواند باعث ایجاد مشکلات جدی شود. در اینجا تاب آوری به سازمان ها کمک می کند تا در برابر اتفاقات غیرمنتظره مقاومت کنند. برای همین نیاز به همکاری بین تیم های Dev و Ops بیش از پیش احساس می شود. رویکرد DevOps به عنوان راهی برای بهبود همکاری و افزایش تاب آوری مطرح شده. سازمان ها متوجه شده اند که باید از روش های فعلی فاصله بگیرند و تیم ها همکاری بیشتری با یکدیگر داشته باشند.منبع: Uwe Friedrichsen - ufried . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Tue, 26 Nov 2024 21:08:10 +0330</pubDate>
            </item>
                    <item>
                <title>راه طولانی و پرپیچ‌ و خم به سوی تاب‌ آوری - بخش اول</title>
                <link>https://virgool.io/@heysaeid92/%D8%B1%D8%A7%D9%87-%D8%B7%D9%88%D9%84%D8%A7%D9%86%DB%8C-%D9%88-%D9%BE%D8%B1%D9%BE%DB%8C%DA%86-%D9%88-%D8%AE%D9%85-%D8%A8%D9%87-%D8%B3%D9%88%DB%8C-%D8%AA%D8%A7%D8%A8-%D8%A2%D9%88%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%D8%A7%D9%88%D9%84-eeah5ruuhe14</link>
                <description>در این سری مطلب درمورد سه پرسش اساسی صحبت خواهیم کرد:تاب آوری چیست؟چگونه میتوان تاب آور شد؟آیا همیشه نیاز است که تمام مسیر را طی کنیم؟آیا تاب آوری به اندازه ای واضح نیست که نیاز به تعریف نداشته باشد؟ بر اساس مشاهدات بسیاری از افراد برداشت های متفاوتی از تاب آوری دارند. هرکس به شکلی خاص از آن صحبت می کند و این ابهام باعث می شود که گاهی اوقات افرادی که درباره تاب آوری صحبت می کنند به دنبال چیز دیگری باشند.در مسیر رسیدن به تاب آوری شرکت ها معمولا مراحل زیادی را انجام می دهند. اما بیشتر اوقات نیازی به ادامه دادن تمام مسیر نیست و می توان در یکی از مراحل میانی توقف کرد. در اینجا توقف به معنی رسیدن به تاب آوری کامل نمی باشد, اما ممکن است همین مقدار کافی باشد.تاب آوری چیست؟اکثر مدیران ادعا می کنند که سیستم هایشان تاب آور است, برنامه نویس ها از طراحی نرم افزارهای تاب آور صحبت می کنند و فروشندگان از تاب آوری محصولات خودشان تعریف می کنند. اما واقعا منظور از تاب آوری چیست؟ آیا همه ما از یک مفهوم یکسان صحبت می کنیم؟اول از همه، تاب آوری چه چیزی نیست؟ یکی از اشتباهات رایج این است که تصور میکنیم سیستمی که برای مدت طولانی بدون مشکل کار کرده تاب آور است. چون تصور میکنیم عملکرد بی نقص یک سیستم در طول زمان به معنی تاب آوری آن سیستم می باشد. اما این تصور اشتباه است!کارکرد طولانی مدت یک سیستم فقط نشان می دهد که طراحی اولیه آن سیستم در شرایط درست و پیش بینی شده صورت گرفته است. تاب آوری تنها زمانی مشخص می شود که سیستم با شرایط پیش بینی نشده رو به رو شود. برای مثال زنجیره های تأمین جهانی تا پیش از حادثه کشتی Ever Given که باعث مسدود شدن کانال سوئز شد, تاب آور به نظر میرسیدند. اما این اتفاق غیر منتظره باعث شد تا ماه ها طول بکشد تا این زنجیره ها به حالت عادی بازگردند. این مورد به خوبی نشان می دهد که زنجیره های تأمین جهانی تاب آور نبوده اند, بلکه فقط در شرایط عادی به خوبی عمل می کردند.اما تعریف تاب آوری چیست؟برای رسیدن به این تعریف, منابع مختلفی از حوزه های گوناگون مانند روان شناسی, اکولوژی, مهندسی سیستم ها و... بررسی شدند. تاب آوری را میتوان توانایی مقابله موفق با شرایط نامطلوب دانست:مدیریت شرایط پیش بینی شده (پایداری): توانایی حفظ عملکرد در برابر مشکلات شناخته شده.مقابله با شرایط پیش بینی نشده: توانایی واکنش به اتفاقات غیر منتظره.بهبود و یادگیری از اتفاقات غیر منتظره: توانایی استفاده از تجربیات گذشته برای تقویت سیستم و جلوگیری از تکرار مشکلات.اگر کمی به این تعریف فکر کنیم, متوجه میشویم که راه حل های نرم افزاری به تنهایی تاب آور نیستند. آن ها می توانند پایدار باشند, اما اساسا نوشتن کدی که بتواند با اتفاقات پیش بینی نشده مقابله کند عملا غیر ممکن است. در بعضی از موارد شاید کدی که نوشتیم به صورت اتفاقی یک اتفاق را مدیریت کند, اما این اتفاق بیشتر به شانس وابسته است. معمولا بیشتر سیستم ها در مواجهه با اتفاقات پیش بینی نشده دچار خطا می شوند.با تمام این موارد, یک سیستم حتی اگر به تنهایی تاب آور نباشد, داشتن پایداری ارزش بسیار بالایی دارد. یعنی اینکه سیستم بتواند مشکلات شناخته شده و مورد انتظار را مدیریت کند. باید توجه داشته باشیم که پایداری یکی از پیش نیازهای اساسی برای تاب آوری است. بدون آن آمادگی برای مدیریت اتفاقات بدون فایده خواهد بود. چرا که ما برای مدیریت اتفاقات پیش بینی نشده آماده هستیم. اما اگر هربخشی از سیستم به طور موقت غیر قابل دسترسی شود کل سیستم به طور اجتناب ناپذیری از کار می افتد.منبع: Uwe Friedrichsen - ufried . com</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 21 Nov 2024 20:45:11 +0330</pubDate>
            </item>
                    <item>
                <title>قراردادهای اجتماعی در میکروسرویس‌ ها</title>
                <link>https://virgool.io/@heysaeid92/%D9%82%D8%B1%D8%A7%D8%B1%D8%AF%D8%A7%D8%AF%D9%87%D8%A7%DB%8C-%D8%A7%D8%AC%D8%AA%D9%85%D8%A7%D8%B9%DB%8C-%D8%AF%D8%B1-%D9%85%DB%8C%DA%A9%D8%B1%D9%88%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D9%87%D8%A7-mrh9g5ohxeoe</link>
                <description>ایده تصویر از سایت kwikattorneys . com گرفته شده استدر طراحی میکروسرویس ها یکی از مهم ترین موارد تنظیم یک Social Contract بین تیم میکروسرویس و مصرف کنندگان آن می باشد. این Contract در واقع یک چارچوب برای هماهنگی و همکاری بین طرفین می باشد و کمک می کند تا از تغییرات مشکل ساز(غافلگیرکننده) و ناسازگاری جلوگیری شود.برای مثال فرض کنید یک میکروسرویس داریم که اینترفیس آن توسط چندین سرویس دیگر استفاده می شود. به دلیل نیازهای جدید مجبور به تغییر آن اینترفیس می‌شویم. این تغییر ممکن است سرویس های مصرف کنندگان را ایمپکت کند. برای همین نیاز می باشد تا قبل از هر تغییری با مصرف کنندگان درباره زمان بندی و جزئیات تغییرات هماهنگ شویم. به زبان ساده تر Social Contract یعنی توافق کنیم که چه نوع تغییراتی, چگونه و با شرایطی می توانند انجام شوند و مصرف کنندگان تا چه زمانی باید این تغییرات را انجام دهند.دو نوع Breaking Contracts داریم:ساختاری: این نوع  شامل تغییرات در ساختار و فرمت اینترفیس, تغییر نام یا حذف پارامترها, تغییر تایپ پارامترها و حذف یک endpoint یا تغییر مسیر آن می باشد. معنایی: این نوع شامل تغییرات در منطق خروجی یا مقدارهای بازگشتی, تغییر در رفتار یک عملیات و تغییر در پاسخ های مرتبط با کدهای خطا می باشد. این تغییرات معمولا به خاطر ساختار ثابت API به سختی قابل تشخیص می باشند.انتخاب یک روش مناسب بستگی به انتظارات مصرف کنندگان از تغییرات دارد. به صورت کلی نگهداری یک اینترفیس قدیمی می تواند هزینه های زیادی داشته باشد, ولی باید زمان کافی برای مصرف کنندگان جهت مهاجرت به نسخه جدید در نظر بگیریم. این زمان و تعادل باید بین تیم میکروسرویس با مصرف کنندگان بررسی شود. در کتاب Building Microservices پیشنهاد می شود که تیم میکروسرویس و مصرف کنندگان درباره ی چند نکته مهم به توفق برسند:- درخواست تغییر اینترفیس به چه شکل مطرح شود؟- همکاری بین تیم میکروسرویس و مصرف کنندگان برای رسیدن به توافق به چه شکل می باشد؟- چه کسی مسئول انجام تغییرات در مصرف کننده می باشد؟- مصرف کنندگان برای انجام تغییرات چه مدت زمان دارند؟همچنین برای اینکه بتوانیم مصرف کنندگان را به سمت سازگاری هدایت کنیم روش های زیر پیشنهاد می شود:Tracking Usageاگر به توافق رسیده ایم که مصرف کنندگان تا تاریخ مشخصی به اینترفیس جدید مهاجرت کنند باید مطمئن شویم که این تغییرات را انجام دهند. برای مثال میتوانیم از لاگ و client id برای بررسی این مورد استفاده کنیم.Extreme Measuresاگر به هر دلیلی مصرف کنندگان همچنان از اینترفیس قدیمی استفاده می کنند, میتوانیم بعد از یک مدت مشخص آن اینترفیس را حدف کنیم. معمولا در سازمان ها یک مدت مشخص را برای مهاجرت به اینترفیس جدید در نظر گرفته می شود و بعد از آن بدون هیچ بررسی اضافی اینترفیس قدیمی را حذف می کنند. همچنین بعضی اوقات با کند کردن مصنوعی پاسخ میتوانیم مصرف کنندگان را مجبور به مهاجرت به نسخه جدید کنیم.در پایان باید توجه داشته باشیم که موفقیت یک Social Contract کاملا به ارتباط و هماهنگی بین تیم ها بستگی دارد. اگر تمام تیم ها در جریان این توافقات بوده و همکاری داشته باشند این فرآیند باعث ایجاد تجربه ی مثبت می شود. </description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Tue, 12 Nov 2024 18:30:00 +0330</pubDate>
            </item>
                    <item>
                <title>انواع Coupling در میکروسرویس ها</title>
                <link>https://virgool.io/@heysaeid92/%D8%A7%D9%86%D9%88%D8%A7%D8%B9-coupling-%D8%AF%D8%B1-%D9%85%DB%8C%DA%A9%D8%B1%D9%88%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D9%87%D8%A7-g9vvugbgc3re</link>
                <description>در معماری میکروسرویس ها یکی از مهم ترین چالش ها حفظ تعادل بین Coupling و Cohesion سرویس ها می باشد. کوپلینگ بین سرویس ها انواع مختلفی دارد که هرکدام از آنها اثرات متفاوتی بر طراحی دارند. در اینجا برخی از مهم ترین انواع آن مانند Domain Coupling, Temporal Coupling, Pass-Through Coupling و Common Coupling را باهم بررسی میکنیم.Domain Couplingدر این نوع کوپلینگ سرویس هایی که داریم برای انجام یک عملیات خاص به یکدیگر وابسته هستند. برای مثال اگر OrderService برای انجام رزرو به InventoryService و پرداخت به PaymentService نیاز داشته باشد, یک Domain Coupling بین این سرویس ها داریم. خب منطقا نمیتوانیم این کوپلینگ را به صورت کلی حذف کنیم, ولی میتوانیم تا حدودی آن را کاهش دهیم تا این وابستگی بیش از حد نباشد. اگر دیدیم که یک سرویس با تعداد زیادی سرویس دیگه ارتباط داره, احتمالا این سرویس کار زیادی بر عهده داره که بهتر هستش اون رو بازطراحی کنیم.Temporal Couplingاین کوپلینگ زمانی به وجود می آید که یک سرویس برای انجام کار خود به همزمانی عملیات یک سرویس دیگر نیاز دارد. برای مثال اگر OrderService هنگام ارسال درخواست به InventoryService منتظر پاسخ باشه و بدون اون نتونه پروسه رو ادامه بده, وابستگی زمانی ایجاد شده. برای کاهش این کوپلینگ میتوانیم از روش هایی مانند Message Broker ها استفاده کنیم تا سرویس ها بدون نیاز به همزمانی باهم تبادل داشته باشند.Pass-Through Couplingاین نوع کوپلینگ نیز زمانی رخ می دهد که سرویس یک داده ای را فقط به خاطر نیاز یک سرویس پایین دستی دیگه ارسال میکنبدون اینکه خودش به اون داده نیاز داشته باشه. برای مثال OrderService یک داده ای رو به PaymentService ارسال میکنه و این سرویس هم بدون پردازش داده اون رو به DeliveryService ارسال میکنه. این باعث میشه که سرویس اول به نحوه کارکرد سرویس پایین دستی آگاهی داشته باشه که موجب وابستگی پیاده سازی میشه. برای کاهش این نوع کوپلینگ میتوانیم از روش هایی مانند &quot;ارتباط مستقیم با سرویس پایین دستی&quot;, &quot;پنهان سازی جزئیات&quot; و یا &quot;نگهداری بدون پردازش&quot; استفاده کنیم.Common Couplingاین نوع کوپلینگ زمانی رخ می دهد که چندین سرویس از یک مجموعه داده های مشترک مثل دیتابیس های مشترک استفاده می کنند. این باعث میشه که تغییر در داده های مشترک سرویس های دیگه رو ایمپکت کنه و مدیریت داده ها رو هم پیچیده تر کنه. برای کاهش این کوپلینگ نیز میتوانیم از دیتابیس های جدا, استفاده از API ها و دیگر روش ها استفاده کنیم.در پایان, باید توجه داشته باشیم که در طراحی میکروسرویس ها تعادل مناسبی بین استقلال سرویس ها و ارتباطات آن ها برقرار کنیم. باید همیشه از خود سوال کنیم که آیا این وابستگی ضروری است یا راهی برای ساده تر و انعطاف پذیرتر کردن آن وجود دارد؟</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Thu, 07 Nov 2024 19:29:12 +0330</pubDate>
            </item>
                    <item>
                <title>از لاک پشت های روی هم تا تسلسل بی پایان در دنیای نرم افزار</title>
                <link>https://virgool.io/@heysaeid92/%D8%A7%D8%B2-%D9%84%D8%A7%DA%A9-%D9%BE%D8%B4%D8%AA-%D9%87%D8%A7%DB%8C-%D8%B1%D9%88%DB%8C-%D9%87%D9%85-%D8%AA%D8%A7-%D8%AA%D8%B3%D9%84%D8%B3%D9%84-%D8%A8%DB%8C-%D9%BE%D8%A7%DB%8C%D8%A7%D9%86-%D8%AF%D8%B1-%D8%AF%D9%86%DB%8C%D8%A7%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1-och6ynt4wpik</link>
                <description>تصویر از از answers-in-reason .com می باشد
از شخصی پرسیدن که دنیا رو چی استاده, گفت: «روی یه لاک پشت» دوباره ازش پرسیدن: «خب اون لاک پشت روی چی ایستاده؟» جواب داد: «روی یه لاک پشت دیگه!»—Rev. Joseph Frederick Berg (1854)این داستان کوتاه به یک استدلال فلسفی/منطقی به نام تسلسل بی پایان (Infinite Regress) اشاره دارد. تسلسل بی پایان زمانی رخ می دهد که برای توضیح یک مسئله به پاسخ دیگری نیاز می باشد و این فرایند به شکل بی پایان ادامه دارد بدون آنکه به یک نقطه پایان و نتیجه نهایی برسیم! این داستان نه تنها در فلسفه بلکه در دنیای طراحی نرم افزار نیز وجود دارد و با این موقعیت ها روبرو می شویم. تسلسل بی پایان در طراحی و پیاده سازی نرم افزار به وابستگی های زنجیره ای و بی پایان اشاره دارد که بسیاری از ما با آنها روبرو هستیم.در دنیای نرم افزار تسلسل بی پایان می تواند به شکل هایی مانند Circular Dependencies و نبود مرزبندی های مشخص بین ماژول ها و سرویس ها رخ دهد. برای مثال اگر ماژول های مختلف یک سیستم بدون مرزهای مشخص به هم وابسته باشند احتمال ایجاد وابستگی ها و مشکلات ناشی از آن زیاد می باشد که می تواند باعث ایجاد مشکلاتی مانند پیچیدگی در نگهداری, توسعه و تست سیستم شود. به دلیل اینکه هر تغییر در یک بخش به دلیل وجود وابستگی ها می تواند به صورت زنجیره ای بخش های دیگر را ایمپکت کند و باعث بروز خطاهای ناخواسته شود.برای جلوگیری از این وضعیت و حفظ یکپارچگی سیستم باید اصول طراحی سیستم را رعایت کنیم. برای مثال در طراحی میکروسرویس ها با استفاده از اصولی مانند Loose Coupling و High Cohesion میتوانیم تا حدود زیادی از این وابستگی ها جلوگیری کنیم. به زبان ساده تر هر سرویس باید تنها بر وظایف خود تمرکز کند و اطلاعات داخلی خودش را از سرویس های دیگر مخفی/پنهان نگه دارد تا به جای وابستگی های دوطرفه یک ساختار مستقل تر و پایدارتر ایجاد شود. پیشنهاد میکنم برای اطلاعات بیشتر در رابطه با مرزبندی میکروسرویس ها فصل دوم کتاب Building Microservices رو مطالعه کنید. بیایید یک مثال عملی را بررسی کنیم. فرض کنید که می خواهیم یک سیستم احراز هویت را طراحی کنیم, این سیستم به شکل کلی و ساده شامل ماژول های زیر می باشد:کاربر: برای مدیریت کاربران.احراز هویت: برای تایید هویت کاربران.ایمیل: برای ارسال ایمیل های تایید و اطلاع رسانی.اگر در اینجا ماژول ایمیل برای دسترسی به اطلاعات کاربر به ماژول احراز هویت و ماژول احراز هویت برای ارسال کد تایید به ماژول ایمیل وابسته باشد, یک circular dependency ایجاد کرده ایم که مشکلاتی مانند تست و نگهداری را برای ما ایجاد میکند. حال برای اینکه درگیر این مشکل نشویم می توانیم از اینترفیس های مشترک و جدا کردن وظیفه آنها استفاده کنیم. یعنی ماژول ایمیل فقط به اینترفیس مربوط به User دسترسی داشته باشد که توسط ماژول کاربر پیاده سازی شده است تا به این شکل وابستگی یک طرفه باشد.</description>
                <category>Saeid Noormohammadi</category>
                <author>Saeid Noormohammadi</author>
                <pubDate>Mon, 04 Nov 2024 19:13:54 +0330</pubDate>
            </item>
            </channel>
</rss>