مخزن شما هرگز تمام ماجرا نبود

کد نشان می‌دهد چه چیزی وجود دارد. دلیل‌ها در میان مشخصات، رخدادها، داده‌ها و تصمیم‌ها زندگی می‌کنند.

مخزن شما هرگز تمام ماجرا نبود

شش ماه پس از انتشار یک قابلیت، اگر مخزن را باز کنید، می‌توانید بخش زیادی از ماجرا را بازسازی کنید. می‌توانید معماری را دنبال کنید، شِما را بررسی کنید، تست‌ها را بخوانید و دقیقاً ببینید کدام خط‌ها تغییر کرده‌اند.

اما چیزی که معمولاً نمی‌توانید بازسازی کنید، گفت‌وگویی است که آن خط‌ها را ضروری کرده است.

کد به شما نمی‌گوید که یک قانون اعتبارسنجی وجود دارد چون یکی از مشتریان خروجی‌های معیوب می‌فرستد. توضیح نمی‌دهد که یک سیاست بازتلاش عجیب از تراکنش‌های تکراری در یک سیستم پایین‌دستی جلوگیری می‌کند. نشان نمی‌دهد که رابط کاربری تمیزتر پس از یک آزمون دسترس‌پذیری رد شده است، یا این‌که یک مرز سرویس بازتاب یک محدودیت قراردادی است نه ترجیح مهندسی.

Git در حفظ تاریخچهٔ کد عالی است. نیت را فقط زمانی حفظ می‌کند که تیمی عمداً آن نیت را ثبت کند و آن را به پیاده‌سازی متصل نگه دارد.

این شکاف همیشه بخشی از مهندسی نرم‌افزار بوده است. ابزارهای کدنویسی AI آن را آشکارتر می‌کنند. یک سیستم می‌تواند هر فایل در یک مخزن را بخواند، هر نماد را دنبال کند و وصله‌ای از نظر فنی قانع‌کننده تولید کند، اما باز هم مسئلهٔ اشتباهی را حل کند.

مسئله این نیست که کد گمراه‌کننده است. کد دارد به پرسشی محدودتر پاسخ می‌دهد.

پنج لایهٔ حقیقت مهندسی

بیشتر تغییرات معنادار در نرم‌افزار به پنج لایهٔ متفاوت از شواهد متکی هستند.

  1. نیت — کاربر، مشتری یا کسب‌وکار چه نتیجه‌ای را درخواست می‌کند؟ این ممکن است در یک مشخصات، تیکت، گفت‌وگوی پشتیبانی یا یادداشت جلسه باشد.
  2. محدودیت‌ها — چه چیزی نباید خراب شود؟ تعهدات سازگاری، مرزهای امنیتی، مقررات، قراردادها، بودجه‌ها و ضرب‌الاجل‌ها اغلب بیرون از مخزن قرار دارند.
  3. پیاده‌سازی — سیستم امروز چگونه کار می‌کند؟ کد، تست‌ها، شِماها، وابستگی‌ها و پیکربندی استقرار این لایه را فراهم می‌کنند.
  4. شواهد زمان اجرا — در سیستم واقعی چه اتفاقی می‌افتد؟ لاگ‌ها، تریس‌ها، متریک‌ها، داده‌های تولید و گزارش‌های رخداد می‌توانند فرض‌هایی را که در کد معقول به نظر می‌رسند، نقض کنند.
  5. تاریخچهٔ تصمیم‌ها — چرا رویکرد فعلی انتخاب شد؟ pull requestها، بحث‌های طراحی، گزینه‌های ردشده و رخدادهای قبلی پاسخ را در خود دارند.

مخزن در لایهٔ سوم بیشترین قوت را دارد. بخش‌هایی از لایه‌های دیگر را هم در خود دارد، اما به‌ندرت آن‌قدر هست که بتواند آن‌ها را به‌طور کامل نمایندگی کند.

