<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"><channel><title>نوشته های عمران باتمان‌غلیچ</title><link>https://virgool.ir/feed/@emran.bm</link><description>توسعه‌دهنده - عاشق از صفر تا صدِ چرخه تولید نرم‌افزار - کمی هم اهل شعر و زندگی</description><language>fa</language><pubDate>2026-11-11 15:31:52</pubDate><image><url>https://files.virgool.ir/upload/users/81854/avatar/TAnu8F.jpeg</url><title>عمران باتمان‌غلیچ</title><link>https://virgool.ir/@emran.bm</link></image><item><title>راه‌اندازی سرور CI: کوزه‌گری که از کوزه‌شکسته آب می‌خورد!</title><link>https://virgool.ir/SahabPardaz/راه-اندازی-سرور-ci-کوزه-گری-که-از-کوزه-شکسته-آب-می-خورد-yvbx2yvkyl5e</link><description>در این نوشته قصد داریم از زاویه نگاه کیفیت به سراغ گوشه‌ای از گودِ توسعه‌ی محصول برویم که با اینکه داعیه‌دار ارتقای کیفیت محصولات نرم‌افزاری‌ست، اما عمدتا خودش کیفیت بالایی ندارد: سرور CI.‏Self-Hosted CI Server چیست؟گاهی به علت نیاز به منابع پردازشی بیشتر، شخصی‌سازی، صرفه‌جویی در هزینه‌ها، رعایت محرمانگی و ... نمی‌توان از زیرساخت‌های عمومیِ CI استفاده کرد. اکثر پلتفرم‌های این حوزه (نظیر Gitlab CI و Github Actions) در پاسخ به این نیازمندی‌ها امکان استفاده از Self-Hosted CI Server را فراهم کرده‌اند تا بتوان از امکانات همان پلتفرم در سرور شخصی بهره برد.برای اطلاعات بیشتر در این باره می‌توانید به توضیحات گیت‌هاب و گیت‌لب مراجعه کنید.مشکل چیست؟وقتی مجبور می‌شویم برای پروژه‌ی خود یک یا چند Self-Hosted CI Server راه‌اندازی کنیم، غالبا دست به یک کار هنری می‌زنیم؛ مجموعه‌ای از آزمون‌و‌خطاها و اعمال تنظیمات و نصب ابزارهای مختلف، برای رسیدن به یک سرور مناسب در اسرع وقت.تا اینجای کار کاملا طبیعی است. اولین قدم‌ها همواره قدم‌هایی نوآورانه و بدون چارچوب هستند. مشکل از آنجایی شروع می‌شود که وقتی به مرحله‌ای رسیدیم که سرور CI کارمان را راه انداخت، رهایش می‌کنیم.مشکل به اینجا هم ختم نمی‌شود؛ بسته به نیاز پروژه در زمان‌های مختلف، تغییراتی روی سرور CI اعمال می‌کنیم و پس از مدتی به معنای واقعی کلمه با یک کار هنری مواجهیم: چیزی که سازنده‌اش هم نمی‌تواند بازتولیدش کند!از اینجا به بعد، آپدیت زیرساخت CI، تغییر تنظیمات سرور CI، آپدیت ابزارهای نصب‌شده در آن، دیباگ مشکلات در سرور و ... نیازمند انرژی زیادی برای انجام خواهند بود. به طوری که پیشنهاد یک تغییر ساده در سرور CI احتمالا با این واکنش‌ها مواجه خواهد شد: «این را بگذاریم برای آخر هفته»، «فعلا فرصت این کار را نداریم»، «بچه‌ها امروز کامیت نکنید تا CI درست شود»، «این تغییر را باید فلانی انجام دهد» و ...اگر به هر دلیلی سرور CIتان دچار مشکل شود یا از دست برود، احتمالا تا یک هفته نمی‌توان به شرایط پایدار سابق بازگشت. زیرا شرایط سابق تعریف مشخصی برای بازتولید ندارد و کوچکترین اختلاف در تنظیمات هرجای سیستم ممکن است نتیجه‌ی جاب‌ها را دگرگون کند. در قسمت بعد نمونه‌ی این تنظیمات آمده است.این‌ها دقیقا همان مشکلاتی هستند که برای جلوگیری از آن‌ها در محصول نهایی خود، دست به دامن CI شده بودیم. انگار فراموش کرده‌ایم که اصلا در راستای چه آرمان‌هایی سراغ مفهوم Continuous Integration رفته بودیم!تحت داکر بودن کافی نیست!ممکن است در ابتدا راه‌حل را در این ببینیم که جاب‌های CI را در محیط داکر - یا سایر تکنولوژی‌های مشابه - اجرا کنیم تا کمترین وابستگی را به محیط میزبان CI داشته و مشکلات فوق را پشت سر بگذاریم.اگرچه containerization برای محیط CI بسیار توصیه شده و لازم است، اما کافی نیست. حتی در شرایطی که همه‌ی جاب‌های CI تحت داکر اجرا می‌شوند، هنگام تغییر، ارتقا یا بازسازی سرور CI، ممکن است با رفتارهای ناسازگاری در آن مواجه شوید و روزها برای پاس کردن پایپلاینی که تا دیروز مشکلی نداشت تلاش کنید!فهرست زیر شامل برخی موارد است که در سرور میزبان CI ممکن است بر اجرای جاب‌ها تاثیرگذار باشد:- نسخه‌ی داکر- نسخه‌ی کرنل سیستم‌عامل- احراز هویت در رجیستری‌های private (برای دانلود ایمیج خود جاب)- تنظیمات مربوط به registry mirror- تنظیمات مربوط به insecure registries- دسترسی شبکه به سرویس‌های جانبی- تنظیمات مربوط به امکان / عدم امکان اجرای موازی جاب‌ها- و...راه‌حلراه‌های مختلفی برای مقابله با مشکل یادشده وجود دارد. مثلا می‌توان از سرور CI (همان کار هنری!) snapshot گرفت و در مواقع لزوم از آن استفاده کرد.اما راه‌حل پیشنهادی ما این است که مراحل راه‌اندازی و تنظیم سرور CI در قالب اسکریپت، خودکار شود.این کار نه‌تنها باعث می‌شود وضعیت سرور CI قابل بازتولید باشد، بلکه امکان مرور جزئیات آن را در اختیار همه‌ی اعضای تیم قرار می‌دهد. بعلاوه تجربه نشان داده که طی این خودکارسازی، بسیاری از ابزارها و تنظیمات اضافی یا اشتباه، خود را نشان داده و حذف خواهند شد.خودکارسازی راه‌اندازی سرور CIما داخل تیم خود در سحاب اسکریپت‌هایی نوشتیم که با معرفی یک سرور تازه‌نفس، آن را تبدیل به یک سرور CI می‌کند. طی این کار، تجربه‌هایی کسب کردیم که در ادامه به اختصار با شما در میان می‌گذاریم. امیدواریم برای شما هم مفید باشند. فایل‌های مربوط به ساخت و تنظیم سرور CI در یک فولدر در مخزن خود پروژه نگهداری شود.تنها پیش‌فرضی که از ماشین مقصد باید وجود داشته باشد، نسخه‌ی سیستم عامل و تنظیمات شبکه (برای دسترس‌پذیری ماشین میزبان) است.مطابق طراحی اکثر سرویس‌های CI، سرور مربوطه به صورت stateless نگهداری شود. یعنی ذخیره‌ی هرگونه داده توسط جاب‌های CI، خارج از سرور انجام شود تا فرایند update / rollback سرویس بی‌نیاز از data migration باشد.البته وجود cache در سرور CI بلامانع است. به شرط آن که به معنای واقعی کلمه cache باشد نه data. یعنی از بین رفتن آن خللی در functionality سیستم CI ایجاد نکند.در هنگام طراحی جاب‌های CI کمترین میزان وابستگی به سرور CI موجود باشد و حتی الامکان از روش‌های virtualization (نظیر Docker) بهره گرفته شود.با توجه به اینکه برای اجرای خود اسکریپت، طبیعتا سرور CI/CD وجود ندارد، نیاز است تا نکات زیر رعایت شود:- اسکریپت با این پیش‌فرض نوشته شود که قرار است در کامپیوتر شخصی اجرا گردد.- حتی‌الامکان اسکریپت مربوطه به حداقل پیش‌نیازها برای اجرا وابسته باشد.- اجرای اسکریپت به سادگی اجرای یک فایل bash یا شبیه آن باشد، بدون هیچگونه flag و تنظیمات اضافه. (هر آپشنی با توضیحات مرتبط به صورت interactive از کاربر گرفته شود.) این کار در راستای عمل به شیوه‌ی Document as Code است. به بیان دیگر، مستندات مربوط به راه‌اندازی سرور CI باید تنها یک جمله باشد: «فلان اسکریپت را اجرا کنید!»پیش‌فرض‌هایی که اسکریپت مطابق آن‌ها نوشته شده، assert شوند و در صورت مغایرت، خطای متناظر به صورت گویا چاپ شود.- پیش‌فرض‌های سرور:.    نوع سیستم عامل.    نسخه‌ی سیستم عامل.    دسترسی تحت شبکه به سرویس‌های دیگر.    (در صورت نیاز) حداقل منابع پردازشی مورد نیاز- پیش‌فرض‌های کلاینت (همان اسکریپت interactive):.    پیشنیازهای اجرای اسکریپت (مانند نسخه‌ی انسیبل، ابزار sshpass و ...)هر تغییر در تنظیمات سرور CI باید توسط تغییر و اجرای اسکریپت مربوطه اعمال شود. (حتی الامکان خودتان ssh نزنید!)از عمومی و کلی کردن ساختار اسکریپت خودداری شود. اسکریپت تنها وظیفه دارد سرور CI مربوط به پروژه‌ی کنونی خودش را تنظیم کند.اگرچه عمومی بودن اسکریپت در ظاهر جذاب به نظر می‌رسد، اما باعث می‌شود پارامترهای وروردی بسیار زیاد و گیج‌کننده شوند. مضاف بر اینکه برخی تنظیمات واقعا خاص سرور CI پروژه است و عمومی کردن آن اساسا بی‌معنی است؛ مانند گواهی SSL مربوط به سرویس‌های داخلی، که اصلا برای یک پروژه‌ی دلخواه دیگر ممکن است به کل نیاز نباشد.به طور کلی، هدف اسکریپت خودکار، راه‌اندازی سرور CI در شرایط کنونی شرکت / پروژه است و طبیعتا با تغییر این شرایط، اسکریپت نیز می‌تواند تغییر کند.پارامترهای غیرمحرمانه (مانند گواهی SSL شرکت) حتی الامکان hard-code شوند. این کار باعث می‌شود اجرای اسکریپت برای اجراکننده (که ممکن است هرکسی باشد) ساده‌تر شود.موارد آخر احتمالا با پیش‌فرض‌های بسیاری از ما هماهنگ نیست. مثلا همه‌ی ما عمدتا تلاش کرده‌ایم تا یک قابلیت را در صورت امکان به صورت عمومی‌تر فراهم کنیم (مورد ۸) یا اصرار داشته‌ایم که پارامتر‌های هاردکدشده را به بیرون کد منتقل کنیم (مورد ۹). اینجا هم، مثل هزاران موضوع دیگر در مهندسی نرم‌افزار، با یک trade-off روبرو هستیم که برآورد هزینه/فایده‌ی آن را به خودتان واگذار می‌کنیم.ایام به کام و پایپلاین‌هایتان پاس!</description><category>عمران باتمان‌غلیچ</category><author>عمران باتمان‌غلیچ</author><pubDate>Wed, 25 Aug 2021 19:49:52 +0430</pubDate></item><item><title>چرا تست نمی‌نویسیم؟</title><link>https://virgool.ir/SahabPardaz/why-dont-we-test-mw1knems3l01</link><description>از موارد استثنا که بگذریم، معمولا برنامه‌نویس‌های تازه‌نفس اشتیاق زیادی به نوشتن تست برای کدهایشان ندارند. خیلی از بحث‌ها در تیم‌های توسعه نیز ناظر به همین موضوع است: چرا باید تست بنویسیم؟ چقدر تست بنویسیم کافی است؟ چرا اینجا لازم نیست تست بنویسیم؟ و ...مطالب مختلفی در مورد راه‌های اصولی نوشتن تست وجود دارد؛ لذا در این مقاله به جای پرداختن به آن‌ها، تلاش شده تا به دلایلی که باعث می‌شود کمتر سراغ تست برویم، اشاره شود و درک بهتری از شرایط حاصل گردد. همچنین در ادامه، راه‌هایی برای بهبود این شرایط پیشنهاد خواهد شد.«تست کردن» یا «تست نوشتن»؟ مسئله این استاگر اولین لحظه‌ای که توانستید دستوری را - در قالب متن - به کامپیوتر بفهمانید به خاطر بیاورید، احتمالا حس فوق‌العاده‌ی پس از آن را هم به خاطر خواهید آورد؛ شما نه به آن دلیل که توانسته‌اید متنی را تایپ کنید، بلکه به خاطر اینکه توانسته‌اید آن را تست کنید، هیجان‌زده شدید. نکته دقیقا اینجاست! تازه‌کارترین برنامه‌نویس‌ها هم هرگز فراموش نمی‌کنند «برنامه‌ای که به تازگی نوشته‌اند» را تست کنند، بلکه صرفا دلیلی نمی‌بینند آن را در قالب کد مکتوب کنند؛ زیرا:مطمئن هستند کد کنونی درست کار می‌کند. مخصوصا مواقعی که قسمت کاملا جدیدی را توسعه داده‌اند؛ چراکه در فرایند توسعه، بارها و بارها عملکرد مورد نظرشان را به صورت دستی تست کرده‌اند.مطمئن هستند آنچه قرار است به عنوان تست بنویسند، پاس می‌شود؛ لذا انگیزه‌ای برای صرف وقت و نوشتن «کدی که نتیجه‌اش مشخص است» ندارند.ترجیح میدهند وقتی را که صرف نوشتن تست می‌کنند، به توسعه‌ی قابلیتی جدید و یا رفع یک مشکل دیگر اختصاص دهند.ممکن است نوشتن تست فرایند پیچیده، زمانبر و یا مبهمی برای آن‌ها باشد.ممکن است با خود بگویند اصلاً چه کسی می‌خواهد این تست را اجرا کند؟ممکن است تست را وظیفه‌ی فرد یا تیم دیگری بدانند.درباره هر یک از مسائل یاد شده می‌توان دلایل متقابل آورد (چنانچه آورده‌اند) و توضیح داد که چرا نوشتن تست با وجود این دلایل، غالبا سودمند است. اما به نظر می‌رسد مسئله بیشتر به تجربه مرتبط باشد تا دانش؛ توسعه‌دهنده‌ای که بر نوشتن تست اصرار می‌ورزد، احتمالا بیش از آنچه مزایای کوتاه‌مدت و بلندمدت این کار را «مطالعه» کرده باشد، «تجربه» کرده است. این همان دلیلی است که باعث می‌شود توسعه‌دهندگانِ باتجربه‌تر با اطمینان و لذت بیشتری تست بنویسند، تا برنامه‌نویسان تازه‌نفس.در ادامه به مواردی خواهیم پرداخت که به کمک آنها بتوان نوشتن تست را برای همه بامعناتر کرد.جذابیت‌هایی که در ابتدا دیده نمی‌شوندراستش را بخواهید، گاهی حق با برنامه‌نویس‌های تازه‌نفس است! اما مشکل اینجاست که آنها احتمالا دلایل اصلیِ بیهوده بودن تست را بیان نمی‌کنند. وقتی تست‌ها به صورت خودکار اجرا نمی‌شوند، عملا تبدیل به کدهای یکبارمصرف می‌شوند. یا وقتی فرایند بعد از تست (نظیر انتشار، استقرار، تست‌های non-functional و ...) همچنان به صورت دستی است و هیچ رویّه‌ی مشخصی ندارد، چه انگیزه‌ای برای مشخص کردن فرایند تست به تنهایی وجود دارد؟در مقابل، وقتی همه یا بخشی از چرخه‌ی تولید نرم‌افزار خودکار است (به این معنا که فرایند آن مشخص و قابل اجرا توسط کامپیوتر است)، وجود تست‌هایی که آن‌ها هم به صورت خودکار بتوانند به اطمینان از درستی مراحل بعدی کمک کنند، جذاب‌تر خواهد بود.از موارد بالا که بگذریم، نوشتن تست جذابیت‌هایی دارد که مشاهده‌ی آن‌ها نیازمند گذر زمان است. برخی از این موارد به شرح زیر است:۱. وقتی بر روی یک قابلیت یا رفع ایراد تمرکز کرده‌اید، ممکن است از تأثیر آن بر زوایای دیگر محصول غافل باشید. اینجاست که تست‌هایی که قبلا برای آن زوایا نوشته‌اید، به دادتان میرسند.تست‌ها، زمانی که شکست می‌خورند ارزش واقعی خود را نشان می‌دهند؛ نه زمانی که پاس می‌شوند!۲. شرایطی را در نظر بگیرید که بتوان تنها با فشار یک دکمه، نسخه جدیدی از برنامه را منتشر کرد. در این شرایط وجود تست‌های ریز و درشت، مخصوصا زمانی که با کاربران متعدد یا سخت‌گیر مواجهید، این قوّت قلب را به شما می‌دهد که احتمالا آن دکمه قرار نیست روزگارتان را سیاه کند!تست‌ها به همان اندازه که مانع خوشحالی تیم از ارائه سریع‌تر محصول می‌شوند، مانع ناراحتی آن‌ها از شکست محصول به دلیل سهل‌انگاری یا غفلت خواهند شد.۳. «این مشکل را قبلاً دیده بودم»، «دوباره همان حالت پیش آمده»، «این را مگر حل نکرده بودیم؟!» و جمله‌های مشابه غالبا به این علت بیان می‌شوند که هنگام حل یک ایراد، برای آن تست نمی‌نویسیم و لذا بعداً به دلایل مختلف دوباره با آن مواجه می‌شویم.نوشتن تست برای ایرادات، در واقع نوعی مستند کردن آن‌هاست؛ مستندی دقیق، پویا و قابل اجرا.۴. علاوه بر موارد فوق، نوشتن تست خود باعث دقیق شدن مسئله و توجه به زوایای مختلفی می‌شود که لزوما هنگام پیاده‌سازی راه‌حل به ذهن توسعه‌دهنده نمی‌رسند. بارها رخ داده است که برخی تست‌هایی که بعد از توسعه‌ی یک قابلیت جدید نوشته می‌شوند - در کمال ناباوریِ توسعه‌دهنده - شکست می‌خورند!جذابیت‌هایی که باید ایجاد شوندمسئله‌ای که ممکن است ما را در مقابل نوشتن تست تنبل کند، عدم جذابیت این کار است. اگر از زاویه‌ی فلسفه‌ی لذت‌گرایی به موضوع نگاه کنیم، نوشتن تست، علاوه بر فواید بلندمدت، باید لذت‌های کوتاه‌مدت نیز به همراه داشته باشد؛ این نکته در نگاه اول ممکن است بی‌اهمیت جلوه کند؛ اما تجربه خلاف آن را نشان می‌دهد.در ادامه به برخی نکات کوچک که به این جذابیت کمک می‌کنند اشاره می‌شود. این نکات در عین جذابیت کوتاه‌مدت، برکات بزرگ‌تری نیز به همراه خواهند داشت که توضیح آن در این مجال نمی‌گنجد.ساده کردن فرایند تستگاهی علت تنبلی در نوشتن تست، پیچیدگی و حجم کار غیرطبیعی در پیاده‌سازی آن است.چارچوب‌های رایج تست معمولا بسیاری از پیچیدگی‌های عمومی آن را به عهده می‌گیرند (مواردی نظیر ایزوله بودن تست‌ها از هم، پاک کردن داده‌ها بعد از تست، نمایش نتایج، علت شکست‌ها و ...). اگر مواردی هستند که همچنان نویسنده‌ی تست را با حجم زیادی از کد تکراری یا پیچیده روبرو می‌کنند، این مسئله را به طور جداگانه حل کنید. یا از کسانی که به طور پیش‌فرض با نوشتن تست خوشحال هستند بخواهید بیشتر تست بنویسند!If it hurts, do it more frequently!Jez Humbleبرای مطالعه‌ی بیشتر در این باره به اینجا مراجعه کنید.محاسبه و نمایش میزان پوشش تست (Test Coverage)تقریبا تمامی ابزارهای اجرای تست، میزان پوشش تست را نیز می‌توانند محاسبه کنند و یا دست‌کم گزارش‌هایی تولید می‌کنند که ابزارهای دیگری نظیر SonarQube یا CodeCov برای محاسبه با آن‌ها آشنا هستند.اما مسئله مهم در اینجا محاسبه نیست، بلکه نمایش مقدار محاسبه شده است. سعی کنید میزان پوشش کد را در محل‌هایی که بیشتر در چشم هستند، نمایش دهید. یک نشان (badge) در مخزن پروژه، یک قسمت کوچک از مانیتور عمومی در تیم و ... می‌تواند جای مناسبی برای نمایش پوشش کد باشد.چراغ تست!اگر اهل زیاده‌روی هستید، وجود یک چراغ فیزیکی که نشانگر pass یا fail بودن تست‌ها در شاخه‌ی اصلی مخزن کد است، می‌تواند جذاب باشد. به این صورت که هنگام موفق بودن تست‌ها چراغ سبز، و به محض شکست آن‌ها قرمز شود.وقتی چراغ قرمز است توقف کنید؛ همه‌ی کارهایتان را رها کنید و به رفع مشکلی که پیش آمده بپردازید. طبق توصیه‌ای که در کتاب Continuous Delivery بیان شده، اولویت اول تیم، پاس نگهداشتن پایپلاین است.وقتی چراغ سبز است با خیالی آسوده به کارهای دیگر خود ادامه دهید.نمایش پوشش تست به صورت عینییک قابلیت فوق‌العاده که اخیرا در گیت‌لب اضافه شده است، امکان مشخص کردن خطوط پوشش‌داده‌شده در MergeRequestهاست؛ به این صورت که در کنار خطوط کد، این که هر خط در تست‌ها پوشش داده شده یا خیر با رنگ سبز و زرد نمایش داده می‌شود. جزئیات بیشتر در این باره را می‌توانید در اینجا مشاهده کنید.درگیر کردن تست در برنامه‌ریزی‌های زمانیدر جلسه‌ی برنامه‌ریزی اسپرینت (sprint planning) نشسته‌اید و مشغول تخمین زمان مورد نیاز برای انجام یک کار هستید. هرکس دلایل خود را برای زمانی که تخمین زده است، مطرح می‌کند. مدیر تیم به این اشاره می‌کند که از نظر او آن کار به علاوه‌ی زمان مورد نیاز برای تستش به فلان مقدار زمان نیاز دارد.شاید ساده به نظر برسد؛ اما همین جمله‌ی ساده، باعث می‌شود فشار زمانی که توسعه‌دهنده حین انجام یک کار حس می‌کند کمتر شده و با احتمال و اشتیاق بیشتری به نوشتن تست بپردازد.تعیین اهداف برای میزان پوشش تست‌هاما در سحاب یک پلکان بلوغِ توسعه‌ی محصول داریم که مراحل مختلف برای رسیدن به سطوح بالاتر کیفیت، در آن مشخص شده است. چندین آیتم از این پلکان، مربوط به انواع تست و ویژگی‌هایی مربوط به آنها (نظیر پوشش کد، پوشش نیازمندی و...) است.همچنین برای اینکه وضعیت هر محصول در این پلکان مشخص و شفاف باشد، «نمو» را توسعه داده‌ایم. نمو ابزاری است که به تیم‌ها کمک می‌کند تا سطح کنونی محصول خود را مشاهده و برای ارتقای آن برنامه‌ریزی کنند.این موضوع باعث شده مفهوم تست در شرکت ارزشمندی خود را بیش از پیش نشان دهد.مخلص کلام!خلاصه‌ی کلام اینکه سعی کنید تست‌ها دیده شوند! بهانه‌های درگیر شدن با نتیجه‌ی تست‌ها را زیاد کنید. آن‌ها هرچه بیشتر در کانون توجه قرار بگیرند، اشتیاق تیم برای تولیدشان بیشتر خواهد بود و در نهایت، وقتی تیم‌ها با فواید بلندمدت تست مواجه شوند، دیگر صورت مسئله‌ی «چرا تست نمی‌نویسیم؟» پاک شده است!</description><category>عمران باتمان‌غلیچ</category><author>عمران باتمان‌غلیچ</author><pubDate>Sat, 06 Mar 2021 12:17:50 +0330</pubDate></item></channel></rss>