زمینهٔ تاریخی
کن تامپسون از چهرههای اصلی شکلگیری Unix در Bell Labs بود. کار او روی زبان B نیز در تاریخ زبانهای برنامهنویسی سیستمی جای دارد؛ همکاری با دنیس ریچی به پیوند عمیق Unix و C انجامید.
نگاه طراحی
از این تاریخ میتوان یک پرسش عملی بیرون کشید: آیا اجزای کوچک با قراردادهای روشن، مسئله را بهتر از یک جزء بزرگ حل میکنند؟ پاسخ به زمینه بستگی دارد، اما سادگی قابل ترکیب همچنان ایدهای ارزشمند است.
سادگیِ قابل ترکیب
سادگی در طراحی سیستم به معنی کمبود قابلیت نیست. گاهی یک جزء کوچک با ورودی و خروجی مشخص، در کنار اجزای دیگر راهحل قدرتمندتری میسازد. برای فهم میراث Unix، توجه به همین قراردادها از حفظکردن نام فرمانها مهمتر است. برنامه باید روشن کند چه چیزی میگیرد، چه چیزی برمیگرداند و شکست را چگونه اعلام میکند.
وقتی دو ابزار قرار است پشت سر هم کار کنند، قالب خروجی ابزار اول بخشی از رابط ابزار دوم میشود. تغییر بیبرنامهٔ فاصلهها، پیامهای اضافی یا کد خروج، میتواند زنجیره را خراب کند. به همین دلیل رابط خط فرمان، درست مانند API، نیازمند ثبات و مستندات است.
مثال آموزشی: یک خط لولهٔ داده
تصور کن قرار است چند فایل لاگ خوانده، رکوردهای معتبر انتخاب و شمارش نهایی گزارش شود. میتوان این کار را به چند مرحلهٔ کوچک تقسیم کرد: خواندن، اعتبارسنجی، پالایش و تجمیع. هر مرحله را جداگانه آزمایش کن و سپس قرارداد انتقال داده میان مراحل را بررسی کن. مزیت این روش، دیدن محل خطا و تعویض یک جزء بدون بازنویسی همهٔ فرایند است.
این الگو همیشه بهترین پاسخ نیست. اگر هزینهٔ انتقال داده زیاد باشد یا مرز مراحل مصنوعی انتخاب شود، یک راهحل یکپارچه مناسبتر خواهد بود. درس اصلی، کوچککردن بیهدف همهچیز نیست؛ انتخاب مرزهایی است که فهم، آزمون و تغییر را آسانتر کنند.
اعتماد به ابزارهای سازنده
برنامهنویس تنها به کد خودش وابسته نیست؛ ابزار ساخت، وابستگیها و محیط اجرا نیز در نتیجه نقش دارند. بررسی نسخهٔ ابزار، امکان بازتولید خروجی و ثبت منشأ وابستگیها، بخشی از مهندسی قابل اعتماد است. این نگاه مکمل سادگی رابطهاست: هم باید بدانیم اجزا چگونه با هم کار میکنند و هم بدانیم آنها از کجا آمدهاند.
برداشت آموزشی IROSG این است که یک ابزار کوچک بنویسی که خروجی داده و پیام خطا را از هم جدا کند، روی دادهٔ نامعتبر کد خروج مناسب بدهد و در مستندات مثال قابل اجرا داشته باشد. چنین تمرینی، ایدهٔ ابزارهای قابل ترکیب را از شعار به تجربهٔ واقعی تبدیل میکند.
یک مسئله را به چند قرارداد کوچک تبدیل کنیم
برای نزدیکشدن به ایدهٔ ابزارهای قابل ترکیب، وظیفهای ساده انتخاب کنید: شمارش رخدادهای یک فایل متنی. میتوان یک برنامهٔ بزرگ نوشت که خواندن فایل، انتخاب سطر، مرتبسازی و گزارش را همزمان انجام دهد. راه دیگر، تقسیم مسئله به چند مرحله با ورودی و خروجی روشن است. این مثال، تمرین طراحی است و بازسازی یک ابزار مشخص تاریخی نیست. هدف، مقایسهٔ هزینهٔ فهم، آزمون و تغییر دو ساختار است.
در روش چندمرحلهای، هر جزء باید بداند چه میگیرد و چه تحویل میدهد. قالب خروجی مرحلهٔ نخست، قرارداد ورودی مرحلهٔ دوم میشود. اگر یکی از اجزا پیام توضیحی را وسط داده چاپ کند، زنجیره ممکن است نتیجهٔ نادرست بدهد. بنابراین کوچکبودن جزء بهتنهایی کافی نیست؛ قرارداد روشن، رفتار خطا و سازگاری قالبها نیز لازماند. سادگی زمانی ارزشمند است که ترکیب اجزا قابل استدلال باقی بماند.
تمرین زنجیرهٔ پردازش بدون دادهٔ حساس
یک فایل آزمایشی با ده سطر بسازید که چند مقدار تکراری، یک سطر خالی و چند نویسهٔ فارسی داشته باشد. خروجی مورد انتظار را با دست مشخص کنید. سپس مراحل انتخاب، تبدیل و شمارش را جدا اجرا کنید و خروجی میانی هر مرحله را نگه دارید. اگر نتیجهٔ نهایی غلط بود، اکنون میتوان مرز خطا را پیدا کرد. استفاده از دادهٔ ساختگی باعث میشود تمرین، اطلاعات کاربران یا اسرار سیستم را وارد ابزارهای آزمایشی نکند.
در دور دوم، فایل بزرگتری بسازید و ببینید آیا هر مرحله تمام داده را یکباره در حافظه نگه میدارد یا میتواند تدریجی کار کند. این انتخاب بر مصرف حافظه و زمان رسیدن نخستین خروجی اثر دارد. هیچ راهی همیشه برنده نیست؛ مرتبسازی کامل با انتخاب مستقل سطرها نیاز یکسانی ندارد. نتیجهٔ تمرین باید نشان دهد کدام فرض برای مسئلهٔ شما مهم است، نه اینکه صرفاً تعداد خطوط کد کمتر شده باشد.
خطا چگونه از مرز یک ابزار عبور میکند؟
فرض کنید مرحلهٔ خواندن فایل شکست میخورد، ولی مرحلهٔ گزارش یک خروجی خالی و ظاهراً سالم تولید میکند. اگر فقط آخرین خروجی دیده شود، کاربر ممکن است تصور کند هیچ رخدادی وجود نداشته است. این مثال نشان میدهد وضعیت خروج و پیام خطا بخشی از رابط ابزارند. طراحی خوب باید تفاوت «هیچ دادهای پیدا نشد» و «نتوانستیم داده را بخوانیم» را حفظ کند.
برای آزمون این قرارداد، مسیر فایل ناموجود، دسترسی ناکافی و ورودی ناقص را جدا امتحان کنید. لازم نیست به فایلهای واقعی سیستم دست بزنید؛ یک پوشهٔ آزمایشی کافی است. سپس مشخص کنید زنجیره در کدام خطا متوقف میشود و چه چیزی به کاربر اعلام میکند. خروجیِ کوتاه اما مبهم، از گزارشِ روشن بهتر نیست. سادگی رابط باید با امکان عیبیابی همراه باشد تا تیم در شرایط واقعی مجبور به حدسزدن نشود.
اعتماد به ابزار سازندهٔ ابزار
مطالعهٔ تاریخ سیستمها، پرسش دیگری هم پیش میکشد: برنامه را با چه ابزاری ساختهایم و چرا به آن اعتماد میکنیم؟ دیدن متن منبع بهتنهایی همهٔ مراحل ساخت و توزیع را توضیح نمیدهد. در یک فرایند آموزشی، نسخهٔ ابزار ساخت، وابستگیها و خروجی نهایی را ثبت کنید. این پیشنهاد، ادعای وجود آلودگی در ابزار خاصی نیست؛ روشی برای آشکارکردن زنجیرهٔ فرضهاست.
اگر دو نفر از یک ورودی خروجی متفاوت میگیرند، تفاوت محیط، گزینههای ساخت و وابستگیها را بررسی کنید. نتیجهٔ این بررسی میتواند مستند کوتاهی باشد که راه بازتولید را روشن میکند. دنبالکردن زنجیرهٔ اعتماد به معنی بیاعتمادی بیپایان نیست؛ باید مرز مسئولیت و میزان اطمینان لازم برای کاربرد مشخص شود. سامانهٔ آموزشی و مؤلفهٔ حساس سازمان ممکن است نیاز متفاوتی داشته باشند.
مطالعهٔ همکاری بهجای فهرست افتخارات
در روایت تامپسون، همکاری با دیگران و پیوند میان ابزار، زبان و سیستمعامل اهمیت دارد. هنگام خواندن منابع، سعی کنید هر دستاورد را به مسئلهای که حل میکرد وصل کنید. سپس یک نمونهٔ کوچک از همان نوع مسئله بسازید و محدودیت روش را پیدا کنید. این شیوهٔ مطالعه کمک میکند تاریخ فناوری از مجموعهای از نامها و جایزهها به مجموعهای از پرسشهای طراحی تبدیل شود؛ پرسشهایی که هنوز میتوان آنها را در پروژههای کوچک و قابل بررسی تجربه کرد.