این مهم است، چون شکست‌های نرم‌افزاری اغلب در مرز میان لایه‌ها ظاهر می‌شوند. پیاده‌سازی با یک مشخصات قدیمی منطبق است. اصلاحیه تیکت را برآورده می‌کند اما یک محدودیت عملیاتی را نقض می‌کند. تست‌ها پاس می‌شوند چون فرض‌های دیروز را کدگذاری کرده‌اند. کد از درون سازگار است، در حالی که داده‌های تولید از الگویی پیروی می‌کنند که هیچ‌کس مستند نکرده است.

یک وصلهٔ محلیِ درست، هنوز هم می‌تواند تغییر اشتباهی باشد.

آنچه مخزن به‌تنهایی نمی‌تواند پاسخ دهد

کاربری را در نظر بگیرید که سندی را ویرایش می‌کند و سپس جملهٔ به‌روزشده را جست‌وجو می‌کند، اما در نتایج فقط نسخهٔ قدیمی را می‌بیند. «جست‌وجو را فوراً به‌روزرسانی کنید» در ظاهر درخواست روشنی به نظر می‌رسد. مخزن چند نقطهٔ ممکن برای شروع را نشان می‌دهد، اما به‌تنهایی نمی‌تواند راه‌حل درست را تعیین کند.

پرسش منبع محتمل
کدام نسخه از سند مرجع نهایی است؟ سند مبدأ و تاریخچهٔ بازبینی
متن قدیمی کجا باقی مانده است؟ لاگ‌های همگام‌سازی، خروجی استخراج، ایندکس جست‌وجو، یا cache
«فوراً» برای این محصول چه معنایی دارد؟ وعدهٔ محصول یا هدف خدمت
آیا مجوزهای سند همراه با محتوای آن تغییر کرده‌اند؟ مجوزهای مبدأ و تاریخچهٔ ممیزی
آیا نتیجهٔ کهنه به یک کاربر، مبدأ، یا منطقه محدود است؟ ردگیری‌های درخواست و سنجه‌های production

کد جست‌وجو ممکن است توضیح دهد که نتایج چگونه برگردانده می‌شوند. اما نمی‌تواند به شما بگوید که آیا ایراد واقعی تأخیر در همگام‌سازی است، استخراج کهنه است، بی‌اعتبارسازی cache است، انتشار مجوزها است، یا انتظاری است که محصول هرگز آن را تعریف نکرده است.

این تمایز در سیستم‌های بالغ حتی مهم‌تر هم می‌شود. فیلدی که منسوخ به نظر می‌رسد ممکن است هنوز از یک client قدیمی پشتیبانی کند. سرویسی که شبیه نمونه‌ای تکراری به نظر می‌رسد ممکن است داده‌ها را با الزامات مجوز متفاوت از هم جدا کند. بررسی‌ای که ظاهراً بیش از حد به نظر می‌رسد ممکن است تنها ردِ سطح کد از یک incident در production باشد که تیم فعلی هرگز آن را ندیده است.

حذف پیچیدگی ارزشمند است. حذف تاریخی که در لباس پیچیدگی پنهان شده، پرهزینه است.

حتی context بیشتر هم می‌تواند به پاسخ اشتباه منجر شود

راه‌حل بدیهی این است که مواد بیشتری به AI بدهیم: کل مخزن، همهٔ ticketها، همهٔ اسناد، همهٔ پیام‌ها، و همهٔ لاگ‌ها.

این کار دسترسی ایجاد می‌کند، نه فهم.

منابع می‌توانند کهنه، متناقض، حدسی، یا برای مخاطبان متفاوت نوشته شده باشند. یک brainstorm نباید از یک specification تأییدشده معتبرتر تلقی شود. یک requirement مربوط به شش ماه پیش نباید بی‌سروصدا تصمیم محصولِ دیروز را override کند. یک لاگ production باید به release، environment، و code pathای که آن را تولید کرده متصل باشد. یک درخواست مشتری نباید بدون بررسی دامنه، به‌عنوان یک requirement همگانی در نظر گرفته شود.

