اخیراً داشتم یه سیستم localization رو بررسی می‌کردم و دیدم یه روش خیلی خوب توش پیاده کرده بودن. stringها توی یه فایل شبیه JSON ذخیره شده بودن؛ ساده و راحت برای مدیریت. یه چیزی مثل این:

{
  "welcome": "Welcome!",
  "goodbye": "Goodbye!"
}

بعد یه code generator وجود داشت که از روی این stringها فایل کد تولید می‌کرد:

public static class Strings
{
    public const string Welcome = "Welcome!";
    public const string Goodbye = "Goodbye!";
}

حالا به جای اینکه دستی با key یه string خام رو بگیری، می‌تونستی خیلی راحت بنویسی:

var text = Strings.Welcome;

فایده‌ی این سیستم اینه که دیگه لازم نیست با روش‌های hacky به inputهای خام دسترسی داشته باشی. یه compiler یا code generator stringهات رو می‌گیره و تبدیلشون می‌کنه به کد قابل استفاده. بعدش هم می‌تونی راحت importشون کنی و توی فایل‌هات استفاده کنی، در حالی که مزایایی مثل IntelliSense رو هم از دست نمی‌دی. اگه پکیج typed-css-modules توی Node.js رو بشناسی، می‌دونی منظورم چیه. اون می‌تونه فایل‌های .css.d.ts تولید کنه و بهت اجازه بده از فایل‌های CSS import کنی، بدون اینکه autocomplete رو از دست بدی.

این طرز فکر یه چیزی بود که اخیراً توی کتاب The Pragmatic Programmer هم درباره‌ش خونده بودم. یادمه نویسنده‌ها درباره‌ی نوشتن کدی که خودش کد می‌نویسه صحبت می‌کردن. انقدر با علاقه از این ایده حرف می‌زدن که با خودم فکر کردم: «شاید اینقدر دوستش دارن چون این کتاب قدیمیه و اون موقع گزینه‌های آماده‌ی زیادی وجود نداشت.» ولی الان تازه فهمیدم منظورشون چی بوده.

پس شروع کردم انتخاب‌های قبلی خودم رو زیر سؤال بردن. با خودم فکر کردم شاید اگه موقع پیاده‌سازی سیستم localization توی بازی Unity خودم این طرز فکر رو داشتم، خیلی بهتر می‌شد. چرا نداشتم؟ اولین مشکلی که به ذهنم رسید این بود که من بیشتر textها رو از طریق GUI assign می‌کردم، پس شاید لازم بود یه enum generator هم درست کنم. ولی بعد یه مشکل بزرگ‌تر پیش اومد: compile شدن کد توی Unity خیلی طول می‌کشه.

من می‌خواستم یه روش ساده و pragmatic پیاده کنم که قرار بود کارم رو راحت‌تر کنه، ولی یه دیوار بزرگ جلوم بود؛ همون چیزی که بهش می‌گم «tool» و خود اون هم یه چیزی بود که باید باهاش کنار می‌اومدم. شاید tool من برای این کار مناسب نبود. شاید توی آپدیت‌های آینده درست بشه، ولی بحث مشخصاً Unity نیست. بحث این dependency بزرگیه که به پروژه‌هامون اضافه می‌کنیم.

فهمیدم که این یکی از مشکلات abstractionـه. Unity حجم خیلی زیادی از کدهای سطح پایین رو abstract می‌کنه. این از یه طرف می‌تونه خوب باشه، ولی از یه طرف دیگه ممکنه مبارزه‌ی تو رو تبدیل کنه به این سؤال که: «چطوری با Unity مؤثرتر کار کنم؟» و این دقیقاً یکی از دلایلیه که متخصص‌های این حوزه‌ها ارزش دارن. فهمیدن ریزه‌کاری‌های یه engine زمان و انرژی زیادی می‌خواد. تازه حتی بعد از همه‌ی این‌ها هم احتمالاً بیشترش رو نمی‌فهمی و با هر آپدیت ممکنه عملاً با یه برنامه‌ی جدید طرف باشی. Unity برای تیم تو بهینه نشده؛ برای یه تیم متوسط بهینه شده.

