<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های بهنام محمدی</title>
        <link>https://virgool.io/feed/@behnamm92</link>
        <description>مهندس نرم افزار</description>
        <language>fa</language>
        <pubDate>2026-06-07 09:15:30</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/3456/avatar/ga7nTl.jpg?height=120&amp;width=120</url>
            <title>بهنام محمدی</title>
            <link>https://virgool.io/@behnamm92</link>
        </image>

                    <item>
                <title>Developer Experience معیاری که نادیده گرفته شد</title>
                <link>https://virgool.io/codenevis/developer-experience-%D9%85%D8%B9%DB%8C%D8%A7%D8%B1%DB%8C-%DA%A9%D9%87-%D9%86%D8%A7%D8%AF%DB%8C%D8%AF%D9%87-%DA%AF%D8%B1%D9%81%D8%AA%D9%87-%D8%B4%D8%AF-m6x0qqc3wgix</link>
                <description>قابل استفاده بودن و موفق شدن یک نرم افزار به عوامل متعددی بستگی دارد. اما یکی از مهم ترین این عوامل، تجربه کاربری (UX) و در یک نمای کلی تر، تجربه مشتری (CX) است. در واقع، تجربه ای که ما برای کاربر می سازیم کلید موفقیت نرم افزار است.سوالی که در اینجا مطرح می شود این است که چگونه می توانیم تجربه کاربری خوبی را برای کاربران خود رقم بزنیم؟مهم ترین عنصر در اینجا، بهبود دوره ای نرم افزار با استفاده از بازخورد کاربران است. ما باید نرم افزار را به گونه ای تغییر دهیم که نیازهای کاربران را به طور کامل برآورده کند. این امر مستلزم ایجاد تغییرات مداوم در نرم افزار است.مشکلات ناشی از تغییرات مداومبرای مثال، اگر نرم افزار را با استفاده از یک زبان برنامه نویسی سطح بالا مانند جاوا یا سی شارپ نوشته باشیم، اعمال تغییرات به معنای تغییر کلاس ها، توابع، ساختار فایل ها و ... خواهد بود. این تغییرات مداوم و همچنین کدهای نوشته شده توسط افراد مختلف با سبک ها  و دست خط های  متفاوت، پس از مدتی code-base را به وضعیتی غیرقابل توسعه تبدیل می کند.در این وضعیت، درک ساختار کد برای برنامه نویسان دشوار شده و آنها از تغییر کد موجود اجتناب می کنند. در عوض، آنها ترجیح می دهند توابع را به جای استفاده reuse یا extend، از نو بازنویسی (rewrite) کنند. زیرا بازنویسی معمولاً ساده تر از درک کد موجود و تغییر آن است.با گذشت زمان و افزایش عمر نرم افزار، تعداد این توابع موازی با سبک های مختلف کد نویسی افزایش می یابد. در اینجاست که به دلیل دشوار بودن درک و نگهداری کد، مفهوم &quot;Legacy Code&quot; متولد می شود.در واقع، Legacy Code کدی نیست که عملکرد درستی نداشته باشد، بلکه کدی است که هزینه اعمال تغییرات در آن بالا است. این هزینه بالا به طور مستقیم با میزان درک کد توسط توسعه دهندگان رابطه دارد.رابطه بین Developer Experience و Customer Experienceمتأسفانه، این رابطه اغلب نادیده گرفته می شود. به ندرت می بینیم که در انتخاب تکنولوژی ها و معماری ها، به داشتن یک IDE خوب و Learning Curve کوتاه توجهی شود. در عوض، تمرکز همیشه بر روی رفتن به سمت لبه تکنولوژی و دنبال کردن ترندها است. غافل از اینکه تجربه توسعه دهنده (DX) به طور مستقیم تجربه مشتری (CX) را تحت تاثیر قرار می دهد. و در فضای دیگر حتی تعادل بین کار و زندگی برنامه نویسان را به هم میزند زیرا با یک موجود پیچیده به نام Legacy Code طرف هستیم که رفتار آن برای ما قابل پیش بینی نیست و تخمین ها غلط از آب در می آیند.حال این سوال پیش می آید که چگونه می توانیم DX را بهبود ببخشیم؟پاسخ در یک کلمه خلاصه می شود: سادگیسادگی در همه سطوح، از کوچکترین ماژول ها تا معماری کلی نرم افزار برای Integrate کردن این ماژول ها.سادگی کد را قابل فهم تر، قابل نگهداری تر و قابل توسعه تر می کند. همچنین، سادگی باعث می شود که توسعه دهندگان به جای بازنویسی کد، از آن مجددا استفاده کنند یا آن را گسترش دهند چون کد ساده، به سادگی هم درک می شود. در نهایت، سادگی منجر به کاهش هزینه های توسعه، افزایش سرعت توسعه نرم افزار و ماندگاری code-base می شود.</description>
                <category>بهنام محمدی</category>
                <author>بهنام محمدی</author>
                <pubDate>Wed, 06 Mar 2024 01:29:21 +0330</pubDate>
            </item>
                    <item>
                <title>نوشتن یک watchdog ساده</title>
                <link>https://virgool.io/@behnamm92/implement-simple-watchdog-software-mipgbxg82vbt</link>
                <description>اول از همه در مورد مفهوم watchdog صحبت کنیم که اصلا چی هست؟این مفهوم که بیشتر در سخت افزار و برنامه های کامپیوتری mission critical استفاده میشه، کارش اینه که مدام وضعیت healthy یک موجودیت دیگه رو بررسی کنه، و به محض تشخیص معیوب بودن اون سخت افزار یا نرم افزار، مجموعه فرمان های recovery یا alert رو اجرا کنه.رایج ترین نوع recovery الگوریتم ostrich هست که همونطور از نامش پیداست مثل شترمرغ از روی مسئله پیش آمده میپره و بیخیال مشکل میشه و سیستم هدف رو restart میکنه :)برگردیم به مسئله خودمون و پیاده سازی این مفهومصورت مسئلهمی خواهیم یک برنامه single instance داشته باشیم که با selenium یک دستور رو برای crawl کردن تو یک سایتی اجرا کنه، و نکته ای که هست به دلیل وجود rate limit و bot detector توی اون وب سایت باید همه درخواست ها queue بشن و در هر لحظه فقط یک درخواست اجرا بشه و نکته دوم اینه که این سیستم روی ویندوز باید هاست بشه.بدیهیه که با ویندوزی شدن ماجرا کلی از ابزارهای اماده این کار رو از دست میدیم و البته که همیشه هم عجله داریم و باید در کمترین زمان ممکن این کار انجام بشه.الان با چالش های مختلفی رو به رو میشیم که باید همه اونها رو با کمترین ریسورس، که اینجا زمانه حل کنیم.اولین چالش معماری سیستم هست، که crawler و watchdog هر کدوم کجای سیستم باید قرار بگیرن و اصلا health monitoring به چه صورتی انجام بشه؟رایج ترین نوع health check (از این به بعد hc میگیم) به این صورته که یک port مجزا روی برنامه ای که قراره مانیتورینگ روش انجام بشه به بیرون expose میشه و برنامه monitoring که کاملا مستقل اجرا شده این port رو با روش pulling بررسی میکنه و اگر جوابی که انتظار داره رو نگیره (خود برنامه بگه وضعیت خوب نیست یا هیچ جوابی در مدت زمان مشخص نده) وضعیت DOWN به alert manager  اعلام میکنه (مرسومه که در زبان hc وضعیت رو به صورت UP و DOWN اعلام میکنن)خب این روش یه مشکل داره و اون اینه که باید در برنامه crawler کد hc  نوشته بشه و crawler باید بتونه تو این مورد ما، وضعیت سلامت خودشو نگه داره، حالا چون ممکنه برنامه restart هم بشه پس باید اون رو جایی persist کنه.خب تا همینجا کافیه که تشخیص بدیم این روش کلی پیچیدگی داره و کد زیادی باید براش بنویسیم.از اون طرف ما از third party مثل selenium استفاده کردیم که خودش وابسته به browser و فایل اجرایی selenium هست و عملا به دلایل مختلفی هر بخش اون ممکنه crash کنه، ولی watchdog یک برنامه بسیار سبکه که تقریبا مطمئنیم که up-time بالایی داره. بنابراین تصمیم بر این شد خود watchdog مسئول تشخیص سلامت crawler بشه بدون اینکه که crawler اصلا خبر دار بشه که watch dogِی وجود داره.برای این کار ما اومدیم watchdog رو تبدیل به یک reverse proxy کردیم و با عبور دادن همه درخواست ها از اون،  هم تمامی response time نگهداری کردیم و هم تمام منطق hc رو توی اون پیاده سازی کردیم و اجازه دادیم crawler فقط روی منطق خودش تمرکز کنه. https://gist.github.com/behnammohammadi/cbb7cf9a22f93afa12f70c4fd7e4ddde کدی که نوشتیم این منطق رو پیاده میکنه که اگر در 5 دقیقه گذشته تعداد درخواست هایی که به خطا یا timeout خورده بیشتر از درخواست های موفقیت آمیز بشه به شرطی که از اخرین restart کردن سیستم بیشتر از 5 دقیقه گذشته باشد. فرمان restart را به crawler ارسال کنه.نکته مهمی که اینجا وجود داره استفاده از Content.CopyToAsync هست که باعث میشه بدون materialize کردن جواب صرفا stream خونده شده مستقیم به خروجی فرستاده بشه و روی سرعت تاثیر چشم گیری داره.و در اینجا اجرای فرمان restart رو به خود سیستم عامل واگذار کردیم که از طریق دستورات CLI اون رو اجرا میکنه و ما کافیه فقط اون فایل .cmd رو که ساختیم توسط watchdog اجرا کنیم (تابع Restart). https://gist.github.com/behnammohammadi/f155a34b18ab4bb364aab87200cd2e44 حالا برای اینکه خود watchdog رو مطمئن بشیم همیشه در حال اجراست میتونیم استراتژی های مختلفی داشته باشیم ولی در اینجا چون با هر رکوست کلاینت، trigger میشه و اگر خطایی هم رخ بده فقط همون رکوست رو تحت تاثیر قرار میده بنابراین میتونیم این بخش رو بیخیال بشیم و تمرکز رو بذاریم روی up بودن خود اپلیکیشن watchdog.برای این منظور میتونیم برنامه رو به صورت windows service در ویندوز نصب کنیم و recovery mode برای اون مشخص کنیم که در صورت crash کردن برنامه رو restart کنه  یا اون رو در IIS هاست کنیم، ولی خب با این روش ما output console رو از دست میدیم و باید لاگ ها رو جایی persist کنیم تا بتونیم بعدا بخونیم.تو این مورد این خیلی مناسب کیس ما نیست پس تصمیم گرفتیم که هم output console رو داشته باشیم که بتونیم در لحظه عمل debug رو انجام بدیم و هم مکانیزم بازیابی خودکار در صورتی که crash کنه رو داشته باشیم. که البته این روش مشکلاتی رو هم داره مانند اینکه که حتما باید کاربر لاگین شده داشته باشیم و اون session براش باز بمونه ولی تو این کیس ما، این حالت مناسب بود.پس یک فایل اسکریپت ویندوز ساختیم با محتویات زیر که در صورتی که برنامه watchdog کرش کنه و خارج بشه چون توی یک loop هست دوباره به صورت خودکار اجرا میشه https://gist.github.com/behnammohammadi/203867deeac105021fac3b8a7ebe6149 چالش بعدی که داشتیم این بود که درخواست ها همزمان اجرا نشن و سریالی این اتفاق بیفته خب برای این کار هم روش های خیلی زیادی داشتیم که هزینه بر بود به همین منظور خیلی ساده اومدیم از ویژگی lock در برنامه crawler استفاده کردیم و اون بخشی که قراره درخواست رو در وب سایت اجرا کنه رو به صورت critical section نوشتیم و با این روش صف رو پیاده سازی کردیم. https://gist.github.com/behnammohammadi/7b99a63cadc9511c58721b0cb77475e8 همچنین برای پیاده سازی صف زماندار اومدیم از cancellation token استفاده کردیم که داخل critical section وضعیت منقضی شدنش چک میشه که در صورتی که منقضی شده باشه ادامه درخواست پردازش نمیشه.اینجا دیگه کار watchdog ما تموم شد و میتونیم اجراش کنیم و مطمئن باشیم که حواسش به همه چی هست :)</description>
                <category>بهنام محمدی</category>
                <author>بهنام محمدی</author>
                <pubDate>Tue, 02 May 2023 11:55:32 +0330</pubDate>
            </item>
            </channel>
</rss>