بنابراین یک سیستم context جدی به چیزی بیش از retrieval نیاز دارد. باید راهی برای استدلال دربارهٔ این موارد داشته باشد:

  • اعتبار: کدام منبع مجاز است requirement را تعریف کند؟
  • تازگی: کدام اطلاعات جاری است، و چه چیزی جایگزین شده است؟
  • خاستگاه: هر ادعا، محدودیت، یا نتیجه‌گیری از کجا آمده است؟
  • روابط: کدام issue، release، customer، dataset، و code path به هم تعلق دارند؟
  • مجوزها: کدام منابع را می‌توان برای این task استفاده کرد و به این شخص نشان داد؟

Context توده‌ای از tokenها نیست. یک graph است با زمان، اعتبار، و مرزها.

context بیشتر باید شواهد بیشتری تولید کند، نه اعتمادبه‌نفس بیشترِ بدون شواهد.

واحد واقعی کار، تغییر است

ویرایشگرها و ابزارهای کدنویسی حول فایل‌ها سازمان یافته‌اند، چون فایل‌ها همان چیزی هستند که تغییر می‌دهیم. تیم‌های مهندسی حول تغییرها سازمان یافته‌اند.

یک تغییر با یک دلیل آغاز می‌شود. به یک requirement تبدیل می‌شود، به کد و داده دست می‌زند، از review عبور می‌کند، به production می‌رسد، و شواهد تازه ایجاد می‌کند. اگر این مراحل از هم جدا بمانند، هر کار آینده با یک دور دیگر از باستان‌شناسی شروع می‌شود.

یک سیستم AI که روی نرم‌افزار واقعی کار می‌کند باید همین چرخهٔ عمر را دنبال کند.

پیش از پیاده‌سازی، باید درخواست، محدودیت‌های مرتبط، و هر منبع متعارض را شناسایی کند. باید بداند که آیا در حال رفع یک defect است، رفتار مورد انتظار را تغییر می‌دهد، یا یک contract جدید معرفی می‌کند.

در طول پیاده‌سازی، باید هر انتخاب معنادار را به شواهد متصل کند. چرا این module؟ چرا این راهبرد migration؟ چرا این branch حفظ شود؟ توضیح باید فراتر از chatای که کد را تولید کرده دوام بیاورد.

پس از پیاده‌سازی، باید نتایج اعتبارسنجی، تصمیم‌های بازبینی، و محدودیت‌های تازه‌کشف‌شده را به تغییر پیوست کند. در غیر این صورت، نفر بعدی—یا نشست بعدی AI—ناچار خواهد بود دوباره آن‌ها را کشف کند.

این همان تفاوت میان ابزاری است که می‌تواند یک مخزن را ویرایش کند و سیستمی که می‌تواند در کار مهندسی مشارکت داشته باشد.

AI باید بازسازی را کاهش دهد، نه قضاوت را حذف کند

گاهی «زمینه‌ی بهتر» به‌عنوان مسیری به‌سوی توسعه‌ی خودمختار نرم‌افزار مطرح می‌شود. اما ارزش فوری آن چیزی کم‌هیاهوتر و مفیدتر است: کاهش هزینه‌ی بازسازی واقعیت پیش از اعمال تغییر.

AI می‌تواند نیازمندی اولیه را کنار کد مرتبط بیاورد. می‌تواند رخدادی را آشکار کند که دلیل وجود یک سازوکار حفاظتی غیرمعمول را توضیح می‌دهد. می‌تواند یک شاخص ناموفق را به نسخه‌ای متصل کند که آن را تغییر داده است. می‌تواند پیش از آغاز پیاده‌سازی نشان دهد که دو منبع معتبر با هم اختلاف دارند.

