Skip to content

پروژه‌های عمل‌گرایانه

با شروع پروژه، باید از مسائل فلسفه و کدنویسی فردی فاصله بگیریم و دربارهٔ مسائل بزرگ‌تر در مقیاس پروژه صحبت کنیم. قرار نیست وارد جزئیات مدیریت پروژه شویم، اما چند حوزهٔ حیاتی را بررسی می‌کنیم که می‌توانند هر پروژه‌ای را بسازند یا بشکنند.

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

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

قبلاً دربارهٔ آزمون هم‌زمان با کدنویسی صحبت کردیم. در آزمون بی‌رحمانه به گام بعدی فلسفه و ابزارهای آزمون در مقیاس پروژه می‌رویم — به‌ویژه اگر تیم QA بزرگی در اختیار ندارید.

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

موفقیت در چشم بیننده است — حامی پروژه. ادراک موفقیت مهم است، و در انتظارات بزرگ چند ترفند برای خوشحال کردن حامی هر پروژه نشان می‌دهیم.

آخرین نکتهٔ کتاب مستقیماً نتیجهٔ همهٔ بقیه است. در غرور و تعصب شما را تشویق می‌کنیم کار خود را امضا کنید و به آن افتخار کنید.


۴۱ — تیم‌های عمل‌گرا

در گروه L، استافل بر شش برنامه‌نویس درجهٔ یک نظارت می‌کند؛ چالش مدیریتی تقریباً به اندازهٔ گله کردن گربه‌ها دشوار است. — The Washington Post Magazine، ۹ ژوئن ۱۹۸۵

تا اینجای کتاب تکنیک‌های عمل‌گرایانه‌ای را دیدیم که به فرد کمک می‌کند برنامه‌نویس بهتری باشد. آیا این روش‌ها برای تیم‌ها هم کار می‌کنند؟

پاسخ یک «بله» پرصداست! مزایای عمل‌گرا بودن فردی وجود دارد، اما این مزایا چندین برابر می‌شوند اگر فرد در یک تیم عمل‌گرا کار کند.

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

بیایید برخی بخش‌های قبلی را از منظر تیم بازخوانی کنیم.

پنجره‌های شکسته نداشته باشید

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

تیم‌ها به‌طور کلی نباید پنجره‌های شکسته را تحمل کنند — همان ناقصی‌های کوچکی که کسی درستشان نمی‌کند. تیم باید مسئولیت کیفیت محصول را بپذیرد، از توسعه‌دهندگانی که فلسفهٔ «پنجره شکسته نباشد» را که در آنتروپی نرم‌افزار (صفحهٔ ۴) توصیف کردیم درک می‌کنند حمایت کند، و کسانی را که هنوز کشفش نکرده‌اند تشویق کند.

برخی متدولوژی‌های تیمی یک مسئول کیفیت دارند — کسی که تیم مسئولیت کیفیت تحویلی را به او واگذار می‌کند. این آشکاراً مضحک است: کیفیت فقط از مشارکت فردی همهٔ اعضای تیم می‌آید.

قورباغه‌های پخته

قورباغهٔ بدبخت در تابهٔ آب را به یاد دارید، در سوپ سنگی و قورباغه‌های پخته (صفحهٔ ۷)؟ تغییر تدریجی محیط را متوجه نمی‌شود و در نهایت پخته می‌شود. همین برای افرادی که هوشیار نیستند رخ می‌دهد. در گرمای توسعهٔ پروژه، سخت است چشم‌تان را روی محیط کلی نگه دارید.

برای تیم‌ها حتی آسان‌تر است که پخته شوند. مردم فرض می‌کنند کس دیگری مسئله را حل می‌کند، یا رهبر تیم تغییری را که کاربر می‌خواهد تأیید کرده. حتی تیم‌های با نیت خوب می‌توانند نسبت به تغییرات مهم در پروژه‌شان غافل باشند.

با این مبارزه کنید. مطمئن شوید همه فعالانه محیط را برای تغییرات پایش می‌کنند. شاید یک «آزمایش‌گر ارشد آب» منصوب کنید. این فرد مداوم به‌دنبال افزایش دامنه، کاهش بازهٔ زمانی، ویژگی‌های اضافه، محیط‌های جدید — هر چیزی که در توافق اولیه نبود — باشد. معیارهایی برای نیازمندی‌های جدید نگه دارید (صفحهٔ ۲۰۹ را ببینید). تیم لازم نیست تغییرات را یک‌جا رد کند — فقط باید بداند در حال رخ دادن‌اند. وگرنه خودتان در آب داغ خواهید بود.

ارتباط برقرار کنید

آشکار است که توسعه‌دهندگان در یک تیم باید با هم حرف بزنند. در ارتباط برقرار کنید! (صفحهٔ ۱۸) پیشنهادهایی برای تسهیل این کار دادیم. اما آسان است فراموش کنیم تیم خودش در سازمان حضور دارد. تیم به‌عنوان یک موجودیت باید با بقیهٔ جهان واضح ارتباط برقرار کند.

برای بیرونی‌ها، بدترین تیم‌های پروژه آن‌هایی‌اند که سرد و کم‌حرف به نظر می‌رسند. جلساتی بدون ساختار برگزار می‌کنند که کسی نمی‌خواهد حرف بزند. اسنادشان آشفته است: هیچ دو سندی شبیه نیستند و هر کدام اصطلاحات متفاوتی دارند.

تیم‌های پروژهٔ عالی شخصیت متمایزی دارند. مردم منتظر جلسات با آن‌ها می‌مانند، چون می‌دانند اجرای آماده‌ای خواهند دید که به همه حس خوبی می‌دهد. مستنداتی که تولید می‌کنند دقیق، درست و یکدست است. تیم با یک صدا حرف می‌زند.¹ شاید حتی حس شوخ‌طبعی داشته باشند.

یک ترفند سادهٔ بازاریابی به تیم کمک می‌کند با یک صدا ارتباط برقرار کند: یک برند بسازید. وقتی پروژه را شروع می‌کنید، نامی برایش انتخاب کنید، ترجیحاً چیزی عجیب. (در گذشته پروژه‌هایی را به نام طوطی‌های قاتل که به گوسفند شکار می‌کنند، خطای دید و شهرهای افسانه‌ای نام‌گذاری کرده‌ایم.) ۳۰ دقیقه برای یک لوگوی عجیب وقت بگذارید و روی یادداشت‌ها و گزارش‌ها استفاده کنید. در گفتگو با مردم آزادانه از نام تیم استفاده کنید. احمقانه به نظر می‌رسد، اما به تیم هویتی برای ساختن می‌دهد و به جهان چیز به‌یادماندنی برای ارتباط با کار شما.

خودتان را تکرار نکنید

در شرارت‌های تکرار (صفحهٔ ۲۶) دربارهٔ دشواری حذف کار تکراری بین اعضای تیم صحبت کردیم. این تکرار به اتلاف تلاش منجر می‌شود و می‌تواند کابوس نگهداری ایجاد کند. ارتباط خوب کمک می‌کند، اما گاهی چیز اضافه لازم است.

برخی تیم‌ها یک عضو را به‌عنوان کتابدار پروژه منصوب می‌کنند، مسئول هماهنگی مستندات و مخازن کد. اعضای دیگر می‌توانند هنگام جستجوی چیزی اول به او مراجعه کنند. کتابدار خوب هم می‌تواند تکرار در راه با خواندن مطالبی که مدیریت می‌کند پیش‌بینی کند.

وقتی پروژه برای یک کتابدار بزرگ است (یا کسی نقش را نمی‌خواهد)، افرادی را به‌عنوان کانون‌های تمرکز برای جنبه‌های عملکردی مختلف کار منصوب کنید. اگر کسی می‌خواهد دربارهٔ مدیریت تاریخ صحبت کند، باید بداند با مری حرف بزند. اگر مسئلهٔ طرح پایگاه داده است، سراغ فرد بروید.

ارزش سیستم‌های groupware و گروه‌های خبری Usenet محلی برای ارتباط و بایگانی پرسش و پاسخ را فراموش نکنید.

یادداشت ۱: تیم با یک صدا حرف می‌زند — در بیرون. درون تیم، بحث‌های پرشور و قوی را شدیداً تشویق می‌کنیم. توسعه‌دهندگان خوب معمولاً به کارشان علاقه‌مندند.

متعامد بودن

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

در برخی فرهنگ‌های توسعه، تقسیم‌های سخت مسئولیت را اجبار می‌کنند؛ برنامه‌نویسان حق صحبت با آزمایش‌گران را ندارند، آزمایش‌گران حق صحبت با معمار ارشد را ندارند و غیره. برخی سازمان‌ها با زنجیره‌های مدیریتی جدا برای زیرتیم‌ها مشکل را بدتر می‌کنند.

