کاوه امیری سامانه موجودی یک انبار لوازم برقی در همدان را با کپی کردن یک پوشه روی SSH منتشر میکرد، و هشت ماه جواب داد. پنجشنبه بعدازظهر نسخهای را کپی کرد که فایل موجودی هفته قبل را نمیخواند، و فهمید نسخه قبلی دیگر هیچجا وجود ندارد. رویش نوشته بود. انبار تا شنبه با دست شمرد.
هیچچیز در این ماجرا درباره نوشتن کد نیست و همهاش همین موضوع است. انتشار مجموعه عادتهایی است که یک تغییر را برگشتپذیر، تکرارپذیر و قابل بازرسی برای کسی جز خودتان میکند. و یک بند اضافه دارد که در هیچ منبع انگلیسیزبانی نیست: بیشتر خوانندگان اینجا سروری ندارند که واردش شوند، یک کنترل پنل دارند.
اول برگشتپذیری
ویژگیای که آخر هفته کاوه را نجات میداد نه تست بود و نه کانتینر. این است که برگرداندن، انتشار نسخه قبلی است و باید به همان اندازه آسان باشد. اگر برگشتن رویهای غیر از جلو رفتن باشد، در بدترین لحظه ممکن و توسط ترسیدهترین آدم موجود بداهه ساخته میشود. انتشار درست، جابهجا شدن میان نسخههایی است که هر دو هنوز هستند، و نسخه قبلی دقیقاً برای همین نگه داشته میشود.
روی میزبانی اشتراکی هم همین کار شدنی است و کسی نمیگویدش: به جای نوشتن روی پوشه، پوشه تازه را کنارش بگذارید و ریشه سایت را به آن ببرید. برگرداندن بعد از آن یک تغییر مسیر است، نه یک شب. همین یک عادت بیشتر از هر ابزاری در این صفحه ارزش دارد، و در گذاشتنش جایی که عموم به آن برسند شکلهای مختلفش هست.
همین ایده یک لایه پایینتر، دلیل نگه داشتن تاریخچه است. دو دستور کار را برمیگردانند و جای هم نمینشینند: git revert یک کامیت تازه میسازد؛ git reset شاخه را جابهجا میکند. اولی روی هر چیزی که دست کس دیگری هم هست امن است، چون تغییری اضافه میکند که تغییر قبلی را خنثی میکند و سابقه هر دو میماند. دومی چیزی را که شاخه به آن اشاره میکند بازنویسی میکند، که روی کاری که کسی ندیده ابزار درستی است و روی کاری که دیده، راهی برای خراب کردن بعدازظهر یک همکار. همین تفکیک نیمه عملی تاریخچه یک پروژه، و کار کردن به موازات هم است.
ماشینی که هیچچیز ندارد، و ماشینی که جای دیگری ایستاده
انتشار کاوه کار میکرد چون لپتاپش هشت ماه تنظیم کوچک روی هم انباشته بود: کتابخانهای که یک بار نصب شده، متغیری که در پروفایل پوسته نشسته، پوشهای که اتفاقی وجود داشت. هیچکدام جایی نوشته نشده بود. خط لوله روی ماشینی اجرا میشود که هیچچیز ندارد، و همین صادقش میکند: سرور بیلد هر بار از یک جعبه خالی شروع میکند، پس هر چیزی که پروژه لازم دارد باید جایی اعلام شده باشد که یک فایل بتواند ثبتش کند.
و اینجا یک چیز هست که فقط خواننده اینجا با آن روبهرو میشود. ماشین خط لوله بیرون از ایران است، پس بیلد آنجا سبز میشود و روی لپتاپ شما نه. آن جعبه خالی به هر مخزنی میرسد و شما نمیرسید، پس اولین باری که این را میبینید شبیه خراب بودن دستگاه خودتان است و نیست. برعکسش هم درست است: اجراگری که خودتان داخل ایران بالا بیاورید دقیقاً به همان دیوارهایی میخورد که لپتاپتان میخورد، و آن روز است که خط لوله واقعاً چیزی درباره پروژه شما میگوید.
همان غریزه یک قدم جلوتر کانتینر را میسازد. ایمیج کانتینر، وابستگیها و اجراگر و کد را در یک فایل دارد، یک بار ساخته میشود و هرجا بیفتد یکسان اجرا میشود، که کل کاری است که فرستادن محیط، همراه خود کد میکند. چیزی که حذف نمیکند این است که باید بدانید چه چیزی داخل ایمیج رفته: ایمیجی که از یک پایه بدون نسخه ساخته شده همان وابستگی اعلامنشده قبلی است، در یک جعبه، با اعتماد به نفس بیشتر.
و نکتهای که خط اول هر فایل ساخت را برای شما عوض میکند: نام ایمیج بدون میزبان یعنی داکر هاب؛ نام کامل، مخزن را قفل میکند. این یک قرارداد نامگذاری است، نه یک تنظیم پنهان، و یک بار نوشتنش تفاوت میان بیلدی است که گاهی میگیرد و بیلدی که همیشه از جایی میآید که خودتان انتخاب کردهاید.
FROM python:3-slimFROM docker.io/library/python:3-slim
شاهد، و اینکه واقعاً برای چیست
استدلالی که آدمها را درباره تست قانع میکند این نیست که اشکال میگیرند، چون یک تازهکار به درستی میبیند که بیشترشان اشکالی را میگیرند که نویسنده از قبل به آن فکر کرده بود. استدلالی که میایستد این است که تست چیزی است که تغییر دادن را امن میکند. کاوه میتواند سهشنبه تحلیلگر فایل موجودی را از نو بنویسد، با اعتمادی به اندازه همان مقدار از رفتارش که به شکل چیزی نوشته شده که یک ماشین بررسیاش میکند.
اولین تست مفید، تست واحد نیست. تستی است که کل برنامه را روی فایل موجودی هفته قبل اجرا میکند و جمع کل را میسنجد، چون شکستی که کاوه واقعاً داشت همان بود و چون تستی که روی یک ورودی واقعی از گذشته نوشته شده به هیچ نظریهای درباره اینکه واحدها چه هستند نیاز ندارد. ساختار مفصل بعداً میآید، و برای بیشتر پروژههای کوچک هرگز لازم نمیشود؛ به همین دلیل هم شاهدی بر کار کردنش، که از تغییر بعدی شما جان سالم به در ببرد حول دوام گفته شده، نه حول درستی.
بعدازظهر پنجشنبه
هر لایه چه چیزی را میگیرد، و چه چیزی را مستقیم رد میکند
چهار لایه میان یک تغییر و انباری که با دست میشمرد، و هر لایه نسبت به خرابیای که لایه بعدی میگیرد شفاف است.
- مجموعه تست+رفتاری که کار میکرد و حالا نمیکند→هر چیزی که کسی به فکرش نرسیده توصیفش کند، و هر تفاوت محیط
- بیلد از هیچ+کتابخانه اعلامنشده و متغیری که در پروفایل پوسته نشسته→کدی که غلط است، جوری که بیعیب بیلد میشود
- کانتینر+اختلاف سرور و لپتاپ بر سر نسخه یک چیز→یک تغییر بد، وفادارانه و یکسان، همهجا
- نسخه قبلی که نگه داشته شده+هر چیزی که آن سه تا رد کردند، تا وقتی که کسی متوجه شود→هیچچیز، و همین لایهای است که برای خالی کردن دیسک پاک میشود
درزگیر همان متوجه شدن است و اینجا یک لایه نیست. هر چهار تا فرض گرفتهاند که کسی خبردار میشود، و کاوه خبردار شد چون انبار زنگ زد.
جایی که کار میایستد: کنترل پنلی که شبیه هیچکدام اینها نیست
ایست این موضوع در ایران این است که مقصد انتشار یک کنترل پنل میزبانی اشتراکی است. نه SSH هست، نه اجراگر کانتینر، نه چیزی که خط لوله بتواند به آن تحویل بدهد؛ فقط یک مدیر فایل. نتیجهای که گرفته میشود این است که این کل موضوع مال شرکتهای بزرگ است، و آدمها سالها فایل آپلود میکنند.
این نتیجه غلط است و گران، چون سه چیز از چهار چیز این صفحه روی همان کنترل پنل هم کار میکنند: تاریخچه روی دستگاه خودتان است، تست روی دستگاه خودتان اجرا میشود، و نگه داشتن پوشه قبلی یک کلیک است. تنها چیزی که واقعاً به سرور نیاز دارد کانتینر است، و آن هم آخرین قدم است نه اولی. ترتیبی که جواب میدهد کنترل نسخه است، بعد راهی برای اجرا کردن از هیچ، بعد تست، و بعد خودکار کردن انتشار؛ تقریباً همه چهارمی را اول میگیرند، چون ابزارهای جالب همانجاست، و خط لولهای میسازند که انتشاری را خودکار میکند که هیچکس نمیتواند برش گرداند.
سه چیزی که در ۲۰۲۶ باز میکنید
Git اختیاری نیست و از دهه ۲۰۱۰ که جای Subversion را گرفت اختیاری نبوده. رایگان است، و پرارزشترین ساعت این صفحه ساعتی است که صرف فهمیدن این میشود که کامیت یک عکس لحظهای است و شاخه یک اشارهگر به یکی از آن عکسها؛ بعد از آن بیشتر سردرگمی خودش حل میشود، از جمله تفاوت آن دو دستوری که بالا آمد.
GitHub Actions خط لوله پیشفرض پروژههایی است که از قبل روی GitHub هستند و برای مخزنهای عمومی رایگان است. جای Jenkins را برای بیشتر تیمهای کوچک گرفت، که آموزشهای قدیمیتر از حدود ۲۰۱۹ هنوز فرضش میکنند. دو چیز را همان اول تصمیم بگیرید: اینکه اجراگر کجا میایستد، و اینکه هر بیلد از کدام مخزن بسته میگیرد، وگرنه ماشینی که برای شما میسازد و منتشر میکند چیزی را سبز میکند که روی دستگاه شما هرگز اتفاق نمیافتد.
Docker هنوز راهی است که کانتینرها با آن ساخته میشوند و برای استفاده شخصی رایگان است. جای فهرست نوشتهشده مراحل نصب را گرفت که هیچکس بهروز نگهش نمیداشت. اگر مقصدتان کنترل پنل است، این ابزار امروز برای شما یک چیز دیگر است: راهی برای اینکه بیلد روی دستگاه خودتان هر بار یکسان باشد، حتی وقتی هیچ کانتینری جایی مستقر نمیشود.
آنچه هیچکدام از اینها پوشش نمیدهند این است که بعد از انتشار چه میشود، وقتی چیزی در حال اجراست و کسی باید متوجه شود که ایستاده است. کاوه متوجه شد چون انبار زنگ زد، و آن یک روش نظارت نیست. پرسش نزدیکتر این است که وقتی همان انتشار یک صفحه عمومی را عوض میکند بازدیدکننده چه میبیند، که هر چه میان یک مرورگر و یک سرور میگذرد جوابش را دارد، و اینکه فایل موجودی هفته قبل اصلاً کجا باید بماند، که ذخیره داده، جوری که بشود دوباره بیرونش کشید جوابش را دارد.