این قابلیت‌ها قضاوت مهندسی را حذف نمی‌کنند. آن‌ها فقط باعث می‌شوند این قضاوت آگاهانه‌تر باشد.

هنوز هم یک انسان باید تصمیم بگیرد کدام مصالحه قابل‌قبول است، آیا یک نیازمندی کامل است، و یک انتشار تا چه اندازه می‌تواند ریسک را بپذیرد. سیستم باید شواهد را قابل‌مشاهده و استدلال را قابل‌بررسی کند. نباید عدم‌قطعیت را پشت یک patch صیقل‌خورده پنهان کند.

معیار این نیست که «آیا می‌تواند کد تولید کند؟»

معیار این است که «آیا می‌تواند توضیح دهد چرا این، در این لحظه، تغییر درست است؟»

از آگاهی نسبت به مخزن تا آگاهی نسبت به کار

دستیارهای کدنویسی نخست زمانی مفید شدند که فایل پیش روی توسعه‌دهنده را می‌فهمیدند. آگاهی نسبت به مخزن گام بزرگ بعدی بود: پیدا کردن کدهای مرتبط، دنبال کردن نمادها، و اعمال تغییرات در سراسر یک پروژه.

گام بعدی، آگاهی از کاری است که پیرامون مخزن جریان دارد.

یعنی وصل کردن کد به مشخصاتی که آن را درخواست کرده، گفت‌وگویی که آن را روشن کرده، شواهد عملیاتی که آن را به چالش کشیده، و تصمیمی که باید بعداً به خاطر سپرده شود. همچنین یعنی کنار گذاشتن زمینه‌ای که نامرتبط، منقضی، یا خارج از مجوزهای کاربر است.

هنگام ساخت Dvina، این یکی از ایده‌هایی است که مدام به آن برمی‌گردیم. کار درون یک فایل، یک برنامه، یا یک گفت‌وگو رخ نمی‌دهد. معنا در پیوندهای میان آن‌ها و در این‌که این پیوندها در گذر زمان چگونه تغییر می‌کنند، شکل می‌گیرد.

مخزن همچنان ضروری است. این منبع حقیقت اجرایی برای رفتار سیستم است. فقط منبع کامل حقیقت برای نیت محصول، واقعیت عملیاتی، یا حافظه‌ی سازمانی نیست.

کل داستان، آنچه ساخته می‌شود را تغییر می‌دهد

وقتی فقط کد را دارید، پرسش طبیعی این است:

چه تغییری با این سیستم سازگار است؟

با زمینه‌ی گسترده‌تر، پرسش این می‌شود:

چه تغییری با این سیستم، این نیازمندی، این تاریخچه، و این لحظه سازگار است؟

آن سؤال دوم، محدودیت‌ها را پیش از آن‌که به پسرفت تبدیل شوند آشکار می‌کند. منطق پشت پیاده‌سازی را در اختیار بازبین‌ها می‌گذارد. به اعضای جدید تیم کمک می‌کند بفهمند چرا سیستم به این شکل است. و برای AI نقشی مبتنی بر واقعیت تعریف می‌کند: نه یک مرجع غیبی درون ویرایشگر، بلکه مشارکت‌کننده‌ای که می‌تواند شواهد را در سراسر کار کنار هم بگذارد.

مخزن کد شما هیچ‌وقت تمام ماجرا نبوده است.

فرصت واقعی این است که سیستم‌هایی بسازیم که بتوانند بقیه‌ی آن را هم بخوانند—و نشان دهند کارشان را چگونه انجام داده‌اند.

به Dvina بپیوندید

رایگان ثبت‌نام کنید و همهٔ ابزارهای خود را در یک فضای کاری ساده کنار هم بیاورید.

مطالب بیشتر

فقط داده‌های تحلیلی ضروری برای عملکرد روان خدماتمان را جمع‌آوری می‌کنیم.