اشتباه است فکر کنیم فعالیت‌های پروژه — تحلیل، طراحی، کدنویسی و آزمون — می‌توانند جدا باشند. نمی‌توانند. این‌ها دیدگاه‌های مختلف از یک مسئله‌اند و جدا کردن مصنوعی‌شان دردسر زیادی می‌آورد. برنامه‌نویسانی که دو یا سه سطح از کاربران واقعی کدشان فاصله دارند، بعید است از بافت استفادهٔ کارشان آگاه باشند و نمی‌توانند تصمیم‌های آگاهانه بگیرند.

TIP 60

بر اساس عملکرد سازمان‌دهی کنید، نه نقش شغلی

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

عملکرد اینجا لزوماً به معنای use caseهای کاربر نهایی نیست. لایهٔ دسترسی پایگاه داده هم شمرده می‌شود، زیرسیستم راهنما هم. به‌دنبال تیم‌های منسجم و تا حد زیادی خودکفا هستیم — همان معیاری که برای ماژولار کردن کد باید استفاده کنیم. نشانه‌های هشدار سازمان اشتباه تیم وجود دارد — مثال کلاسیک دو زیرتیم است که روی همان ماژول یا کلاس برنامه کار می‌کنند.

این سبک عملکردی چطور کمک می‌کند؟ منابع را با همان تکنیک‌های سازمان‌دهی کد مرتب کنید — قراردادها (طراحی قراردادمحور، صفحهٔ ۱۰۹)، جداسازی (جداسازی و قانون دمتر، صفحهٔ ۱۳۸) و متعامد بودن (صفحهٔ ۳۴) — و تیم را به‌عنوان کل از اثر تغییر جدا می‌کنید. اگر کاربر ناگهان فروشندهٔ پایگاه داده را عوض کند، فقط تیم پایگاه داده تحت تأثیر است. اگر بازاریابی بخواهد ابزار آماده برای تقویم استفاده کند، گروه تقویم ضربه می‌خورد. با اجرای درست، این رویکرد تعداد تعاملات بین کار افراد را کم می‌کند، بازهٔ زمانی را کوتاه می‌کند، کیفیت را بالا می‌برد و باگ‌ها را کم می‌کند. همچنین می‌تواند به مجموعهٔ متعهدتری از توسعه‌دهندگان منجر شود. هر تیم می‌داند تنها مسئول یک عملکرد خاص است و مالکیت بیشتری نسبت به خروجی‌اش احساس می‌کند.

اما این رویکرد فقط با توسعه‌دهندگان مسئول و مدیریت پروژهٔ قوی کار می‌کند. ساخت مجموعه‌ای از تیم‌های خودمختار و رها کردنشان بدون رهبری، دستور فاجعه است. پروژه حداقل به دو «سر» نیاز دارد — یکی فنی، دیگری اداری. سر فنی فلسفه و سبک توسعه را تعیین می‌کند، مسئولیت‌ها را به تیم‌ها می‌دهد و «بحث‌های» اجتناب‌ناپذیر بین افراد را داوری می‌کند. سر فنی هم مداوم به تصویر بزرگ نگاه می‌کند و هر مشترکات غیرضروری بین تیم‌ها که متعامد بودن کل تلاش را کم کند پیدا می‌کند. سر اداری، یا مدیر پروژه، منابع مورد نیاز تیم‌ها را زمان‌بندی می‌کند، پیشرفت را پایش و گزارش می‌دهد و اولویت‌ها را بر اساس نیاز کسب‌وکار تعیین می‌کند. سر اداری شاید سفیر تیم هنگام ارتباط با دنیای بیرون هم باشد.

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

این نوع سازمان تیمی از نظر روحی شبیه مفهوم قدیمی تیم برنامه‌نویس ارشد است که اولین بار در ۱۹۷۲ مستند شد [Bak72].

یادداشت ۲: در The Rational Unified Process: An Introduction، نویسنده ۲۷ نقش جدا در تیم پروژه شناسایی می‌کند! [Kru98]

خودکارسازی

راه خوبی برای اطمینان از یکنواختی و دقت، خودکارسازی همهٔ کارهایی است که تیم انجام می‌دهد. چرا کد را دستی چیدمان کنید وقتی ویرایشگر هنگام تایپ خودکار انجام می‌دهد؟ چرا فرم‌های آزمون را پر کنید وقتی build شبانه می‌تواند آزمون‌ها را خودکار اجرا کند؟

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

بدانید کی رنگ اضافه کردن را متوقف کنید

به یاد داشته باشید تیم‌ها از افراد ساخته می‌شوند. به هر عضو اجازه دهید به روش خودش بدرخشد. فقط به اندازهٔ کافی ساختار بدهید که از آن‌ها حمایت کند و پروژه مطابق نیازمندی‌ها تحویل دهد. سپس، مانند نقاش در نرم‌افزار به اندازه کافی خوب (صفحهٔ ۱۱)، در برابر وسوسهٔ افزودن رنگ بیشتر مقاومت کنید.

بخش‌های مرتبط:

  • آنتروپی نرم‌افزار، صفحهٔ ۴
  • سوپ سنگی و قورباغه‌های پخته، صفحهٔ ۷
  • نرم‌افزار به اندازه کافی خوب، صفحهٔ ۹
  • ارتباط برقرار کنید!، صفحهٔ ۱۸
  • شرارت‌های تکرار، صفحهٔ ۲۶
  • متعامد بودن، صفحهٔ ۳۴
  • طراحی قراردادمحور، صفحهٔ ۱۰۹
  • جداسازی و قانون دمتر، صفحهٔ ۱۳۸
  • خودکارسازی همه‌جا، صفحهٔ ۲۳۰

Challenges

  • اطراف را برای تیم‌های موفق خارج از توسعهٔ نرم‌افزار بگردید. چه چیزی آن‌ها را موفق می‌کند؟ آیا از فرایندهای این بخش استفاده می‌کنند؟
  • دفعهٔ بعد که پروژه‌ای شروع می‌کنید، مردم را متقاعد کنید آن را برند کنند. به سازمان فرصت دهید به ایده عادت کند، سپس ممیزی سریع انجام دهید و ببینید چه تفاوتی در تیم و بیرون ایجاد کرد.
  • جبر تیم: در مدرسه مسائلی مثل «اگر ۴ کارگر ۶ ساعت طول بکشد گودالی بکنند، ۸ کارگر چقدر طول می‌کشد؟» می‌دهند. در زندگی واقعی چه عواملی پاسخ «اگر ۴ برنامه‌نویس ۶ ماه طول بکشد یک برنامه بسازند، ۸ برنامه‌نویس چقدر طول می‌کشد؟» را تحت تأثیر قرار می‌دهند؟ در چند سناریو زمان واقعاً کم می‌شود؟

۴۲ — خودکارسازی همه‌جا

تمدن با گسترش تعداد عملیات مهمی که می‌توانیم بدون فکر کردن انجام دهیم پیش می‌رود. — آلفرد نورث وایت‌هد

در آغاز عصر خودرو، دستورالعمل راه‌اندازی Model-T فورد بیش از دو صفحه بود. در خودروهای مدرن فقط کلید را می‌چرخانید — رویهٔ راه‌اندازی خودکار و ضدخطاست. کسی که فهرست دستورالعمل را دنبال کند ممکن است موتور را سیلابی کند، اما استارت خودکار نمی‌کند.

اگرچه محاسبات هنوز در مرحلهٔ Model-T است، نمی‌توانیم برای هر عملیات رایج بارها دو صفحه دستورالعمل را تکرار کنیم. چه رویهٔ build و انتشار باشد، چه کاغذبازی بازبینی کد یا هر کار تکراری دیگر در پروژه، باید خودکار باشد. شاید استارت و انژکتور سوخت را از صفر بسازیم، اما وقتی آماده شد، از آن به بعد فقط کلید را بچرخانیم.

علاوه بر این می‌خواهیم یکنواختی و تکرارپذیری در پروژه تضمین شود. رویه‌های دستی یکنواختی را به شانس واگذار می‌کنند؛ تکرارپذیری تضمین نیست، به‌ویژه اگر بخش‌هایی از رویه برای افراد مختلف قابل تفسیر باشد.

همه روی خودکار

یک‌بار در محل مشتری بودیم که همهٔ توسعه‌دهندگان از یک IDE استفاده می‌کردند. مدیر سیستم به هر توسعه‌دهنده دستورالعمل نصب بسته‌های افزودنی IDE را داده بود. این دستورالعمل‌ها صفحات زیادی بود — پر از «اینجا کلیک کن، آنجا اسکرول کن، این را بکش، آن را دو بار کلیک کن و دوباره تکرار کن».

جای تعجب نیست هر ماشین توسعه‌دهنده کمی متفاوت بار شده بود. تفاوت‌های ریز در رفتار برنامه وقتی توسعه‌دهندگان مختلف همان کد را اجرا می‌کردند ظاهر می‌شد. باگ‌ها روی یک ماشین بود و روی دیگران نبود. ردیابی تفاوت نسخهٔ هر جزء معمولاً غافلگیری داشت.

