توسعهٔ قرارداد-محور: حقیقت رو یکبار بنویس
خلاصهٔ کاملتر
بن هاودل تو این مقاله سراغ یه الگوی قدیمی میره که خودش سه بار ساختتش: توسعهٔ قرارداد-محور. حرف اصلیش اینه که هر تعریفِ تکراری توی سیستم، دوتا «حقیقت»ه که دیر یا زود با هم اختلاف پیدا میکنن — و اختلافِ دو حقیقت یعنی باگ، فقط با تأخیر. راهحل: حقیقت رو یکبار و ماشینخوان بنویس و بقیه رو ازش تولید کن.
به گفتهٔ نویسنده اصل DRY هیچوقت دربارهٔ کد نبوده، دربارهٔ دانش بوده. یه مدل دامنه که همزمان توی اینترفیس TypeScript، پاسخ API، اسکیمای اعتبارسنجی و جدول دیتابیس تعریف شده، چهار تکه کد نیست؛ یه واقعیته که چهار بار فتوکپی شده. تو این نگاه، قرارداد مستنداتِ سیستم نیست، خودِ سیستمه و بقیه فقط خروجیهای پاییندستیان.
نسخهٔ اول رو موقع CTO بودن تو یه فینتک بانکی ساخته: کل دامنه توی ۱۶ فایل YAML و یه ژنراتور حدوداً ۴۷۰ خطی که ازشون نزدیک ۳۴۹ فایل مدل TypeScript در میآورد. دو تصمیمش رو هنوز دوست داره: ایونتها جفتی تعریف میشدن (یکی موفقیت، یکی ردشدن) تا مسیر خطا هم توی قرارداد باشه، و یه اکستنشن ساده به قرارداد میگفت داده قراره چهجوری کوئری بشه.
جالبترین بخش اون نسخه این بود که قوانین مجوزدهی هم توی همون spec تعریف میشد و میدلورِ اجراش تولید میشد؛ اگه اندپوینتی هیچ سیاستی اعلام نکرده بود، پیشفرضش «مجاز» نبود، «ممنوع» بود. نتیجهش این بود که بازبینی امنیتیِ «کی میتونه چی صدا بزنه» به خوندن یک فایل تبدیل میشد، نه پنجاه ریزالور.
نسخهٔ سوم توی محصول خودش Snug اجرا شده و قرارداد از YAML به TypeScript و Zod منتقل شده. حالا حدود ۶٬۲۰۰ خط قرارداد دستنویس، نزدیک ۱۵٬۴۰۰ خط خروجی تولید میکنه: تایپهای دیتابیس، اسکیمای اعتبارسنجی، یه SDK کاملاً تایپشده و مستندات. دامنه یکبار بهشکل Zod تعریف میشه که هم تایپ زمان کامپایل میده هم اعتبارسنجی زمان اجرا:
export const UserSchema = z.object({
id: z.string(),
email: z.string().email().nullable().optional(),
status: z.enum(["pending", "onboarding", "completed"]).default("pending"),
createdAt: ISODateString,
});تفاوت مهم نسخهٔ جدید اینه که محافظت در برابر drift دندون درآورده: منیفستِ هش، چکی که کد تولیدشدهٔ قدیمیتر از ۲۴ ساعت رو قبول نمیکنه، و جابی توی CI که ثابت میکنه یه مایگریشن تازه دقیقاً پروداکشن رو بازتولید میکنه. SDK فرانت و بک هم بایتبهبایت یکیان و برابر بودن هش SHA-256شون خودش زنگ خطر driftه.
استدلال تازهٔ نویسنده برای ۲۰۲۶ اینه که قبلاً نگرانی از drift آدمها بود، ولی حالا ایجنتها سریعتر drift میکنن. یه مدل با اعتمادبهنفس اندپوینتی میسازه که تقریباً وجود داره، یا فیلدی رو به اسمی که «باید» میداشت تغییر میده. پیشنهادش اینه که بهجای بهتر کردن پرامپت، کانتکست بهتر بدی — و متراکمترین کانتکست همون قرارداده، چون خطای کامپایل تحویلت میده.
هزینههاش رو هم صادقانه میشمرد: بالاخره یه روز باید خودِ ژنراتور رو دیباگ کنی، دریچههای فرار (حالت سختگیر برای CI و حالت هشدار برای آدمها) لازمان وگرنه کل خط لوله دور زده میشه، و هر بیلد چند ثانیه تأخیر میخوره. قاعدهٔ سرانگشتیاش: برای MVP آخر هفته این کار اضافهکاریه؛ بار سومی که یه واقعیت رو تو دو جا درست کردی، وقتشه.
نکات کلیدی:
- هر تعریف تکراری یعنی دو حقیقت که منتظرن با هم اختلاف پیدا کنن
- قرارداد مستندات سیستم نیست، خودِ سیستمه؛ بقیه ازش تولید میشه
- مسیر خطا و قوانین مجوزدهی هم باید توی قرارداد باشن و پیشفرض «ممنوع» باشه
- فرمت عوض میشه (YAML به CUE و protobuf و بعد TypeScript و Zod)، فلسفه میمونه
- محافظت از drift باید دندون داشته باشه: هش، چک تازگی، گیت CI
- توی دورهٔ ایجنتها، قرارداد متراکمترین کانتکستیه که میتونی به مدل بدی




