برای یک تیم توسعه در ایران، بازنشدن سرویس خارجی همیشه یک علت ندارد. ممکن است محدودیت حساب، سیاست ارائهدهنده، مشکل پرداخت، اختلال شبکه یا خطای خود سرویس باشد. اگر همه این وضعیتها را «تحریم» بنامیم، معمولاً راهحل اشتباه انتخاب میکنیم: تنظیم شبکه را تغییر میدهیم در حالی که حساب مجاز نیست، یا زیرساخت را مهاجرت میدهیم در حالی که مشکل موقت است.
هدف عملی تیم باید کمکردن وابستگی شکننده و روشنکردن مسیر کار باشد. توسعهدهنده باید بداند چه چیزی برای Build لازم است، مالک حساب چه کسی است، چه دادهای در سرویس نگهداری میشود و اگر دسترسی قطع شد چه کاری میتوان انجام داد. این آمادگی با پنهانکردن هویت یا استفاده از حساب فرد دیگر تفاوت دارد؛ تصمیم معماری باید با شرایط واقعی قرارداد و دسترسی سازگار باشد.
محدودیت قانونی، سیاست محصول و وضعیت شبکه را تفکیک کنید
ممکن است ارائه یک دسته خدمت طبق مقررات مجاز باشد، اما شرکت آن را در یک کشور عرضه نکند یا پرداخت در دسترس نباشد. عکس این حالت نیز ممکن است: یک صفحه باز شود، ولی استفاده موردنظر شما با شرایط خدمت سازگار نباشد. قبل از خرید یا اتصال محصول به آن سرویس، صفحه سیاست منطقهای، شرایط استفاده و پاسخ پشتیبانی را بخوانید. تجربه یک همکار برای تعیین وضعیت حقوقی قرارداد شما کافی نیست.
توضیح رسمی OFAC درباره بند 560.540 برخی خدمات و نرمافزارهای مرتبط با ارتباطات اینترنتی را با شرایط مشخص پوشش میدهد. این متن مجوز عمومی برای هر نوع Cloud، هر مشتری یا هر کاربردی نیست. نام قدیمی General License D-2 نیز نباید بدون بررسی متن فعلی مبنای تصمیم شود. در قرارداد تجاری حساس، نوع خدمت، طرف قرارداد و کاربرد را برای بررسی متخصص حقوقی مشخص کنید؛ یک پاسخ کلی اینترنتی جای این بررسی را نمیگیرد.
GitHub و Copilot وضعیت یکسانی ندارند
سیاست Trade Controls گیتهاب برای خدمات ابری GitHub در ایران مجوزی را توضیح میدهد، با استثناهای مربوط به اشخاص و کاربردهای محدودشده. همان صفحه برای GitHub Copilot محدودیت صادرات جداگانه دارد. بنابراین مجازبودن استفاده از Repository به معنی مجازبودن همه محصولات شرکت نیست. پرداخت نیز به شرایط پردازشگر پرداخت وابسته است. مقالهای که این تفاوتها را حذف کند، برای برنامهریزی خرید ابزار قابل اتکا نیست.
اگر حساب به اشتباه محدود شده، مسیر رسمی Appeal و پشتیبانی را دنبال کنید و اطلاعات درست ارائه دهید. قبل از سپردن کد پروژه به یک حساب شخصی، مالکیت سازمان، نقش اعضا و دسترسی بازیابی را روشن کنید. قطع دسترسی یک نفر نباید همه تیم را از کد محروم کند. برای تنظیم فرایند همکاری، راهنمای Git برای توسعهدهندگان کمک میکند؛ سیاست سازمان و نگهداری داده بخش جداگانه این تصمیم است.
وابستگیهای واقعی پروژه را فهرست کنید
در بسیاری از پروژهها، Git تنها وابستگی خارجی نیست. دانلود Package، Image پایه Container، فونت، مستندات، API پرداخت، سرویس ایمیل و ابزار تحلیل خطا هم در مسیر توسعه یا اجرای محصول قرار دارند. یک جدول ساده با ستونهای «خدمت»، «استفاده در Build یا Runtime»، «مالک حساب»، «وضعیت دسترسی»، «داده ذخیرهشده» و «روش جایگزینی» تهیه کنید. این جدول باید درباره پروژه خودتان باشد، نه فهرستی عمومی از برندها.
وابستگی Build و Runtime پیامد متفاوت دارند. اگر Registry در مرحله Build قطع شود، نسخه نصبشده محصول ممکن است همچنان کار کند. ولی قطع API احراز هویت خارجی میتواند ورود کاربران را متوقف کند. برای هر مورد مشخص کنید چند ساعت اختلال قابل تحمل است و چه کسی مسئول تصمیم است. سرویس کماهمیتی مانند تحلیل رفتار کاربر نباید بدون دلیل مسیر پرداخت یا نمایش محتوای اصلی را از کار بیندازد.
Lockfile کمک میکند؛ تضمین دسترسی نیست
برای پروژه npm، package.json و Lockfile باید با هم در Repository باشند. دستور npm ci نصب را بر اساس Lockfile انجام میدهد و در ناسازگاری این دو فایل خطا میدهد. این رفتار جلوی انتخاب اتفاقی نسخه تازه را میگیرد، اما Package گمشده یا Registry غیرقابل دسترسی را ایجاد نمیکند. نسخه Node و npm و گزینههای اثرگذار بر نصب را نیز در راهنمای پروژه ثبت کنید.
Cache را هم با مخزن پایدار یکی ندانید. مستند npm cache آن را ذخیرهساز دائمی و قابل اتکا برای همه دادهها معرفی نمیکند. اجرای Offline فقط وقتی موفق است که داده لازم واقعاً موجود باشد و Scriptهای نصب نیز دانلود جداگانه نخواهند. پاککردن Cache بهعنوان اولین واکنش به هر خطا، ممکن است تنها نسخه در دسترس Package را هم از بین ببرد. ابتدا علت خطا را از پیام و وضعیت محیط بفهمید.
مثال: یک ابزار محلی که به API بیرونی نیاز ندارد
نمونه زیر یک گزارش شمارش وضعیت کارهاست. در پوشه تازه، دو فایل package.json و report.mjs را با محتوای نمایشدادهشده بسازید. Node.js نسخه 22 یا جدیدتر و npm لازم است؛ هیچ Package خارجی ندارد و داده نمونه داخل فایل است. با npm run report اجرا میشود و نتیجه را در ترمینال مینویسد. هدف این مثال نشاندادن تفکیک ابزار محلی از سرویس ابری است، نه شبیهسازی نصب Offline یک پروژه با وابستگیهای متعدد.
فایل package.json
{
"name": "local-task-report",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": { "node": ">=22" },
"scripts": { "report": "node report.mjs" }
}
فایل report.mjs
const tasks = [
{ title: 'طراحی فرم', status: 'done' },
{ title: 'پیادهسازی فرم', status: 'doing' },
{ title: 'نوشتن راهنما', status: 'todo' },
{ title: 'بازبینی محتوا', status: 'done' }
];
const counts = { todo: 0, doing: 0, done: 0 };
for (const task of tasks) {
if (!Object.hasOwn(counts, task.status)) {
throw new Error(`Unknown status: ${task.status}`);
}
counts[task.status] += 1;
}
console.table(counts);
console.log(`Total: ${tasks.length}`);
این ابزار برای اجرا به نصب Dependency یا Token نیاز ندارد. اگر بعدها خواندن داده را به یک API وصل کنید، همان اتصال یک وابستگی Runtime تازه است و باید رفتار خطای آن طراحی شود. برای پروژههای دارای Package، نبود وابستگی این نمونه را به محصول خود تعمیم ندهید. نصب وابستگی، دانلود ابزار Build و اجرای Scriptهای نصب مسیرهای جدا هستند؛ وجود یک Lockfile بهتنهایی هیچکدام را آفلاین نمیکند.
Mirror و Registry داخلی مسئول مشخص میخواهند
Mirror معتبر یا Registry داخلی میتواند توزیع وابستگی مجاز را در تیم منظم کند. اما باید بدانید Package از کجا آمده، چه زمانی همگام شده و چه کسی آن را بهروزرسانی میکند. تغییر Registry بدون بررسی Origin و Integrity، مسئله دسترسی را به مسئله زنجیره تأمین تبدیل میکند. نصب Package همنام از منبع ناشناخته یا غیرفعالکردن بررسی TLS برای رفع خطا، تصمیم مناسبی برای پروژه مشتری نیست.
در Python نیز راهنمای نصب تکرارپذیر pip درباره تثبیت نسخهها و ساخت مجموعه محلی Wheel توضیح میدهد. Wheel باید با سیستمعامل، معماری و نسخه Python سازگار باشد؛ فایل جمعآوریشده برای یک محیط الزاماً در محیط دیگر کار نمیکند. حالت بررسی Hash در pip نیز باید برای وابستگیهای مربوط کامل تنظیم شود. Hash، مجوز استفاده یا سلامت رفتار برنامه را تضمین نمیکند؛ فقط کنترل دیگری بر فایل دریافتشده است.
کد، Artifact و داده مشتری سه چیز جدا هستند
داشتن نسخه Git برای بازیابی کامل محصول کافی نیست. Repository معمولاً دیتابیس مشتری، فایلهای بارگذاریشده، Secretها و Artifact انتشار را ندارد. هرکدام باید مسیر نگهداری، مالک و سیاست دسترسی خودش را داشته باشد. برای انتقال تاریخچه Git بدون اتصال مستقیم، git bundle یک امکان مشخص است، اما LFS و فایلهای خارج از Git را خودکار پوشش نمیدهد. بسته انتقال را بر اساس محتوای واقعی پروژه تعریف کنید.
برای Container نیز docker image save امکان ذخیره Image را فراهم میکند، ولی دیتای Volume همراه آن ذخیره نمیشود. Tag متغیر، معماری پردازنده و Image مورد استفاده را در برنامه انتشار روشن کنید. راهنمای Docker برای توسعهدهنده Frontend تفاوت محیط توسعه و اجرای محصول را توضیح میدهد. هدف، امکان بازسازی یک نسخه معلوم است؛ انباشت فایلهای ناشناخته به تیم کمک نمیکند.
جایگزین را بر اساس قابلیت انتخاب کنید
اگر سرویس فعلی قابل استفاده نیست، گزینه جایگزین را با قابلیت ضروری مقایسه کنید: روش احراز هویت، Export داده، SLA، محدودیت حجم، ابزار پایش و امکان پرداخت واقعی. داخلیبودن یا Open source بودن بهتنهایی پاسخ همه این سؤالها نیست. Self-hosting نیز نیازمند نگهداری، بهروزرسانی و بازیابی است. برای مقایسه Backend میتوانید بررسی Supabase و Firebase را بخوانید؛ تصمیم برای هر پروژه باید جدا ثبت شود.
یک برنامه کوتاه برای اختلال بنویسید: کدام خدمات حیاتیاند، آخرین نسخه قابل انتشار کجاست، چه دادهای قابل خروج است و تیم از چه مسیر مجازی با ارائهدهنده ارتباط میگیرد. این سند را با تغییر قرارداد یا زیرساخت بهروز کنید. وابستگی کمتر زمانی مفید است که کار تیم را قابل پیشبینیتر کند؛ حذف یک سرویس و افزودن چند ابزار بیمالک ممکن است فقط شکل مشکل را عوض کند.
هنوز دیدگاهی ثبت نشده
اولین نفری باشید که نظر میدهد!