TIP 61

از رویه‌های دستی استفاده نکنید

مردم به اندازهٔ کامپیوترها تکرارپذیر نیستند و نباید انتظار داشته باشیم. اسکریپت پوسته یا فایل batch همان دستورات را به همان ترتیب، بارها اجرا می‌کند. می‌توان آن را زیر کنترل کد منبع گذاشت تا تغییرات رویه را در طول زمان بررسی کنید («ولی قبلاً کار می‌کرد...»).

ابزار محبوب دیگر خودکارسازی، cron است (یا «at» در Windows NT). اجازه می‌دهد کارهای بدون حضور را به‌صورت دوره‌ای — معمولاً نیمه‌شب — زمان‌بندی کنیم. مثلاً فایل crontab زیر مشخص می‌کند دستور شبانهٔ پروژه هر روز پنج دقیقه بعد از نیمه‌شب اجرا شود، پشتیبان‌گیری ساعت ۳:۱۵ صبح در روزهای هفته، و expense_reports نیمه‌شب اول هر ماه:

text
# MIN HOUR DAY MONTH DAYOFWEEK   COMMAND
# ---------------------------------------------------------------
    5    0   *     *     *       /projects/Manhattan/bin/nightly
   15    3   *     *   1-5       /usr/local/bin/backup
    0    0   1     *     *       /home/accounting/expense_reports

با cron می‌توانیم پشتیبان‌گیری، build شبانه، نگهداری وب‌سایت و هر کار دیگری را — بدون حضور، خودکار — زمان‌بندی کنیم.

کامپایل پروژه

کامپایل پروژه کاری است که باید قابل‌اعتماد و تکرارپذیر باشد. معمولاً پروژه‌ها را با Makefile کامپایل می‌کنیم، حتی با محیط IDE. چند مزیت دارد: رویهٔ اسکریپتی و خودکار است. می‌توانیم قلاب اضافه کنیم تا کد برایمان تولید شود و آزمون‌های رگرسیون خودکار اجرا شوند. IDE مزایای خود را دارد، اما با IDE تنها سخت است به سطح خودکارسازی مورد نظر برسیم. می‌خواهیم با یک دستور checkout، build، test و ship کنیم.

تولید کد

در شرارت‌های تکرار (صفحهٔ ۲۶) تولید کد برای استخراج دانش از منابع مشترک را پیشنهاد کردیم. می‌توانیم از مکانیزم تحلیل وابستگی make برای آسان کردن این فرایند استفاده کنیم. افزودن قواعد به Makefile برای تولید خودکار فایلی از منبع دیگر ساده است. مثلاً فرض کنید می‌خواهیم از فایل XML فایل Java بسازیم و نتیجه را کامپایل کنیم:

makefile
.SUFFIXES: .java .class .xml
.xml.java:
        perl convert.pl $<      > $@
.java.class:
        $(JAVAC) $(JAVAC_FLAGS) $<

با تایپ make test.class، make خودکار به‌دنبال test.xml می‌گردد، با اجرای اسکریپت Perl فایل .java می‌سازد و سپس آن را کامپایل می‌کند تا test.class تولید شود.

می‌توانیم قواعد مشابه برای تولید خودکار کد منبع، فایل هدر یا مستندات از شکل دیگر استفاده کنیم (مولدهای کد، صفحهٔ ۱۰۲ را ببینید).

آزمون‌های رگرسیون

می‌توانید Makefile را برای اجرای آزمون‌های رگرسیون — برای یک ماژول یا کل زیرسیستم — به کار ببرید. با یک دستور در بالای درخت منبع کل پروژه را آزمایش کنید، یا با همان دستور در یک پوشه یک ماژول را. آزمون بی‌رحمانه (صفحهٔ ۲۳۷) را برای رگرسیون بیشتر ببینید.

make بازگشتی

بسیاری از پروژه‌ها Makefileهای بازگشتی و سلسله‌مراتبی برای build و آزمون می‌سازند. اما از برخی مشکلات احتمالی آگاه باشید.

make وابستگی‌ها بین اهداف مختلف را محاسبه می‌کند، اما فقط وابستگی‌هایی را که در یک فراخوانی make وجود دارند تحلیل می‌کند. به‌ویژه، make بازگشتی از وابستگی‌هایی که فراخوانی‌های دیگر make دارند بی‌خبر است. اگر دقیق و محتاط باشید نتیجهٔ درست می‌گیرید، اما آسان است کار اضافهٔ غیرضروری ایجاد کنید — یا وابستگی را از دست بدهید و وقتی لازم است دوباره کامپایل نکنید.

علاوه بر این، وابستگی‌های build ممکن است با وابستگی‌های آزمون یکی نباشند و به سلسله‌مراتب جدا نیاز داشته باشید.

خودکارسازی build

build رویه‌ای است که یک پوشهٔ خالی (و محیط کامپایل شناخته‌شده) می‌گیرد و پروژه را از صفر می‌سازد و هر چیزی که تحویل نهایی می‌خواهید تولید می‌کند — مثلاً تصویر اصلی CD-ROM یا آرشیو خوداستخراج‌شونده. معمولاً build پروژه این گام‌ها را شامل می‌شود:

  1. checkout کد منبع از مخزن.
  2. build پروژه از صفر، معمولاً از Makefile سطح بالا. هر build با شمارهٔ انتشار یا نسخه، یا شاید مهر تاریخ مشخص می‌شود.
  3. ساخت تصویر قابل توزیع. ممکن است شامل اصلاح مالکیت و مجوز فایل‌ها و تولید همهٔ مثال‌ها، مستندات، فایل‌های README و هر چیز دیگری باشد که با محصول ارسال می‌شود، دقیقاً در قالبی که هنگام ارسال لازم است.³
  4. اجرای آزمون‌های مشخص‌شده (make test).

یادداشت ۳: اگر CD-ROM با فرمت ISO9660 تولید می‌کنید، برنامه‌ای را اجرا می‌کنید که تصویر bit-for-bit سیستم فایل ۹۶۶۰ می‌سازد. چرا تا شب قبل از ارسال صبر کنید تا مطمئن شوید کار می‌کند؟

برای بیشتر پروژه‌ها این سطح build هر شب خودکار اجرا می‌شود. در build شبانه معمولاً آزمون‌های کامل‌تری از آنچه فرد هنگام build بخشی از پروژه اجرا می‌کند انجام می‌دهید. نکتهٔ مهم این است که build کامل همهٔ آزمون‌های موجود را اجرا کند. می‌خواهید بدانید آیا آزمون رگرسیون به‌خاطر تغییر کد امروز شکست خورد. با شناسایی مشکل نزدیک منبع، شانس بیشتری برای یافتن و رفع آن دارید.

وقتی آزمون‌ها را منظم اجرا نمی‌کنید، ممکن است بفهمید برنامه سه ماه پیش به‌خاطر تغییر کد خراب شده. موف باشید آن را پیدا کنید.

buildهای نهایی

buildهای نهایی که قصد ارسال به‌عنوان محصول دارید ممکن است از build شبانهٔ معمول متفاوت باشند. build نهایی ممکن است قفل مخزن، برچسب شمارهٔ انتشار، تنظیم متفاوت بهینه‌سازی و پرچم اشکال‌زدایی و غیره بخواهد. ما هدف make جدا (make final مثلاً) را ترجیح می‌دهیم که همهٔ این پارامترها را یک‌جا تنظیم کند.

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

کارهای اداری خودکار

آیا خوب نیست برنامه‌نویسان همهٔ وقتشان را صرف برنامه‌نویسی کنند؟ متأسفانه نادر است. ایمیل پاسخ داده می‌شود، کاغذبازی پر می‌شود، اسناد روی وب گذاشته می‌شوند و غیره. شاید اسکریپت پوسته برای بخشی از کار کثیف بسازید، اما هنوز باید یادتان باشد اجرا کنید.

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

یادداشت ۴: اولین چیزی که از دست می‌دهید چیست؟ یادم رفت.

تولید وب‌سایت

بسیاری از تیم‌های توسعه از وب‌سایت داخلی برای ارتباط پروژه استفاده می‌کنند و این ایدهٔ خوبی است. اما نمی‌خواهیم وقت زیادی صرف نگهداری وب‌سایت کنیم و نمی‌خواهیم کهنه یا از تاریخ بیفتد. اطلاعات گمراه‌کننده از نبود اطلاعات بدتر است.

مستنداتی که از کد، تحلیل نیازمندی‌ها، اسناد طراحی و هر نقشه، نمودار یا گراف استخراج می‌شوند باید منظم روی وب منتشر شوند. دوست داریم این اسناد را خودکار — بخشی از build شبانه یا قلاب checkout کد منبع — منتشر کنیم.

هر طور انجام شود، محتوای وب باید خودکار از اطلاعات مخزن تولید و بدون دخالت انسان منتشر شود. این کاربرد دیگری از اصل DRY است: اطلاعات در یک شکل به‌عنوان کد و اسناد check-in‌شده وجود دارد. نمای مرورگر وب فقط یک نماست. نباید آن نما را دستی نگه دارید.