پس اصلاً ارزشش رو داره؟ این frameworkها و لایه‌های abstraction همون لحظه توی وقتت صرفه‌جویی می‌کنن، ولی در بلندمدت باید ساعت‌هایی رو هم حساب کنی که صرف یاد گرفتن engine خودت می‌کنی؛ یه black box که شاید حتی به internalsش هم دسترسی نداشته باشی. واقعاً مطمئنی که در بلندمدت ساختن engine خودت یا استفاده از یه framework سطح پایین‌تر، بیشتر از یاد گرفتن و کار کردن با محدودیت‌های Unity یا Unreal زمان می‌بره؟

این موضوع شبیه سریع‌تر کد نوشتنه. به‌صورت فرضی ممکنه بتونی برنامه‌ها رو دو برابر سریع‌تر بنویسی، ولی اگه این کار باعث بشه دو برابر بیشتر bug تولید کنی، شاید دیگه ارزشش رو نداشته باشه. آیا abstraction واقعاً داره کمکت می‌کنه؟

باید بگم که من کلاً مخالف abstraction نیستم. به نظرم برای کسایی که این abstractionها رو می‌سازن عالیه و قطعاً برای بقیه هم بعضی وقت‌ها خیلی مفیده. من قطعاً برای یه پروژه‌ی web development سفارشی نمی‌رم با C کد بنویسم. ولی باید حواسمون باشه: تا چه حد باید abstraction رو قبول کنیم؟

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

سؤال اینجا درباره‌ی trade-offهاست. آیا ابزار خودکاری که داری استفاده می‌کنی واقعاً در بلندمدت به نفعت تموم می‌شه؟ آیا واقعاً ارزش داره این همه jargon یاد بگیری فقط برای اینکه یه مقدار بیشتر انرژی ذخیره کنی؟ می‌تونی از بقیه هم بپرسی، ولی حواست باشه: sunk cost fallacy می‌تونه خیلی روی این بحث‌ها تأثیر بذاره. ممکنه یکی بگه: «آره، خیلی عالیه»، فقط چون خودش قبلاً انقدر وقت و انرژی روی اون چیز گذاشته که دیگه نمی‌خواد از صفر شروع کنه.

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

با اینکه این مقاله درباره‌ی AI نیست، می‌خوام آخرش اشاره کنم که AI چقدر abstraction به چرخه‌های development ما اضافه کرده. abstractionهای قدیم صرفاً چیزهایی بودن که ما نمی‌دونستیم، نه چیزهایی که هیچ‌کس نمی‌دونست. Unity کلی developer داره که چیزهای داخلش رو می‌سازن. اون‌ها مستندات خیلی دقیقی درباره‌ی اینکه engine زیر hood چطور کار می‌کنه و چطور می‌شه با جزئیات زیاد optimizeش کرد می‌نویسن. تو Unity رو با این روش یاد نمی‌گیری که یه سری کلمه به سمتش پرت کنی، ببینی چی جواب می‌ده و بعد سعی کنی از توش یه سری pattern پیدا کنی.

ولی ما با AI دقیقاً همین کار رو می‌کنیم. یه black box واقعی که خروجیش یه مقداری randomness داره و فقط با trial and error می‌تونی یاد بگیری چطور باهاش کار کنی. ممکنه الان زندگیت رو راحت‌تر کنه، ولی technical debtی که به پروژه‌ات اضافه می‌کنه چیزی نیست که بتونی تا ابد نادیده بگیری. با اینکه عملاً برای کارم دارم «AI Engineering» انجام می‌دم، AI واقعاً ابزار ترسناکی برای developmentـه و هنوز مطمئن نیستم استفاده‌ی واقعاً خوب ازش چیه، به‌جز انجام دادن کارهای خیلی mundane مثل rename کردن چند تا variable یا چنین فرایندهای refactoring.