هر اطلاعاتی که build شبانه تولید می‌کند باید روی وب‌سایت توسعه در دسترس باشد: نتایج خود build (مثلاً خلاصهٔ یک‌صفحه‌ای با هشدارها و خطاهای کامپایلر و وضعیت فعلی)، آزمون‌های رگرسیون، آمار عملکرد، معیارهای کدنویسی و هر تحلیل ایستای دیگر و غیره.

رویه‌های تأیید

برخی پروژه‌ها گردش‌های اداری مختلفی دارند که باید رعایت شوند. مثلاً بازبینی کد یا طراحی باید زمان‌بندی و پیگیری شود، تأییدها لازم است و غیره. می‌توانیم خودکارسازی — به‌ویژه وب‌سایت — را برای کاهش بار کاغذبازی به کار ببرید.

فرض کنید می‌خواهید زمان‌بندی و تأیید بازبینی کد را خودکار کنید. شاید نشانگر ویژه‌ای در هر فایل منبع بگذارید:

c
/* Status: needs_review */

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

می‌توانید فرم روی صفحهٔ وب برای ثبت تأیید یا رد بازبینان بگذارید. پس از بازبینی، وضعیت خودکار به reviewed تغییر کند. اینکه بازبینی کد با حضور همه انجام شود به شما بستگی دارد؛ کاغذبازی را همچنان خودکار می‌توانید انجام دهید. (در مقاله‌ای در CACM آوریل ۱۹۹۹، رابرت گلاس تحقیقاتی را خلاصه می‌کند که نشان می‌دهد بازرسی کد مؤثر است، اما انجام بازبینی در جلسات نه [Gla99a].)

فرزندان کفاش

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

اما همهٔ مواد اولیه برای ساخت ابزار بهتر را داریم: cron، make، Ant و CruiseControl برای خودکارسازی ([Cla04] را ببینید)، و Ruby، Perl و زبان‌های اسکریپت سطح بالا برای توسعهٔ سریع ابزارهای سفارشی، مولدهای صفحهٔ وب، مولدهای کد، چارچوب آزمون و غیره.

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

بخش‌های مرتبط:

  • گربه کد منبع من را خورد، صفحهٔ ۲
  • شرارت‌های تکرار، صفحهٔ ۲۶
  • قدرت متن ساده، صفحهٔ ۷۳
  • بازی‌های پوسته، صفحهٔ ۷۷
  • اشکال‌زدایی، صفحهٔ ۹۰
  • مولدهای کد، صفحهٔ ۱۰۲
  • تیم‌های عمل‌گرا، صفحهٔ ۲۲۴
  • آزمون بی‌رحمانه، صفحهٔ ۲۳۷
  • همه‌چیز نوشتن است، صفحهٔ ۲۴۸

Challenges

  • عادت‌هایتان در طول روز کاری را ببینید. کارهای تکراری می‌بینید؟ همان دنبالهٔ دستورات را بارها تایپ می‌کنید؟
  • چند اسکریپت پوسته برای خودکارسازی بنویسید. همیشه همان دنبالهٔ آیکون‌ها را کلیک می‌کنید؟ می‌توانید ماکرو بسازید؟
  • چقدر از کاغذبازی پروژه را می‌توان خودکار کرد؟ با هزینهٔ بالای نیروی برنامه‌نویسی،⁵ چقدر از بودجهٔ پروژه صرف رویه‌های اداری می‌شود؟ آیا زمان ساخت راه‌حل خودکار با صرفه‌جویی کلی توجیه می‌شود؟

یادداشت ۵: برای برآورد، میانگین صنعتی حدود ۱۰۰٬۰۰۰ دلار آمریکا به ازای هر نفر — حقوق به‌علاوه مزایا، آموزش، فضای اداری و سربار و غیره.


۴۳ — آزمون بی‌رحمانه

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

یافتن باگ کمی شبیه ماهیگیری با تور است. از تورهای ریز و کوچک (آزمون واحد) برای ماهی‌های کوچک و از تورهای درشت و بزرگ (آزمون یکپارچگی) برای کوسه‌های قاتل استفاده می‌کنیم. گاهی ماهی‌ها فرار می‌کنند، پس هر سوراخی که پیدا کنیم وصله می‌کنیم، به امید گرفتن نقص‌های لغزان بیشتر در استخر پروژه.

TIP 62

زود آزمایش کنید. زیاد آزمایش کنید. خودکار آزمایش کنید.

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

بسیاری از تیم‌ها برنامهٔ آزمون دقیق برای پروژه‌هایشان می‌نویسند. گاهی حتی از آن‌ها استفاده می‌کنند. اما دیده‌ایم تیم‌هایی که از آزمون خودکار استفاده می‌کنند شانس موفقیت بسیار بهتری دارند. آزمون‌هایی که با هر build اجرا می‌شوند از برنامه‌های آزمونی که روی قفسه می‌مانند مؤثرترند.

هرچه زودتر باگ پیدا شود، ارزان‌تر رفع می‌شود. «کمی کد بنویس، کمی آزمایش کن» ضرب‌المثل محبوبی در دنیای Smalltalk است،⁶ و می‌توانیم آن را به‌عنوان شعار خود بپذیریم و هم‌زمان با (یا حتی قبل از) نوشتن کد تولید، کد آزمون بنویسیم.

در واقع پروژهٔ خوب ممکن است کد آزمون بیشتری از کد تولید داشته باشد. زمان تولید این کد آزمون ارزشش را دارد. در بلندمدت خیلی ارزان‌تر تمام می‌شود و واقعاً شانس تولید محصولی با نقص نزدیک به صفر دارید.

علاوه بر این، دانستن اینکه آزمون را پاس کرده‌اید اطمینان بالایی می‌دهد که تکه‌ای از کد «تمام» شده.

TIP 63

کدنویسی تمام نشده تا همهٔ آزمون‌ها اجرا نشوند

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

باید سه جنبهٔ اصلی آزمون در مقیاس پروژه را ببینیم: چه چیزی را آزمایش کنیم، چگونه آزمایش کنیم و چه زمانی آزمایش کنیم.

چه چیزی را آزمایش کنیم

چند نوع اصلی آزمون نرم‌افزار وجود دارد:

  • آزمون واحد
  • آزمون یکپارچگی
  • اعتبارسنجی و تأیید
  • اتمام منابع، خطاها و بازیابی
  • آزمون عملکرد
  • آزمون قابلیت استفاده

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

یادداشت ۶: eXtreme Programming [URL 45] این مفهوم را «یکپارچه‌سازی پیوسته، آزمون بی‌امان» می‌نامد.

آزمون واحد

آزمون واحد کدی است که یک ماژول را اجرا می‌کند. این موضوع را در کدی که آزمون آن آسان است (صفحهٔ ۱۸۹) جداگانه پوشش دادیم. آزمون واحد پایهٔ همهٔ شکل‌های دیگر آزمون در این بخش است. اگر قطعات به‌تنهایی کار نکنند، احتمالاً با هم هم خوب کار نمی‌کنند. همهٔ ماژول‌هایی که استفاده می‌کنید باید آزمون واحد خود را پاس کنند قبل از ادامه.

وقتی همهٔ ماژول‌های مرتبط آزمون‌های فردی را پاس کردند، آمادهٔ مرحلهٔ بعد هستید. باید ببینید همهٔ ماژول‌ها چطور در کل سیستم با هم کار و تعامل می‌کنند.

آزمون یکپارچگی

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

آزمون یکپارچگی در واقع گسترش آزمون واحدی است که توصیف کردیم — فقط حالا می‌آزمایید کل زیرسیستم‌ها چطور قراردادهایشان را رعایت می‌کنند.

اعتبارسنجی و تأیید

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

آیا نیازمندی‌های عملکردی سیستم را برآورده می‌کند؟ این هم باید آزمایش شود. سیستمی بدون باگ که به سؤال اشتباه پاسخ می‌دهد خیلی مفید نیست. به الگوهای دسترسی کاربر نهایی و تفاوت آن‌ها با دادهٔ آزمون توسعه‌دهنده آگاه باشید (برای مثال داستان ضربه‌های قلم‌مو در صفحهٔ ۹۲ را ببینید).

اتمام منابع، خطاها و بازیابی

حالا که ایدهٔ نسبتاً خوبی دارید سیستم در شرایط ایده‌آل درست رفتار می‌کند، باید ببینید در شرایط واقعی چطور رفتار می‌کند. در دنیای واقعی برنامه‌ها منابع نامحدود ندارند؛ چیزها تمام می‌شوند. چند محدودیتی که کد ممکن است ببیند:

  • حافظه
  • فضای دیسک
  • پهنای باند CPU
  • زمان ساعت دیواری
  • پهنای باند دیسک
  • پهنای باند شبکه
  • پالت رنگ
  • وضوح تصویر

شاید واقعاً فضای دیسک یا شکست تخصیص حافظه را بررسی کنید، اما چند وقت یک‌بار بقیه را آزمایش می‌کنید؟ آیا برنامه روی صفحهٔ ۶۴۰×۴۸۰ با ۲۵۶ رنگ جا می‌شود؟ آیا روی صفحهٔ ۱۰۲۴×۷۶۸ با رنگ ۲۴ بیتی بدون شبیه تمبر پستی اجرا می‌شود؟ آیا کار دسته‌ای قبل از شروع آرشیو تمام می‌شود؟

می‌توانید محدودیت‌های محیطی مثل مشخصات ویدیو را کشف و متناسب تطبیق دهید. اما همهٔ شکست‌ها قابل بازیابی نیستند. اگر کد تشخیص دهد حافظه تمام شده، گزینه‌هایتان محدود است: شاید منابع کافی برای کار دیگری جز شکست نمانده باشد.

وقتی سیستم خراب می‌شود،⁷ آیا با وقار شکست می‌خورد؟ آیا تا جایی که می‌تواند وضعیت را ذخیره و از دست رفتن کار جلوگیری می‌کند؟ یا «GPF» یا core dump را در چهرهٔ کاربر می‌اندازد؟

یادداشت ۷: ویراستار خواست جمله را به «وقتی سیستم خراب می‌شود» تغییر دهیم. مقاومت کردیم.

آزمون عملکرد

آزمون عملکرد، آزمون فشار یا آزمون تحت بار هم ممکن است جنبهٔ مهمی از پروژه باشد.

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

برای برخی برنامه‌ها شاید به سخت‌افزار یا نرم‌افزار تخصصی برای شبیه‌سازی واقع‌گرایانهٔ بار نیاز داشته باشید.

آزمون قابلیت استفاده

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

قابلیت استفاده را از منظر عوامل انسانی ببینید. آیا در تحلیل نیازمندی سوءتفاهم‌هایی بود که باید رفع شوند؟ آیا نرم‌آفزار مثل امتداد دست به کاربر می‌آید؟ (نه فقط می‌خواهیم ابزار خودمان به دستمان بخورد، بلکه ابزاری که برای کاربران می‌سازیم هم به دستشان بخورد.)

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

برآورده نکردن معیارهای قابلیت استفاده به اندازهٔ تقسیم بر صفر باگ بزرگ است.

چگونه آزمایش کنیم

چه چیزی را آزمایش کنیم را دیدیم. حالا به چگونگی آزمایش می‌پردازیم، از جمله:

  • آزمون رگرسیون
  • دادهٔ آزمون
  • اجرای سیستم‌های GUI
  • آزمون آزمون‌ها
  • آزمون کامل

آزمون طراحی/متدولوژی

آیا می‌توانید طراحی خود کد و متدولوژی ساخت نرم‌افزار را آزمایش کنید؟ تا حدی بله. با تحلیل معیارها — اندازه‌گیری جنبه‌های مختلف کد. ساده‌ترین معیار (و اغلب کم‌جالب‌ترین) تعداد خطوط کد است — کد چقدر بزرگ است؟

معیارهای متنوع دیگری برای بررسی کد وجود دارد، از جمله:

  • معیار پیچیدگی سیکلوماتیک مک‌کیب (پیچیدگی ساختار تصمیم)
  • fan-in وراثت (تعداد کلاس‌های پایه) و fan-out (تعداد ماژول‌های مشتق که این را به‌عنوان والد استفاده می‌کنند)
  • مجموعهٔ پاسخ (جداسازی و قانون دمتر، صفحهٔ ۱۳۸)
  • نسبت‌های جفت‌شدگی کلاس ([URL 48] را ببینید)

برخی معیارها برای «نمره قبولی» طراحی شده‌اند، برخی فقط با مقایسه مفیدند. یعنی برای هر ماژول در سیستم محاسبه می‌کنید و می‌بینید یک ماژول خاص نسبت به بقیه چطور است. معمولاً از تکنیک‌های آماری استاندارد (میانگین و انحراف معیار) استفاده می‌شود.

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

آزمون رگرسیون

آزمون رگرسیون خروجی آزمون فعلی را با مقادیر قبلی (یا شناخته‌شده) مقایسه می‌کند. مطمئن می‌شویم باگ‌هایی که امروز رفع کردیم چیزهایی که دیروز کار می‌کردند را نشکستند. این شبکهٔ ایمنی مهمی است و از غافلگیری‌های ناخوشایند کم می‌کند.

همهٔ آزمون‌هایی که تا اینجا گفتیم می‌توانند به‌عنوان رگرسیون اجرا شوند تا مطمئن شویم با توسعهٔ کد جدید عقب نرفته‌ایم. می‌توانیم رگرسیون برای عملکرد، قراردادها، اعتبار و غیره اجرا کنیم.

دادهٔ آزمون

دادهٔ اجرای همهٔ این آزمون‌ها را از کجا می‌آوریم؟ فقط دو نوع داده داریم: دادهٔ دنیای واقعی و دادهٔ مصنوعی. به هر دو نیاز داریم، چون ماهیت متفاوت این داده‌ها باگ‌های مختلف را آشکار می‌کند.

دادهٔ دنیای واقعی از منبع واقعی می‌آید. شاید از سیستم موجود، سیستم رقیب یا نمونهٔ اولیه جمع‌آوری شده. دادهٔ معمول کاربر را نشان می‌دهد. غافلگیری‌های بزرگ وقتی می‌فهمید «معمول» یعنی چه می‌آید. این بیشترین احتمال را برای آشکار کردن نقص‌ها و سوءتفاهم‌های تحلیل نیازمندی دارد.

دادهٔ مصنوعی به‌صورت مصنوعی تولید می‌شود، شاید تحت محدودیت‌های آماری. شاید به دلایل زیر به دادهٔ مصنوعی نیاز داشته باشید:

  • به دادهٔ زیاد نیاز دارید، شاید بیش از هر نمونهٔ دنیای واقعی. شاید بتوانید دادهٔ واقعی را به‌عنوان بذر برای مجموعهٔ بزرگ‌تر استفاده کنید و برخی فیلدها را که باید یکتا باشند تنظیم کنید.
  • به داده‌ای برای فشار دادن شرایط مرزی نیاز دارید. این داده ممکن است کاملاً مصنوعی باشد: فیلدهای تاریخ با ۲۹ فوریه ۱۹۹۹، اندازهٔ رکورد عظیم، یا آدرس با کد پستی خارجی.
  • به داده‌ای با ویژگی‌های آماری خاص نیاز دارید. می‌خواهید ببینید اگر هر سومین تراکنش شکست بخورد چه می‌شود؟ الگوریتم مرتب‌سازی که با دادهٔ از پیش مرتب‌شده کند می‌شود را به یاد دارید؟ می‌توانید داده را به‌صورت تصادفی یا مرتب ارائه دهید تا این ضعف را آشکار کنید.

اجرای سیستم‌های GUI

آزمون سیستم‌های GUI-محور اغلب به ابزارهای تخصصی نیاز دارد. این ابزارها ممکن است بر مدل ضبط/پخش رویداد ساده باشند یا به اسکریپت‌های نوشته‌شدهٔ مخصوص برای هدایت GUI نیاز داشته باشند. برخی سیستم‌ها ترکیبی از هر دو دارند.

ابزارهای کم‌پیچیده‌تر درجهٔ بالایی از جفت‌شدگی بین نسخهٔ نرم‌افزار تحت آزمون و خود اسکریپت آزمون تحمیل می‌کنند: اگر جعبهٔ گفتگو را جابه‌جا یا دکمه را کوچک‌تر کنید، آزمون شاید آن را پیدا نکند و شکست بخورد. بیشتر ابزارهای مدرن آزمون GUI از تکنیک‌های مختلف برای دور زدن این مشکل استفاده می‌کنند و سعی می‌کنند با تفاوت‌های جزئی چیدمان سازگار شوند.

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

یکی از مزایای زیاد نوشتن کد جداشده (جداسازی و قانون دمتر، صفحهٔ ۱۳۸) آزمون ماژولارتر است. مثلاً برای برنامه‌های پردازش داده با رابط GUI، طراحی باید آن‌قدر جداشده باشد که بتوانید منطق برنامه را بدون GUI آزمایش کنید. این ایده شبیه آزمون اول زیرقطعات است. وقتی منطق برنامه اعتبارسنجی شد، یافتن باگ‌هایی که با رابط کاربری ظاهر می‌شوند آسان‌تر است (احتمالاً باگ‌ها از کد رابط کاربری آمده‌اند).

آزمون آزمون‌ها

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

مجموعهٔ چارچوب‌های آزمون را مثل سیستم امنیتی پیچیده‌ای ببینید که وقتی باگ ظاهر می‌شود زنگ می‌زند. چه راه بهتری برای آزمون سیستم امنیتی از تلاش برای نفوذ؟

بعد از نوشتن آزمون برای کشف باگ خاص، عمداً باگ را ایجاد کنید و مطمئن شوید آزمون شکایت می‌کند. این تضمین می‌کند آزمون اگر واقعاً رخ داد باگ را می‌گیرد.

TIP 64

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

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

هنگام نوشتن آزمون مطمئن شوید وقتی باید زنگ می‌زنند.

آزمون کامل

وقتی مطمئن شدید آزمون‌هایتان درست‌اند و باگ‌هایی که می‌سازید را پیدا می‌کنند، چطور بدانید پایگاه کد را به‌اندازهٔ کافی کامل آزمایش کرده‌اید؟

پاسخ کوتاه «نمی‌دانید» است و هرگز هم نخواهید دانست. اما محصولاتی در بازار هستند که کمک می‌کنند. این ابزارهای تحلیل پوشش کد را در حین آزمون زیر نظر می‌گیرند و ردیابی می‌کنند کدام خطوط اجرا شده و کدام نه. احساس کلی از جامعیت آزمون می‌دهند، اما انتظار ۱۰۰٪ پوشش نداشته باشید.

حتی اگر هر خط کد را اجرا کنید، این کل تصویر نیست. مهم تعداد حالت‌هایی است که برنامه ممکن است داشته باشد. حالت‌ها معادل خطوط کد نیستند. مثلاً تابعی با دو عدد صحیح که هر کدام از ۰ تا ۹۹۹ می‌توانند باشند:

java
int test(int a, int b) {
  return a / (a + b);
}

در تئوری این تابع سه‌خطی ۱٬۰۰۰٬۰۰۰ حالت منطقی دارد؛ ۹۹۹٬۹۹۹ درست کار می‌کنند و یکی نه (وقتی a + b صفر است). فقط دانستن اینکه این خط کد را اجرا کرده‌اید کافی نیست — باید همهٔ حالت‌های ممکن برنامه را شناسایی کنید. متأسفانه به‌طور کلی این مسئلهٔ واقعاً سخت است. سخت به معنای «خورشید قبل از اینکه حلش کنید سنگ سرد می‌شود».

TIP 65

پوشش حالت را آزمایش کنید، نه پوشش کد

حتی با پوشش کد خوب، داده‌ای که برای آزمون استفاده می‌کنید تأثیر بزرگی دارد و مهم‌تر، ترتیبی که کد را طی می‌کنید شاید بزرگ‌ترین تأثیر را داشته باشد.

چه زمانی آزمایش کنیم

بسیاری از پروژه‌ها آزمون را به آخرین لحظه موکول می‌کنند — دقیقاً جایی که با تیغ مهلت قطع می‌شود.⁸ باید خیلی زودتر شروع کنیم. به‌محض وجود هر کد تولید، باید آزمایش شود.

بیشتر آزمون‌ها باید خودکار باشند. مهم است که با «خودکار» منظورمان تفسیر خودکار نتایج آزمون هم هست. خودکارسازی همه‌جا (صفحهٔ ۲۳۰) را برای این موضوع ببینید.

دوست داریم هرچه می‌توانیم آزمایش کنیم و همیشه قبل از check-in کد به مخزن منبع. برخی سیستم‌های کنترل کد منبع مثل Aegis می‌توانند این را خودکار انجام دهند. وگرنه فقط تایپ می‌کنیم:

text
% make test

معمولاً اجرای رگرسیون روی همهٔ آزمون‌های واحد و یکپارچگی به‌اندازهٔ لازم مشکلی ندارد.

اما برخی آزمون‌ها شاید به‌راحتی به‌این‌اندازه مکرر اجرا نشوند. آزمون فشار مثلاً ممکن است به راه‌اندازی یا تجهیزات خاص و کمی همراهی نیاز داشته باشد. شاید کمتر — هفتگی یا ماهانه — اجرا شوند. اما مهم است به‌صورت منظم و زمان‌بندی‌شده اجرا شوند. اگر خودکار نمی‌شود، در برنامه بگذارید و منابع لازم را تخصیص دهید.

یادداشت ۸: deadline (۱۸۶۴) خطی که درون یا اطراف زندان کشیده می‌شود و زندانی با عبور از آن در معرض تیراندازی است — Webster's Collegiate Dictionary.

تنگ کردن تور

در پایان می‌خواهیم مهم‌ترین مفهوم در آزمون را آشکار کنیم. آشکار است و تقریباً هر کتاب درسی می‌گوید همین‌طور انجام دهید. اما به دلایلی بیشتر پروژه‌ها هنوز نمی‌کنند.

اگر باگی از تور آزمون‌های موجود رد شود، باید آزمون جدیدی اضافه کنید تا دفعهٔ بعد بگیردش.

TIP 66

باگ را یک‌بار پیدا کنید

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

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

بخش‌های مرتبط:

  • گربه کد منبع من را خورد، صفحهٔ ۲
  • اشکال‌زدایی، صفحهٔ ۹۰
  • جداسازی و قانون دمتر، صفحهٔ ۱۳۸
  • بازسازی، صفحهٔ ۱۸۴
  • کدی که آزمون آن آسان است، صفحهٔ ۱۸۹
  • خودکارسازی همه‌جا، صفحهٔ ۲۳۰

Challenges

  • آیا می‌توانید پروژه‌تان را خودکار آزمایش کنید؟ بسیاری از تیم‌ها مجبورند «نه» بگویند. چرا؟ تعریف نتایج قابل قبول خیلی سخت است؟ این اثبات «تمام شدن» پروژه به حامیان را سخت نمی‌کند؟
  • آیا آزمون منطق برنامه مستقل از GUI خیلی سخت است؟ این دربارهٔ GUI چه می‌گوید؟ دربارهٔ جفت‌شدگی؟

۴۴ — همه‌چیز نوشتن است

کم‌رنگ‌ترین جوهر از بهترین حافظه بهتر است. — ضرب‌المثل چینی

معمولاً توسعه‌دهندگان به مستندسازی فکر زیادی نمی‌کنند. در بهترین حالت ضرورت ناگوار است؛ در بدترین حالت کار اولویت پایین است به امید اینکه مدیریت در پایان پروژه فراموشش کند.

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

این افکار اصیل یا نو نیستند؛ ایدهٔ پیوند کد و مستندات در کار دونالد کنوث روی برنامه‌نویسی ادبی و ابزار JavaDoc شرکت Sun و غیره دیده می‌شود. می‌خواهیم دوگانگی بین کد و مستندات را کم‌رنگ کنیم و آن‌ها را دو نمای یک مدل بدانیم (فقط یک نماست، صفحهٔ ۱۵۷). در واقع می‌خواهیم یک قدم جلوتر برویم و همهٔ اصول عمل‌گرایانه را به مستندات هم اعمال کنیم، نه فقط کد.

TIP 67

انگلیسی را فقط یک زبان برنامه‌نویسی دیگر بدانید

اساساً دو نوع مستندات برای پروژه تولید می‌شود: داخلی و خارجی. مستندات داخلی شامل توضیحات کد منبع، اسناد طراحی و آزمون و غیره است. مستندات خارجی هر چیزی است که به بیرون ارسال یا منتشر می‌شود، مثل راهنمای کاربر. اما صرف‌نظر از مخاطب یا نقش نویسنده (توسعه‌دهنده یا نویسنده فنی)، همهٔ مستندات آینهٔ کد است. اگر اختلاف باشد، کد مهم است — برای بهتر یا بدتر.

TIP 68

مستندات را بسازید، نه بعداً الحاق کنید

با مستندات داخلی شروع می‌کنیم.

توضیحات در کد

تولید اسناد قالب‌بندی‌شده از توضیحات و اعلان‌های کد منبع نسبتاً ساده است، اما اول باید مطمئن شویم واقعاً توضیح در کد داریم. کد باید توضیح داشته باشد، اما توضیح زیاد هم به اندازهٔ کم بد است.

به‌طور کلی توضیحات باید دربارهٔ «چرا» چیزی انجام شده، هدف و مقصدش صحبت کنند. کد خودش نشان می‌دهد «چگونه» انجام شده، پس توضیح دربارهٔ آن تکراری است — و نقض اصل DRY.

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

دوست داریم توضیح سادهٔ سطح ماژول، توضیح برای داده و اعلان نوع مهم، و سربرگ کوتاه برای هر کلاس و متد ببینیم که نحوهٔ استفاده از تابع و هر کاری که غیربدیهی است را توصیف کند.

نام متغیرها البته باید خوب انتخاب و معنادار باشند. مثلاً foo بی‌معناست، همان‌طور doit یا manager یا stuff. نمادگذاری مجاری (که اطلاعات نوع متغیر را در خود نام رمز می‌کنید) در سیستم‌های شی‌گرا کاملاً نامناسب است. به یاد داشته باشید شما (و دیگران بعد از شما) کد را صدها بار می‌خوانید، اما فقط چند بار می‌نویسید. وقت بگذارید connectionPool بنویسید نه cp.

بدتر از نام‌های بی‌معنا، نام‌های گمراه‌کننده‌اند. آیا کسی توضیح ناسازگاری‌های کد قدیمی مثل «روتینی به نام getData واقعاً داده را روی دیسک می‌نویسد» داده؟ مغز انسان بارها این را خراب می‌کند — اثر استروپ [Str35] نامیده می‌شود. می‌توانید این آزمایش را خودتان انجام دهید. چند قلم رنگی بردارید و نام رنگ‌ها را بنویسید، اما هرگز نام رنگ را با همان رنگ قلم ننویسید. می‌توانید «آبی» را با سبز، «قهوه‌ای» را با قرمز بنویسید و غیره. (یا مجموعهٔ نمونهٔ رنگ‌ها را در وب‌سایت ما در www.pragmaticprogrammer.com ببینید.) وقتی نام رنگ‌ها را کشیدید، سعی کنید هرچه سریع‌تر رنگی که هر کلمه با آن کشیده شده را با صدای بلند بگویید. جایی گیر می‌کنید و شروع به خواندن نام رنگ‌ها به‌جای خود رنگ‌ها می‌کنید. نام‌ها برای مغز شما عمیقاً معنادارند و نام‌های گمراه‌کننده آشوب به کد می‌افزایند.

می‌توانید پارامترها را مستند کنید، اما از خود بپرسید آیا در همهٔ موارد واقعاً لازم است. سطح توضیحی که ابزار JavaDoc پیشنهاد می‌دهد مناسب به نظر می‌رسد:

java
/**
  * Find the peak (highest) value within a specified date
  * range of samples.
  *
  * @param aRange Range of dates to search for data.
  * @param aThreshold Minimum value to consider.
  * @return the value, or <code>null</code> if no value found
  *         greater than or equal to the threshold.
  */
  public Sample findPeak(DateRange aRange, double aThreshold);

فهرست چیزهایی که نباید در توضیحات کد منبع باشند:

  • فهرست توابع صادرشدهٔ کد در فایل. برنامه‌هایی هستند که منبع را برایتان تحلیل می‌کنند. از آن‌ها استفاده کنید و فهرست همیشه به‌روز است.
  • تاریخچهٔ بازبینی. برای این کار سیستم‌های کنترل کد منبع هستند (کنترل کد منبع، صفحهٔ ۸۶). اما مفید است اطلاعات تاریخ آخرین تغییر و شخص تغییردهنده را بگنجانید.⁹
  • فهرست فایل‌های دیگری که این فایل استفاده می‌کند. با ابزارهای خودکار دقیق‌تر تعیین می‌شود.
  • نام فایل. اگر باید در فایل باشد، دستی نگه ندارید. RCS و سیستم‌های مشابه می‌توانند این اطلاعات را خودکار به‌روز نگه دارند. اگر فایل را جابه‌جا یا تغییر نام دهید، نمی‌خواهید یادتان باشد سربرگ را ویرایش کنید.

یکی از مهم‌ترین اطلاعاتی که باید در فایل منبع باشد نام نویسنده است — نه لزوماً آخرین ویرایشگر، بلکه مالک. وصل کردن مسئولیت و پاسخگویی به کد منبع در صداقت مردم معجزه می‌کند (غرور و تعصب، صفحهٔ ۲۵۸).

یادداشت ۹: این نوع اطلاعات، و همچنین نام فایل، با برچسب RCS $Id$ فراهم می‌شود.

پروژه شاید به اعلان‌های حق نسخه‌برداری یا متن حقوقی دیگر در هر فایل منبع نیاز داشته باشد. ویرایشگر را طوری تنظیم کنید که خودکار درج کند.

با توضیحات معنادار، ابزارهایی مثل JavaDoc [URL 7] و DOC++ [URL 21] می‌توانند آن‌ها را استخراج و قالب‌بندی کنند تا خودکار مستندات سطح API تولید شود. این یک نمونهٔ خاص از تکنیک کلی‌تری است که استفاده می‌کنیم — اسناد قابل اجرا.

اسناد قابل اجرا

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

برای اصلاح، باید منبع معتبر اطلاعات را انتخاب کنیم. شاید مشخصات، شاید ابزار طرح پایگاه داده، یا شاید منبع سوم. فرض کنیم سند مشخصات را منبع انتخاب می‌کنیم. حالا مدل این فرایند است. باید راهی برای صادر کردن اطلاعات آن به‌عنوان نماهای مختلف — طرح پایگاه داده و رکورد زبان سطح بالا مثلاً — پیدا کنیم.¹⁰

اگر سند شما به‌صورت متن ساده با دستورات نشانه‌گذاری (HTML، LATEX یا troff مثلاً) ذخیره شده، می‌توانید از ابزارهایی مثل Perl برای استخراج طرح و قالب‌بندی خودکار استفاده کنید. اگر سند در قالب باینری پردازش متن است، جعبهٔ صفحهٔ بعد را برای گزینه‌ها ببینید.

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

یادداشت ۱۰: فقط یک نماست (صفحهٔ ۱۵۷) را برای مدل‌ها و نماها بیشتر ببینید.

اگر سند من متن ساده نیست چه؟

متأسفانه، اسناد پروژهٔ بیشتری با پردازشگرهای متن نوشته می‌شوند که فایل را روی دیسک در قالب اختصاصی ذخیره می‌کنند. «متأسفانه» می‌گوییم چون این گزینه‌های پردازش خودکار سند را شدیداً محدود می‌کند. اما هنوز چند گزینه دارید:

  • ماکرو بنویسید. بیشتر پردازشگرهای پیشرفته زبان ماکرو دارند. با تلاش می‌توانید آن‌ها را طوری برنامه‌دهی کنید که بخش‌های برچسب‌خوردهٔ اسناد را به شکل‌های جایگزین مورد نیاز صادر کنند. اگر برنامه‌نویسی در این سطح دردناک است، همیشه می‌توانید بخش مناسب را به فایل متن سادهٔ استاندارد صادر کنید و سپس با ابزاری مثل Perl به شکل نهایی تبدیل کنید.
  • سند را تابع کنید. به‌جای سند به‌عنوان منبع قطعی، از نمایش دیگری استفاده کنید. (در مثال پایگاه داده شاید طرح را منبع معتبر بدانید.) سپس ابزاری بنویسید که این اطلاعات را به شکلی که سند می‌تواند وارد کند صادر کند. اما مراقب باشید. باید مطمئن شوید این اطلاعات هر بار که سند چاپ می‌شود وارد می‌شود، نه فقط یک‌بار هنگام ایجاد سند.

می‌توانیم مستندات سطح API را از کد منبع با ابزارهایی مثل JavaDoc و DOC++ به‌شکل مشابه تولید کنیم. مدل، کد منبع است: یک نمای مدل می‌تواند کامپایل شود؛ نماهای دیگر برای چاپ یا مشاهدهٔ وب هستند. هدف همیشه کار روی مدل است — چه مدل خود کد باشد یا سند دیگر — و همهٔ نماها خودکار به‌روز شوند (خودکارسازی همه‌جا، صفحهٔ ۲۳۰).

ناگهان مستندسازی آن‌قدرها بد نیست.

نویسندگان فنی

تا اینجا فقط دربارهٔ مستندات داخلی — نوشته‌شده توسط خود برنامه‌نویسان — صحبت کردیم. اما وقتی نویسندگان فنی حرفه‌ای در پروژه هستند چه؟ اغلب برنامه‌نویسان فقط مطالب را «از بالای دیوار» به نویسندگان فنی می‌اندازند و می‌گذارند خودشان راهنمای کاربر، مطالب تبلیغاتی و غیره تولید کنند.

این اشتباه است. فقط به‌خاطر اینکه برنامه‌نویسان این اسناد را نمی‌نویسند نمی‌توانیم اصول عمل‌گرایانه را رها کنیم. می‌خواهیم نویسندگان همان اصول پایهٔ برنامه‌نویس عمل‌گرا را بپذیرند — به‌ویژه اصل DRY، متعامد بودن، مفهوم مدل-نما و استفاده از خودکارسازی و اسکریپت.

چاپ کنید یا بافید

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

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

گاهی باید همان مستندات را در قالب‌های مختلف ارائه دهید: سند چاپی، صفحات وب، راهنمای آنلاین یا شاید اسلاید. راه‌حل معمول زیاد به cut-and-paste تکیه می‌کند و چند سند مستقل جدید از اصل می‌سازد. این ایدهٔ بد است: ارائهٔ سند باید از محتوایش جدا باشد.

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

html
<H1>Chapter Title</H1>

در نسخهٔ گزارش سند فصل جدید تولید کند و در اسلاید عنوان اسلاید جدید. فناوری‌هایی مثل XSL و CSS¹¹ می‌توانند چند قالب خروجی از این یک نشانه‌گذاری تولید کنند.

یادداشت ۱۱: eXtensible Style Language و Cascading Style Sheets، دو فناوری برای جدا کردن ارائه از محتوا.

اگر از پردازشگر متن استفاده می‌کنید، احتمالاً قابلیت‌های مشابه دارید. اگر یادتان باشد از سبک‌ها برای شناسایی عناصر مختلف سند استفاده کنید، با اعمال برگه‌های سبک مختلف ظاهر خروجی نهایی را به‌شدت عوض می‌کنید. بیشتر پردازشگرهای متن حالا اجازه می‌دهند سند را به قالب‌هایی مثل HTML برای انتشار وب تبدیل کنید.

زبان‌های نشانه‌گذاری

در پایان، برای پروژه‌های مستندسازی در مقیاس بزرگ، پیشنهاد می‌کنیم برخی از طرح‌های مدرن‌تر نشانه‌گذاری مستندات را ببینید.

بسیاری از نویسندگان فنی حالا از DocBook برای تعریف اسنادشان استفاده می‌کنند. DocBook استاندارد نشانه‌گذاری مبتنی بر SGML است که هر جزء سند را با دقت شناسایی می‌کند. سند می‌تواند از پردازندهٔ DSSSL عبور کند تا به قالب‌های مختلف رندر شود. پروژهٔ مستندسازی Linux از DocBook برای انتشار اطلاعات به قالب‌های RTF، TEX، info، PostScript و HTML استفاده می‌کند.

تا وقتی نشانه‌گذاری اصلی شما به‌اندازهٔ کافی غنی باشد همهٔ مفاهیم مورد نیاز (از جمله پیوندهای ابرمتنی) را بیان کند، ترجمه به هر شکل قابل انتشار دیگر هم آسان و هم خودکار می‌تواند باشد. می‌توانید راهنمای آنلاین، راهنمای چاپی، برجسته‌های محصول برای وب‌سایت و حتی تقویم نکتهٔ روزانه تولید کنید — همه از یک منبع که البته زیر کنترل کد منبع است و همراه build شبانه ساخته می‌شود (خودکارسازی همه‌جا، صفحهٔ ۲۳۰).

مستندات و کد نماهای مختلف از همان مدل زیربنایی‌اند، اما فقط نما باید متفاوت باشد. نگذارید مستندات شهروند درجهٔ دوم شود و از گردش کار اصلی پروژه تبعید شود. با مستندات همان دقتی را که با کد دارید رفتار کنید و کاربران (و نگهدارندگان بعدی) از شما ستایش می‌کنند.

بخش‌های مرتبط:

  • شرارت‌های تکرار، صفحهٔ ۲۶
  • متعامد بودن، صفحهٔ ۳۴
  • قدرت متن ساده، صفحهٔ ۷۳
  • کنترل کد منبع، صفحهٔ ۸۶
  • فقط یک نماست، صفحهٔ ۱۵۷
  • برنامه‌نویسی تصادفی، صفحهٔ ۱۷۲
  • گودال نیازمندی‌ها، صفحهٔ ۲۰۲
  • خودکارسازی همه‌جا، صفحهٔ ۲۳۰

Challenges

  • آیا برای کد منبعی که تازه نوشتید توضیح نوشتید؟ چرا نه؟ وقت کم؟ مطمئن نیستید کد واقعاً کار می‌کند — فقط ایده را به‌عنوان نمونه اولیه امتحان می‌کنید؟ بعداً دور می‌اندازید، درست؟ بدون توضیح و آزمایشی وارد پروژه نمی‌شود، می‌شود؟
  • گاهی مستندسازی طراحی کد ناراحت‌کننده است چون طراحی در ذهنتان روشن نیست؛ هنوز در حال تکامل است. احساس می‌کنید نباید برای توصیف چیزی که هنوز انجام نداده تلاش تلف کنید. آیا شبیه برنامه‌نویسی تصادفی (صفحهٔ ۱۷۲) به نظر نمی‌رسد؟

۴۵ — انتظارات بزرگ

ای آسمان‌ها از این متحیر شوید و به‌شدت بترسید... — ارمیا ۲:۱۲

شرکتی سود رکورد اعلام می‌کند و قیمت سهامش ۲۰٪ می‌افتد. خبر مالی آن شب توضیح می‌دهد شرکت انتظارات تحلیل‌گران را برآورده نکرد. کودکی هدیهٔ گران کریسمس باز می‌کند و به گریه می‌افتد — عروسکی ارزان که امید داشت نبود. تیم پروژه معجزه می‌کند و برنامهٔ فوق‌العاده پیچیده‌ای پیاده می‌کند، اما کاربران آن را رد می‌کنند چون سیستم راهنما ندارد.

از نظر انتزاعی، برنامه‌ای موفق است که مشخصاتش را درست پیاده کند. متأسفانه این فقط قبض انتزاعی می‌پردازد.

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

TIP 69

به‌آرامی انتظارات کاربران را فراتر ببرید

اما اجرای این نکته کمی کار می‌خواهد.

ارتباط انتظارات

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

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

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

چند تکنیک مهم برای تسهیل این فرایند وجود دارد. از میان آن‌ها گلوله‌های ردیاب (صفحهٔ ۴۸) و نمونه اولیه و یادداشت Post-it (صفحهٔ ۵۳) مهم‌ترین‌اند. هر دو به تیم اجازه می‌دهند چیزی بسازند که کاربر ببیند. هر دو راه ایده‌آلی برای ارتباط درک شما از نیازمندی‌هایشان‌اند. و هر دو به شما و کاربران اجازه می‌دهند ارتباط با هم را تمرین کنید.

یک قدم بیشتر

اگر با کاربران نزدیک کار کنید، انتظاراتشان را به اشتراک بگذارید و بگویید چه می‌کنید، هنگام تحویل پروژه غافلگیری کمی خواهید داشت.

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

کمی بیشتر از آنچه انتظار داشتند به آن‌ها بدهید. تلاش اضافه برای افزودن ویژگی کاربرمحور بارها و بارها خودش را در حسن‌نیت جبران می‌کند.

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

  • راهنمای Balloon یا ToolTip
  • میانبرهای صفحه‌کلید
  • راهنمای مرجع سریع مکمل راهنمای کاربر
  • رنگی‌سازی
  • تحلیل‌گر فایل log
  • نصب خودکار
  • ابزار بررسی یکپارچگی سیستم
  • امکان اجرای چند نسخهٔ سیستم برای آموزش
  • صفحهٔ splash سفارشی‌شده برای سازمانشان

همهٔ این‌ها نسبتاً سطحی‌اند و سیستم را با انبوه ویژگی سنگین نمی‌کنند. اما به کاربران می‌گویند تیم توسعه به تولید سیستم عالی اهمیت داده، سیستمی برای استفادهٔ واقعی. فقط یادتان باشد با افزودن این ویژگی‌های جدید سیستم را نشکستید.

بخش‌های مرتبط:

  • نرم‌افزار به اندازه کافی خوب، صفحهٔ ۹
  • گلوله‌های ردیاب، صفحهٔ ۴۸
  • نمونه اولیه و یادداشت Post-it، صفحهٔ ۵۳
  • گودال نیازمندی‌ها، صفحهٔ ۲۰۲

Challenges

  • گاهی سخت‌گیرترین منتقدان پروژه کسانی‌اند که روی آن کار کرده‌اند. آیا تجربه کرده‌اید از اینکه انتظارات خودتان از چیزی که تولید کردید برآورده نشد؟ چطور ممکن است؟ شاید چیزی بیش از منطق در کار است.
  • کاربران هنگام تحویل نرم‌افزار دربارهٔ چه چیزهایی نظر می‌دهند؟ آیا توجهشان به بخش‌های مختلف برنامه متناسب با تلاشی است که در هر بخش گذاشته‌اید؟ چه چیزهایی خوشحالشان می‌کند؟

۴۶ — غرور و تعصب

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

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

TIP 70

کار خود را امضا کنید

صنعتگران دوران قدیم به امضای کارشان افتخار می‌کردند. شما هم باید بکنید.

تیم‌های پروژه هنوز از افراد ساخته می‌شوند و این قاعده می‌تواند دردسر بیاورد. در برخی پروژه‌ها ایدهٔ مالکیت کد می‌تواند مشکل همکاری ایجاد کند. مردم ممکن است قلمرویی شوند یا نخواهند روی عناصر بنیادی مشترک کار کنند. پروژه شاید مثل مجموعه‌ای از فیفدوم‌های منزوی شود. نسبت به کد خود تعصب پیدا می‌کنید و علیه همکاران.

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

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

اگرچه کد باید مالک داشته باشد، لازم نیست مالکیت فردی باشد. در واقع روش موفق eXtreme Programming کنت بک [URL 45] مالکیت جمعی کد را پیشنهاد می‌کند (اما این به شیوه‌های اضافه مثل برنامه‌نویسی جفتی برای محافظت در برابر خطرات ناشناسی هم نیاز دارد).

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

یک برنامه‌نویس عمل‌گرا.