فصل ۹ - پروژههای عملگرا
با پیشرفت پروژه، باید از مسائل مربوط به فلسفه فردی و کدنویسی فاصله بگیریم و درباره مسائل بزرگتر در سطح پروژه صحبت کنیم. قرار نیست وارد جزئیات مدیریت پروژه شویم، اما درباره چند حوزه حیاتی صحبت خواهیم کرد که میتوانند سرنوشت هر پروژهای را رقم بزنند (یا آن را بسازند یا نابود کنند).
به محض اینکه بیش از یک نفر روی یک پروژه کار کنند، باید قوانین پایهای وضع کنید و بخشهایی از پروژه را بر اساس آن تفویض کنید. در مبحث ۴۹، تیمهای عملگرا، نشان خواهیم داد که چگونه این کار را با رعایت فلسفه عملگرا (Pragmatic) انجام دهید.
هدف از یک متد توسعه نرمافزار، کمک به افراد برای کار کردن با یکدیگر است. آیا شما و تیمتان کاری را انجام میدهید که برایتان خوب کار میکند، یا فقط روی مصنوعات سطحی و پیشپاافتاده سرمایهگذاری میکنید و از مزایای واقعی که شایستهاش هستید بیبهرهاید؟ در مبحث ۵۰، نارگیلها کار را راه نمیاندازند خواهیم دید چرا، و راز واقعی موفقیت را ارائه میدهیم.
و البته اگر نتوانید نرمافزار را به طور مداوم و قابل اعتماد تحویل دهید، هیچکدام از اینها اهمیتی ندارد. این اساسِ مثلث جادوییِ کنترل نسخه، تست و اتوماسیون است: مبحث ۵۱، کیت شروع عملگرا.
با این حال، در نهایت، موفقیت در چشم بیننده است—یعنی حامی (Sponsor) پروژه. آنچه مهم است درک موفقیت است، و در مبحث ۵۲، کاربران خود را خوشحال کنید، به شما نشان خواهیم داد چگونه حامی هر پروژهای را خوشحال کنید.
آخرین نکته در کتاب، پیامد مستقیم تمام موارد دیگر است. در مبحث ۵۳، غرور و تعصب، از شما میخواهیم که پایِ کارِ خود را امضا کنید و به کاری که انجام میدهید افتخار کنید.
مبحث ۴۹: تیمهای عملگرا
«در گروه L، اشتوفل بر شش برنامهنویس درجهیک نظارت میکند، چالشی مدیریتی که تقریباً قابل مقایسه با چوپانیِ گربههاست.»
— مجله واشنگتن پست، ۹ ژوئن ۱۹۸۵
حتی در سال ۱۹۸۵ هم شوخیِ «چوپانی گربهها» (Herding cats) داشت قدیمی میشد. تا زمان چاپ نسخه اول این کتاب در آغاز قرن، این شوخی رسماً باستانی شده بود. با این حال هنوز پابرجاست، چون رنگی از حقیقت در خود دارد.
برنامهنویسان کمی شبیه گربهها هستند: باهوش، بااراده، صاحبنظر، مستقل، و اغلب توسط اینترنت پرستش میشوند.
تا اینجا در این کتاب به تکنیکهای عملگرایی نگاه کردیم که به یک فرد کمک میکند برنامهنویس بهتری باشد. آیا این روشها برای تیمها هم کار میکنند، حتی برای تیمهایی از افراد بااراده و مستقل؟
پاسخ یک «بله»ی قاطع است! عملگرا بودن به عنوان یک فرد مزایایی دارد، اما اگر فرد در یک تیم عملگرا کار کند، این مزایا چندین برابر میشوند. [۷۵]
از نظر ما، یک تیم، موجودیتی کوچک و عمدتاً پایدار است. پنجاه نفر یک تیم نیستند، یک «لشکر» (Horde) هستند. تیمهایی که اعضایش دائماً به مأموریتهای دیگر کشیده میشوند و هیچکس دیگری را نمیشناسد هم تیم نیستند، آنها صرفاً غریبههایی هستند که موقتاً زیر باران در یک ایستگاه اتوبوس ایستادهاند.
یک تیم عملگرا کوچک است، زیر ۱۰-۱۲ عضو یا در همین حدود. اعضا به ندرت میآیند و میروند. همه همدیگر را خوب میشناسند، به هم اعتماد دارند و به هم وابستهاند.
نکته ۸۴: تیمهای کوچک و پایدار را حفظ کنید
در این بخش به طور مختصر نگاه میکنیم که چگونه تکنیکهای عملگرا میتوانند برای تیمها به عنوان یک کل به کار روند. این یادداشتها فقط یک شروع هستند. وقتی گروهی از توسعهدهندگان عملگرا داشته باشید که در محیطی توانمندساز کار میکنند، آنها به سرعت پویاییهای تیمیِ مخصوص به خودشان را که برایشان کار میکند، توسعه داده و اصلاح میکنند.
بیایید برخی از بخشهای قبلی را در قالب تیمها بازتعریف کنیم.
پنجرههای شکسته ممنوع
کیفیت یک مسئله تیمی است. کوشاترین توسعهدهنده هم اگر در تیمی قرار گیرد که اهمیت نمیدهد، حفظ اشتیاق لازم برای اصلاح مشکلات ریز را دشوار خواهد یافت. مشکل زمانی بدتر میشود که تیم فعالانه توسعهدهنده را از صرف زمان برای این اصلاحات دلسرد کند.
تیمها به عنوان یک کل نباید پنجرههای شکسته را تحمل کنند—آن نواقص کوچکی که هیچکس درستشان نمیکند. تیم باید مسئولیت کیفیت محصول را بر عهده بگیرد، از توسعهدهندگانی که فلسفه «پنجرههای شکسته ممنوع» (که در مبحث ۳، آنتروپی نرمافزار توصیف کردیم) را درک میکنند حمایت کند، و کسانی را که هنوز آن را کشف نکردهاند تشویق نماید.
برخی متدولوژیهای تیمی یک «مسئول کیفیت» دارند—کسی که تیم مسئولیت کیفیت خروجی را به او تفویض میکند. این به وضوح مضحک است: کیفیت تنها میتواند از مشارکتهای فردیِ تمام اعضای تیم حاصل شود. کیفیت باید در ساختار تعبیه شود (Built-in)، نه اینکه بعداً به آن پیچ شود (Bolted on).
قورباغههای آبپز
آن قورباغه افسانهای در دیگ آب را از مبحث ۴، سوپ سنگ و قورباغههای آبپز به یاد دارید؟ متوجه تغییر تدریجی محیطش نمیشود و در نهایت پخته میشود. همین اتفاق میتواند برای افرادی بیفتد که هوشیار نیستند.
چشمداشتن به محیط کلی در بحبوحه توسعه پروژه میتواند دشوار باشد. برای تیمها به عنوان یک کل، آبپز شدن حتی آسانتر است. افراد فرض میکنند که کس دیگری دارد به موضوع رسیدگی میکند، یا اینکه رهبر تیم حتماً با تغییری که کاربر درخواست کرده موافقت کرده است. حتی خوشنیتترین تیمها هم میتوانند از تغییرات مهم در پروژههایشان غافل بمانند.
با این بجنگید. همه را تشویق کنید که فعالانه محیط را برای تغییرات رصد کنند. بیدار و آگاه بمانید نسبت به افزایش دامنه، کاهش زمانبندیها، ویژگیهای اضافی، محیطهای جدید—هر چیزی که در توافق اولیه نبود. معیارهایی (Metrics) برای نیازمندیهای جدید نگه دارید. تیم لزومی ندارد تغییرات را فوراً رد کند—فقط باید آگاه باشید که آنها دارند اتفاق میافتند. وگرنه این شما خواهید بود که توی آب جوش میافتید. [۷۶]
پورتفولیوی دانش خود را زمانبندی کنید
در مبحث ۶، پورتفولیوی دانش شما، به راههایی نگاه کردیم که باید در زمان شخصی خودتان روی پورتفولیوی دانشتان سرمایهگذاری کنید. تیمهایی که میخواهند موفق شوند نیز باید سرمایهگذاریهای دانش و مهارت خود را در نظر بگیرند.
اگر تیم شما در مورد بهبود و نوآوری جدی است، باید آن را زمانبندی کنید. تلاش برای انجام کارها «هر وقت که وقت آزاد بود» به این معنی است که آنها هرگز اتفاق نخواهند افتاد. با هر نوع بکلاگ (Backlog) یا لیست وظایف یا جریانی که کار میکنید، آن را فقط برای توسعه ویژگیها رزرو نکنید. تیم روی چیزهایی فراتر از فقط ویژگیهای جدید کار میکند. برخی مثالهای ممکن عبارتند از:
- نگهداری سیستمهای قدیمی: با اینکه ما عاشق کار روی سیستم جدید و براق هستیم، احتمالاً کارهای نگهداری وجود دارد که باید روی سیستم قدیمی انجام شود. ما تیمهایی را دیدهایم که سعی میکنند این کار را به گوشهای هل دهند. اگر تیم موظف به انجام این وظایف است، پس آنها را انجام دهید—واقعی و جدی.
- بازتاب و اصلاح فرآیند: بهبود مستمر تنها زمانی اتفاق میافتد که وقت بگذارید به اطراف نگاه کنید، بفهمید چه چیزی کار میکند و چه چیزی نه، و سپس تغییرات ایجاد کنید (مبحث ۴۸، جوهره چابکی را ببینید). خیلی از تیمها آنقدر مشغول خالی کردن آب قایق هستند که وقت ندارند نشتی را بگیرند. زمانبندیاش کنید. درستش کنید.
- آزمایشهای تکنولوژی جدید: تکنولوژی، فریمورک یا کتابخانههای جدید را فقط به خاطر اینکه «همه دارند استفاده میکنند» یا بر اساس چیزی که در کنفرانس دیدید یا آنلاین خواندید، اتخاذ نکنید. عامدانه تکنولوژیهای کاندیدا را با پروتوتایپها بررسی (Vet) کنید. وظایفی را در برنامه بگذارید تا چیزهای جدید را امتحان کرده و نتایج را تحلیل کنید.
- یادگیری و بهبود مهارتها: یادگیری و بهبودهای شخصی شروع خوبی هستند، اما بسیاری از مهارتها وقتی در سطح تیم پخش شوند مؤثرترند. برنامه بریزید که انجامش دهید، چه ناهار غیررسمیِ «کیسه قهوهای» (Brown-bag lunch - جلسات غیررسمی حین ناهار) باشد یا جلسات آموزشی رسمیتر.
نکته ۸۵: زمانبندیاش کنید تا اتفاق بیفتد
حضور تیم را مخابره کنید (Communicate Team Presence)
بدیهی است که توسعهدهندگان در یک تیم باید با هم حرف بزنند. ما پیشنهاداتی برای تسهیل این امر در مبحث ۷، ارتباط برقرار کنید! دادیم. با این حال، فراموش کردن اینکه خودِ تیم هم حضوری در سازمان دارد، آسان است. تیم به عنوان یک موجودیت باید با بقیه دنیا به وضوح ارتباط برقرار کند.
برای افراد بیرونی، بدترین تیمهای پروژه آنهایی هستند که عبوس و تودار به نظر میرسند. آنها جلساتی بدون ساختار برگزار میکنند که در آن هیچکس نمیخواهد حرف بزند. ایمیلها و اسناد پروژهشان یک افتضاح است: هیچ دو سندی شبیه هم نیستند و هر کدام از اصطلاحات متفاوتی استفاده میکنند.
تیمهای پروژه عالی، شخصیتی متمایز دارند. مردم مشتاق جلسات با آنها هستند، چون میدانند که شاهد یک اجرای خوبآمادهشده خواهند بود که حس خوبی به همه میدهد. مستنداتی که تولید میکنند شفاف، دقیق و منسجم است. تیم با یک صدا صحبت میکند. آنها حتی ممکن است حس شوخطبعی داشته باشند. [۷۷]
یک ترفند بازاریابی ساده وجود دارد که به تیمها کمک میکند یکپارچه ارتباط برقرار کنند: یک برند بسازید.
وقتی پروژهای را شروع میکنید، اسمی برایش پیدا کنید، ترجیحاً چیزی عجیبوغریب. (در گذشته، ما پروژهها را به نام چیزهایی مثل طوطیهای قاتلی که گوسفند شکار میکنند، خطاهای دید، موشهای صحرایی، شخصیتهای کارتونی و شهرهای افسانهای نامگذاری کردهایم.) ۳۰ دقیقه وقت بگذارید و یک لوگوی بامزه و عجیب طراحی کنید و از آن استفاده کنید. هنگام صحبت با مردم، از نام تیمتان سخاوتمندانه استفاده کنید. احمقانه به نظر میرسد، اما به تیم شما هویتی میدهد تا روی آن بسازد، و به دنیا چیزی به یاد ماندنی میدهد تا با کار شما مرتبط بداند.
خودتان را تکرار نکنید (Don’t Repeat Yourselves)
در مبحث ۹، اصل DRY—بدیهای تکرار، درباره دشواریهای حذف کار تکراری بین اعضای یک تیم صحبت کردیم. این دوبارهکاری منجر به هدر رفتن تلاش میشود و میتواند منجر به کابوس نگهداری گردد. سیستمهای «دودکشی» یا «سیلویی» در این تیمها رایج هستند، با اشتراکگذاری کم و حجم زیادی از عملکردهای تکراری.
ارتباط خوب، کلید اجتناب از این مشکلات است. و منظور ما از «خوب»، ارتباط فوری و بدون اصطکاک است. شما باید بتوانید سوالی از اعضای تیم بپرسید و جوابی کموبیش فوری بگیرید. اگر تیم در یک مکان مستقر است (Co-located)، این میتواند به سادگیِ سرک کشیدن از بالای دیوار پارتیشن یا صدا زدن در راهرو باشد. برای تیمهای دورکار، ممکن است مجبور باشید به اپلیکیشن پیامرسان یا سایر ابزارهای الکترونیکی تکیه کنید.
اگر مجبور باشید یک هفته صبر کنید تا جلسه تیم برگزار شود تا سوالتان را بپرسید یا وضعیتتان را به اشتراک بگذارید، این اصطکاکِ وحشتناک زیادی است. «بدون اصطکاک» یعنی پرسیدن سوال، اشتراکگذاری پیشرفت، مشکلات، بینشها و آموختهها، و باخبر ماندن از اینکه همتیمیهایتان چه میکنند، آسان و کمتشریفات باشد. آگاهی را حفظ کنید تا DRY بمانید.
گلولههای رسامِ تیمی (Team Tracer Bullets)
یک تیم پروژه باید وظایف بسیار متفاوتی را در حوزههای مختلف پروژه به انجام برساند و با تکنولوژیهای متفاوتِ زیادی سروکار داشته باشد. درک نیازمندیها، طراحی [۷۸] معماری، کدنویسی برای فرانتاند و سرور، تست کردن، همه باید اتفاق بیفتند.
اما این یک تصور غلط رایج است که این فعالیتها و وظایف میتوانند جداگانه و در انزوا اتفاق بیفتند. نمیتوانند. برخی متدولوژیها طرفدار انواع و اقسام نقشها و عناوین مختلف در تیم هستند، یا تیمهای تخصصی کاملاً جداگانه ایجاد میکنند. اما مشکل آن رویکرد این است که دروازهها (Gates) و دستبهدستکردنها (Handoffs) را معرفی میکند. حالا به جای جریانی روان از تیم به استقرار، دروازههای مصنوعی دارید که کار در آنجا متوقف میشود. دستبهدستکردنهایی که باید منتظر پذیرش بمانند. تأییدیهها. کاغذبازی. اهالی «لین» (Lean) به این میگویند اتلاف (Waste) و تلاش میکنند فعالانه حذفش کنند.
تمام این نقشها و فعالیتهای متفاوت در واقع نماهای متفاوتی از یک مسئله واحد هستند، و جدا کردن مصنوعی آنها میتواند کوهی از مشکلات ایجاد کند. برای مثال، برنامهنویسانی که دو یا سه سطح از کاربران واقعیِ کدشان دور هستند، بعید است از زمینهای (Context) که کارشان در آن استفاده میشود آگاه باشند. آنها قادر به گرفتن تصمیمات آگاهانه نخواهند بود.
با مبحث ۱۲، گلولههای رسام، ما توصیه میکنیم ویژگیهای فردی (هرچند در ابتدا کوچک و محدود) را توسعه دهید که سرتاسرِ (End-to-end) کل سیستم را طی میکنند. این یعنی شما به تمام مهارتهای لازم برای انجام آن درون تیم نیاز دارید: فرانتاند، UI/UX، سرور، DBA، QA و غیره، که همه با هم راحت باشند و به کار با یکدیگر عادت داشته باشند.
با رویکرد گلوله رسام، میتوانید تکههای بسیار کوچکی از عملکرد را خیلی سریع پیادهسازی کنید و بازخورد فوری بگیرید که تیمتان چقدر خوب ارتباط برقرار میکند و تحویل میدهد. این محیطی ایجاد میکند که میتوانید تغییرات ایجاد کنید و تیم و فرآیندتان را به سرعت و آسانی تنظیم (Tune) کنید.
نکته ۸۶: تیمهای با عملکرد کامل (Fully Functional) سازماندهی کنید
تیمها را طوری بسازید که بتوانید کد را به صورت سرتاسری (End-to-end)، تدریجی و تکرارپذیر بسازید.
اتوماسیون
یک راه عالی برای تضمین همزمانِ یکپارچگی و دقت، خودکار کردن هر کاری است که تیم انجام میدهد. چرا وقتی ادیتور یا IDE شما میتواند فرمتدهی کد را به طور خودکار انجام دهد، با استانداردهای فرمت کد کلنجار بروید؟ چرا وقتی بیلدِ مداوم (Continuous Build) میتواند تستها را خودکار اجرا کند، تست دستی انجام دهید؟ چرا دستی دیپلوی کنید وقتی اتوماسیون میتواند همان کار را هر بار، تکرارپذیر و قابل اعتماد انجام دهد؟
اتوماسیون جزء ضروری هر تیم پروژه است. مطمئن شوید که تیم مهارت ابزارسازی دارد تا ابزارهایی بسازد و مستقر کند که توسعه پروژه و استقرارِ پروداکشن را خودکار میکنند.
بدانید کی افزودن رنگ را متوقف کنید
به یاد داشته باشید که تیمها از افراد تشکیل شدهاند. به هر عضو توانایی درخشیدن به روش خودش را بدهید. فقط به اندازه کافی ساختار به آنها بدهید که از آنها پشتیبانی کند و تضمین کند که پروژه ارزش تحویل میدهد. سپس، مثل نقاش در مبحث ۵، نرمافزار به اندازه کافی خوب، در برابر وسوسه افزودن رنگ بیشتر مقاومت کنید.
بخشهای مرتبط شامل:
- مبحث ۲: گربه سورسکد مرا خورد
- مبحث ۷: ارتباط برقرار کنید!
- مبحث ۱۲: گلولههای رسام
- مبحث ۱۹: کنترل نسخه
- مبحث ۵۰: نارگیلها کار را راه نمیاندازند
- مبحث ۵۱: کیت شروع عملگرا
چالشها
- به دنبال تیمهای موفق در خارج از حوزه توسعه نرمافزار بگردید. چه چیزی آنها را موفق میکند؟ آیا از هیچکدام از فرآیندهای بحث شده در این بخش استفاده میکنند؟
- دفعه بعد که پروژهای را شروع میکنید، سعی کنید افراد را متقاعد کنید که برایش برند بسازند. به سازمانتان زمان بدهید تا به ایده عادت کند، و سپس یک ممیزی سریع انجام دهید تا ببینید چه تفاوتی ایجاد کرده است، هم در درون تیم و هم در خارج.
- احتمالاً زمانی به شما مسائلی مثل این داده شده: «اگر ۴ کارگر در ۶ ساعت یک گودال بکنند، ۸ کارگر در چقدر زمان آن را میکنند؟» اما در زندگی واقعی، اگر کارگران به جای آن کد مینوشتند، چه عواملی روی پاسخ تأثیر میگذاشت؟ در چند سناریو زمان واقعاً کاهش مییابد؟
- کتاب نفر-ماه افسانهای (The Mythical Man Month) [Bro96] اثر فردریک بروکس را بخوانید. برای امتیاز اضافه، دو نسخه بخرید تا بتوانید دو برابر سریعتر بخوانیدش. (شوخی با قانون بروکس!)
مبحث ۵۰: نارگیلها کار را راه نمیاندازند
بومیان جزیره هرگز پیش از آن هواپیما ندیده بودند، یا با مردمانی مثل این غریبهها ملاقات نکرده بودند. غریبهها در ازای استفاده از زمینهای آنها، پرندگان مکانیکی را فراهم کردند که تمام طول روز در یک «باند فرود» پرواز میکردند و میآمدند و میرفتند و ثروت مادی باورنکردنی را به خانه جزیرهای آنها میآوردند. غریبهها چیزهایی درباره جنگ و نبرد میگفتند.
یک روز جنگ تمام شد و همه آنها رفتند و ثروتهای عجیبشان را هم با خود بردند.
جزیرهنشینان که ناامیدانه میخواستند بخت و اقبال خوبشان را بازگردانند، یک ماکت (Facsimile) از فرودگاه، برج مراقبت و تجهیزات را با استفاده از مواد محلی بازسازی کردند: ساقههای مو، پوست نارگیل، برگ نخل و امثال آن. اما به دلیلی، با اینکه همه چیز سر جای خود بود، هواپیماها نیامدند.
آنها فرم را تقلید کرده بودند، اما محتوا را نه. انسانشناسان به این پدیده «فرقه بارپرست» (Cargo Cult) میگویند.
خیلی وقتها، ما همان جزیرهنشینان هستیم. افتادن در دام فرقه بارپرست آسان و وسوسهکننده است: با سرمایهگذاری و ساختن مصنوعاتِ به آسانی قابلمشاهده، امیدوارید که آن جادویِ زیربنایی و کارآمد را جذب کنید. اما همانطور که در مورد فرقههای بارپرست اصلی در ملانزی صادق بود، یک فرودگاه تقلبی ساخته شده از پوست نارگیل، جایگزین چیز واقعی نیست. [۷۹]
برای مثال، ما شخصاً تیمهایی را دیدهایم که ادعا میکنند از «اسکرام» (Scrum) استفاده میکنند. اما با بررسی دقیقتر، معلوم شد که آنها جلسه ایستاده (Stand up) روزانه را هفتهای یک بار انجام میدادند، با تکرارهای (Iterations) چهار هفتهای که اغلب به تکرارهای شش یا هشت هفتهای تبدیل میشد. آنها حس میکردند که این اشکالی ندارد چون داشتند از یک ابزار زمانبندی محبوبِ «چابک» استفاده میکردند.
آنها فقط روی مصنوعات سطحی سرمایهگذاری کرده بودند—و تازه آن هم اغلب فقط در حد اسم، انگار که «استند آپ» یا «ایتریشن» نوعی وِرد و طلسم برای خرافاتیها بود. جای تعجب نیست که آنها هم در جذب جادوی واقعی ناکام ماندند.
زمینه (Context) مهم است
آیا شما یا تیمتان در این دام افتادهاید؟ از خودتان بپرسید، اصلاً چرا دارید از آن متد توسعه خاص استفاده میکنید؟ یا آن فریمورک؟ یا آن تکنیک تست کردن؟ آیا واقعاً برای کارِ در دستِ انجام مناسب است؟ آیا برای شما خوب کار میکند؟ یا صرفاً به این خاطر اتخاذ شده که توسط آخرین داستان موفقیتِ اینترنتی استفاده میشده است؟
یک روند فعلی وجود دارد که سیاستها و فرآیندهای شرکتهای موفقی مثل اسپاتیفای، نتفلیکس، استرایپ، گیتلب و دیگران را اتخاذ کنند. هر کدام برداشت منحصر به فرد خود را از توسعه و مدیریت نرمافزار دارند.
اما زمینه را در نظر بگیرید: آیا شما در همان بازار هستید، با همان محدودیتها و فرصتها، تخصص و اندازه سازمان مشابه، مدیریت مشابه و فرهنگ مشابه؟ پایگاه کاربر و نیازمندیهای مشابه؟ گول نخورید. مصنوعات خاص، ساختارهای سطحی، سیاستها، فرآیندها و متدها کافی نیستند.
نکته ۸۷: کاری را بکنید که جواب میدهد، نه کاری که مُد شده است
از کجا میفهمید «چه چیزی جواب میدهد»؟ به بنیادیترینِ تکنیکهای عملگرا تکیه کنید: امتحانش کنید.
ایده را با یک تیم کوچک یا مجموعهای از تیمها «پایلوت» (Pilot) کنید. تکههای خوبی را که به نظر خوب کار میکنند نگه دارید و هر چیز دیگری را به عنوان اتلاف یا سربار دور بریزید. هیچکس سازمان شما را تنزل رتبه نمیدهد چون متفاوت از اسپاتیفای یا نتفلیکس عمل میکند، زیرا حتی خود آنها هم زمانی که در حال رشد بودند از فرآیندهای فعلیشان پیروی نمیکردند. و سالها بعد، وقتی آن شرکتها بالغ شوند و تغییر جهت دهند (Pivot) و به رشد ادامه دهند، باز هم کار متفاوتی انجام خواهند داد. راز واقعی موفقیت آنها همین است.
یک سایز به تن هیچکس درست نمینشیند
هدف از یک متدولوژی توسعه نرمافزار، کمک به افراد برای کار کردن با یکدیگر است. همانطور که در مبحث ۴۸، جوهره چابکی بحث کردیم، هیچ برنامه واحدی وجود ندارد که بتوانید هنگام توسعه نرمافزار از آن پیروی کنید، مخصوصاً برنامهای که کس دیگری در شرکت دیگری به آن رسیده است.
بسیاری از برنامههای گواهینامه (Certification) در واقع حتی بدتر از آن هستند: آنها بر این اساس بنا شدهاند که دانشجو بتواند قوانین را حفظ کند و از آنها پیروی نماید. اما این چیزی نیست که شما میخواهید. شما به توانایی دیدنِ فراتر از قوانین موجود و بهرهبرداری از امکانات برای کسب مزیت نیاز دارید. این ذهنیت بسیار متفاوتی است نسبت به اینکه بگویید «اما اسکرام/لین/کانبان/XP/چابک این کار را اینطوری انجام میدهد...» و غیره.
در عوض، شما میخواهید بهترین قطعات را از هر متدولوژی خاص بردارید و آنها را برای استفاده تطبیق دهید. هیچ سایزی مناسب همه نیست، و متدهای فعلی فاصله زیادی با کامل بودن دارند، بنابراین نیاز خواهید داشت که به بیش از تنها یک متد محبوب نگاه کنید.
برای مثال، اسکرام برخی شیوههای مدیریت پروژه را تعریف میکند، اما اسکرام به تنهایی راهنمایی کافی در سطح فنی برای تیمها یا در سطح پورتفولیو/حاکمیت (Governance) برای رهبری ارائه نمیدهد. پس از کجا شروع میکنید؟
مثل آنها باشید!
ما مکرراً میشنویم که رهبران توسعه نرمافزار به کارکنانشان میگویند: «ما باید مثل نتفلیکس عمل کنیم» (یا یکی دیگر از این شرکتهای پیشرو). البته که میتوانید این کار را بکنید.
اول، بروید چند صد هزار سرور و دهها میلیون کاربر برای خودتان جور کنید...
هدف واقعی
هدف البته «انجام دادن اسکرام»، «انجام دادن چابک»، «انجام دادن لین» یا هر چیز دیگر نیست. هدف این است که در موقعیتی باشید که نرمافزارِ کارآمدی را تحویل دهید که قابلیت جدیدی را در لحظه به کاربران میدهد. نه هفتهها، ماهها یا سالها بعد، بلکه همین الان.
برای بسیاری از تیمها و سازمانها، «تحویل مداوم» (Continuous Delivery) هدفی بلندپروازانه و دستنیافتنی به نظر میرسد، بهویژه اگر گرفتار فرآیندی باشید که تحویل را به ماهها یا حتی هفتهها محدود میکند. اما مانند هر هدفی، کلید کار این است که نشانه را در جهت درست نگه دارید.
(تصویر delivery_times.png در اینجا اشاره به نمودار کاهش زمان تحویل دارد)
اگر تحویل شما سالها طول میکشد، سعی کنید چرخه را به ماهها کوتاه کنید. از ماهها، آن را به هفتهها برسانید. از یک اسپرینت چهار هفتهای، دو هفته را امتحان کنید. از یک اسپرینت دو هفتهای، یک هفته را. سپس روزانه. سپس، در نهایت، بر اساس تقاضا (On demand).
توجه داشته باشید که توانایی تحویل بر اساس تقاضا به این معنی نیست که مجبورید هر دقیقه از هر روز تحویل انجام دهید. شما زمانی تحویل میدهید که کاربران نیاز دارند، و زمانی که از نظر تجاری منطقی است.
نکته ۸۸: وقتی تحویل دهید که کاربران نیاز دارند
برای حرکت به سمت این سبک از توسعه مداوم، به یک زیرساخت قرص و محکم نیاز دارید، که در مبحث بعدی، مبحث ۵۱، کیت شروع عملگرا دربارهاش بحث میکنیم. شما توسعه را در شاخه اصلی (Main trunk) سیستم کنترل نسخه خود انجام میدهید، نه در برنچها، و از تکنیکهایی مثل «سوئیچهای ویژگی» (Feature switches) استفاده میکنید تا ویژگیهای آزمایشی را به صورت گزینشی برای کاربران عرضه کنید.
وقتی زیرساخت شما مرتب شد، باید تصمیم بگیرید چگونه کار را سازماندهی کنید. مبتدیان ممکن است بخواهند با اسکرام برای مدیریت پروژه، به علاوه شیوههای فنی از «برنامهنویسی مفرط» (XP) شروع کنند. تیمهای منظمتر و باتجربهتر ممکن است به تکنیکهای کانبان (Kanban) و لین (Lean) نگاه کنند، هم برای تیم و هم شاید برای مسائل بزرگترِ حاکمیتی.
اما حرف ما را کورکورانه نپذیرید، خودتان تحقیق کنید و این رویکردها را امتحان کنید. البته مراقب باشید که زیادهروی نکنید. سرمایهگذاری بیش از حد روی هر متدولوژی خاص میتواند شما را نسبت به جایگزینها کور کند. به آن عادت میکنید. خیلی زود دیدنِ هر راه دیگری سخت میشود. شما فسیل (Calcified) شدهاید و حالا دیگر نمیتوانید به سرعت تطبیق پیدا کنید.
در این حالت، انگار که دارید از نارگیل استفاده میکنید.
بخشهای مرتبط شامل:
- مبحث ۱۲: گلولههای رسام
- مبحث ۲۷: از چراغهای جلوی خود جلو نزنید
- مبحث ۴۸: جوهره چابکی
- مبحث ۴۹: تیمهای عملگرا
- مبحث ۵۱: کیت شروع عملگرا
مبحث ۵۱: کیت شروع عملگرا
«تمدن با افزایش تعداد عملیات مهمی که میتوانیم بدون فکر کردن انجام دهیم، پیشرفت میکند.»
— آلفرد نورث وایتهد
آن قدیمها که ماشینها تازه آمده بودند، دستورالعملهای روشن کردن یک فورد مدل T بیش از دو صفحه بود. با ماشینهای مدرن، فقط یک دکمه را فشار میدهید—فرآیند روشن کردن خودکار و ضدخطا (Foolproof) است. کسی که از روی لیستی از دستورالعملها پیروی میکند ممکن است موتور را خفه کند (Flood)، اما استارتر خودکار این کار را نمیکند.
اگرچه توسعه نرمافزار هنوز صنعتی در مرحله «مدل T» است، اما ما نمیتوانیم از پس هزینه تکرارِ بارها و بارهای دو صفحه دستورالعمل برای عملیاتهای رایج بربیاییم. چه فرآیند بیلد و انتشار (Release) باشد، چه تست، کاغذبازیهای پروژه، یا هر وظیفه تکراری دیگر در پروژه، باید روی هر ماشین توانمندی خودکار و تکرارپذیر باشد.
علاوه بر این، ما میخواهیم ثبات (Consistency) و تکرارپذیری را در پروژه تضمین کنیم. رویههای دستی، ثبات را به شانس واگذار میکنند؛ تکرارپذیری تضمینشده نیست، بهویژه اگر جنبههایی از رویه برای افراد مختلف قابل تفسیر متفاوت باشد.
بعد از اینکه ما اولین نسخه برنامهنویس عملگرا را نوشتیم، میخواستیم کتابهای بیشتری بنویسیم تا به تیمها در توسعه نرمافزار کمک کنیم. به این نتیجه رسیدیم که باید از همان ابتدا شروع کنیم: اساسیترین و مهمترین عناصری که هر تیمی، صرفنظر از متدولوژی، زبان یا پشته تکنولوژی، به آن نیاز دارد چیست.
و بدین ترتیب ایده «کیت شروع عملگرا» متولد شد که این سه موضوع حیاتی و مرتبط به هم را پوشش میدهد:
- کنترل نسخه (Version Control)
- تست رگرسیون (Regression Testing)
- اتوماسیون کامل (Full Automation)
اینها سه پایهای هستند که هر پروژهای را نگه میدارند. بیایید ببینیم چطور.
با کنترل نسخه برانید
همانطور که در مبحث ۱۹، کنترل نسخه گفتیم، شما میخواهید همه چیزِ مورد نیاز برای ساخت پروژهتان را تحت کنترل نسخه نگه دارید. این ایده در زمینه خود پروژه حتی مهمتر میشود. [۸۰]
اول، به ماشینهای بیلد (Build machines) اجازه میدهد «موقت» (Ephemeral) باشند. به جای یک ماشین مقدس و قراضه در گوشه دفتر که همه میترسند لمسش کنند، ماشینها و/یا کلاسترهای بیلد در صورت تقاضا (On demand) به عنوان نمونههای لحظهای (Spot instances) در ابر ایجاد میشوند. پیکربندی استقرار (Deployment configuration) نیز تحت کنترل نسخه است، بنابراین انتشار به پروداکشن میتواند به صورت خودکار مدیریت شود.
و این بخش مهم ماجراست: در سطح پروژه، کنترل نسخه فرآیند بیلد و انتشار را میراند.
نکته ۸۹: از کنترل نسخه برای راندن بیلدها، تستها و انتشارها استفاده کنید
یعنی بیلد، تست و استقرار از طریق کامیتها یا پوشها به کنترل نسخه تریگر (Trigger) میشوند، و در یک کانتینر در ابر ساخته میشوند. انتشار به محیط استیجینگ (Staging) یا پروداکشن با استفاده از یک تگ در سیستم کنترل نسخه مشخص میشود. بدین ترتیب انتشارها به بخشی بسیار کمتشریفاتتر از زندگی روزمره تبدیل میشوند—«تحویل مداوم» (Continuous Delivery) واقعی، که به ماشین بیلد خاص یا ماشین هیچ توسعهدهندهای وابسته نیست.
تست بیرحمانه و مداوم
بسیاری از توسعهدهندگان به آرامی تست میکنند؛ ناخودآگاه میدانند که کد کجا خواهد شکست و از نقاط ضعف دوری میکنند. برنامهنویسان عملگرا متفاوتاند. ما انگیزه داریم باگهایمان را همین حالا پیدا کنیم تا مجبور نباشیم بعداً شرمساریِ پیدا شدن باگهایمان توسط دیگران را تحمل کنیم.
پیدا کردن باگها تا حدودی شبیه ماهیگیری با تور است. ما از تورهای ریز و کوچک (یونیت تستها) برای گرفتن ماهیهای ریز (Minnows) استفاده میکنیم، و از تورهای بزرگ و درشت (تستهای یکپارچهسازی) برای گرفتن کوسههای قاتل. گاهی ماهیها موفق به فرار میشوند، بنابراین هر سوراخی را که پیدا کنیم وصله میکنیم، به امید گرفتن نقصهای بیشتر و لیزتری که در استخر پروژهمان شنا میکنند.
نکته ۹۰: زود تست کنید، زیاد تست کنید، خودکار تست کنید
ما میخواهیم به محض اینکه کد داریم، تست کردن را شروع کنیم. آن ماهیهای ریز عادت بدی دارند که خیلی سریع تبدیل به کوسههای غولپیکر و آدمخوار شوند، و گرفتن کوسه خیلی سختتر است. بنابراین ما یونیت تست مینویسیم. خیلی زیاد.
در واقع، یک پروژه خوب ممکن است کد تست بیشتری نسبت به کد پروداکشن داشته باشد. زمانی که صرف تولید این کد تست میشود ارزش تلاشش را دارد. در درازمدت بسیار ارزانتر تمام میشود، و شما واقعاً شانسی خواهید داشت که محصولی با نقص نزدیک به صفر تولید کنید. علاوه بر این، دانستن اینکه تست را پاس کردهاید، به شما درجه بالایی از اطمینان میدهد که یک قطعه کد «تمام شده» است.
نکته ۹۱: کدنویسی تمام نشده مگر اینکه تمام تستها اجرا شوند
بیلدِ خودکار تمام تستهای موجود را اجرا میکند. مهم است که هدفمان «تست برای واقعیت» باشد؛ به عبارت دیگر، محیط تست باید تا حد امکان با محیط پروداکشن منطبق باشد. هر شکافی (Gap)، جایی است که باگها تخمگذاری میکنند.
بیلد ممکن است چندین نوع اصلی از تست نرمافزار را پوشش دهد: تست واحد (Unit)؛ تست یکپارچهسازی (Integration)؛ اعتبارسنجی و تایید (Validation and Verification)؛ و تست عملکرد (Performance). این لیست به هیچ وجه کامل نیست و برخی پروژههای خاص به انواع دیگری از تست نیز نیاز خواهند داشت. اما نقطه شروع خوبی به ما میدهد.
تست واحد (Unit Testing)
تست واحد کدی است که یک ماژول را تمرین میدهد. ما این را در مبحث ۴۱، تست برای کد پوشش دادیم. تست واحد پایه و اساس تمام اشکال دیگر تست است که در این بخش بحث خواهیم کرد. اگر قطعات به تنهایی کار نکنند، احتمالاً با هم نیز خوب کار نخواهند کرد. تمام ماژولهایی که استفاده میکنید باید قبل از اینکه بتوانید پیش بروید، تستهای واحد خودشان را پاس کنند. وقتی تمام ماژولهای مربوطه تستهای فردی خود را پاس کردند، آماده مرحله بعدی هستید. باید تست کنید که تمام ماژولها چگونه در سراسر سیستم از هم استفاده کرده و با هم تعامل میکنند.
تست یکپارچهسازی (Integration Testing)
تست یکپارچهسازی نشان میدهد که زیرسیستمهای اصلیِ تشکیلدهنده پروژه با هم کار میکنند و تعامل خوبی دارند. با وجود قراردادهای (Contracts) خوب و بهخوبی تستشده، هرگونه مشکل یکپارچهسازی به راحتی قابل تشخیص است. در غیر این صورت، یکپارچهسازی به زمینی حاصلخیز برای پرورش باگها تبدیل میشود. در واقع، اغلب این تنها منبع بزرگ باگها در سیستم است. تست یکپارچهسازی واقعاً فقط گسترشِ تست واحدی است که توصیف کردیم—شما فقط دارید تست میکنید که چگونه کل زیرسیستمها به قراردادهایشان احترام میگذارند.
اعتبارسنجی و تایید (Validation and Verification)
به محض اینکه یک رابط کاربری قابل اجرا یا پروتوتایپ دارید، باید به یک سوال بسیار مهم پاسخ دهید: کاربران به شما گفتند چه میخواهند، اما آیا این همان چیزی است که نیاز دارند؟ آیا نیازمندیهای عملکردی سیستم را برآورده میکند؟ این هم نیاز به تست شدن دارد. یک سیستم بدون باگ که به سوالِ غلط پاسخ میدهد، چندان مفید نیست. آگاه باشید به الگوهای دسترسی کاربر نهایی و اینکه چطور با دادههای تست توسعهدهنده تفاوت دارند.
تست عملکرد (Performance Testing)
تست عملکرد یا تست فشار (Stress testing) نیز ممکن است جنبههای مهمی از پروژه باشند. از خود بپرسید آیا نرمافزار نیازمندیهای عملکردی را تحت شرایط دنیای واقعی برآورده میکند—با تعداد کاربران، کانکشنها، یا تراکنشهای مورد انتظار در ثانیه. آیا مقیاسپذیر است؟ برای برخی اپلیکیشنها، ممکن است به سختافزار یا نرمافزار تست تخصصی برای شبیهسازی واقعیِ بار نیاز داشته باشید.
تست کردنِ تستها
چون ما نمیتوانیم نرمافزار کامل بنویسیم، نتیجه میگیریم که نمیتوانیم نرمافزارِ تستِ کامل هم بنویسیم. ما باید تستها را تست کنیم.
به مجموعه تستسوییتهای (Test suites) خود به عنوان یک سیستم امنیتی پیچیده نگاه کنید که طراحی شده تا وقتی باگی پیدا شد آژیر بکشد. چه راهی بهتر برای تست یک سیستم امنیتی جز اینکه سعی کنید دزدکی وارد شوید؟
بعد از اینکه تستی نوشتید تا یک باگ خاص را تشخیص دهد، عمداً آن باگ را ایجاد کنید و مطمئن شوید که تست شکایت میکند. این تضمین میکند که اگر باگ در واقعیت اتفاق بیفتد، تست آن را خواهد گرفت.
نکته ۹۲: از خرابکاران (Saboteurs) برای تستِ تستکردن خود استفاده کنید
اگر در تست کردن واقعاً جدی هستید، یک برنچ جداگانه از درخت سورس بگیرید، عمداً باگ معرفی کنید و تایید کنید که تستها آنها را میگیرند. در سطح بالاتر، میتوانید از چیزی مثل «میمون آشوب» (Chaos Monkey) نتفلیکس استفاده کنید تا سرویسها را مختل کنید (یعنی «بکشید») و تابآوری اپلیکیشن خود را تست نمایید. [۸۱]
هنگام نوشتن تستها، مطمئن شوید که آژیرها وقتی باید به صدا درآیند، به صدا درمیآیند.
تست کردنِ کامل
وقتی مطمئن شدید که تستهایتان درست هستند و باگهایی را که ایجاد میکنید پیدا میکنند، چطور میدانید که آیا پایه کد (Code base) را به اندازه کافی کامل تست کردهاید؟
پاسخ کوتاه این است که «نمیدانید» و هرگز هم نخواهید دانست. ممکن است بخواهید ابزارهای آنالیز پوشش (Coverage analysis) را امتحان کنید که کد شما را در حین [۸۲] تست تماشا میکنند و ردیابی میکنند کدام خطوط کد اجرا شدهاند و کدام نشدهاند. این ابزارها کمک میکنند حسی کلی از جامع بودن تستهایتان پیدا کنید، اما انتظار نداشته باشید پوشش ۱۰۰٪ ببینید.
حتی اگر اتفاقاً به تکتک خطوط کد برخورد کنید، این تمام تصویر نیست. آنچه مهم است، تعداد حالتهایی (States) است که برنامه شما ممکن است داشته باشد. حالتها معادل خطوط کد نیستند.
برای مثال، فرض کنید تابعی دارید که دو عدد صحیح میگیرد که هر کدام میتوانند عددی از ۰ تا ۹۹۹ باشند:
int test(int a, int b) { return a / (a + b); }
در تئوری، این تابع سه خطی ۱,۰۰۰,۰۰۰ حالت منطقی دارد، که ۹۹۹,۹۹۹ تای آن درست کار میکنند و یکی کار نخواهد کرد (وقتی a + b برابر صفر شود). صرفِ دانستن اینکه شما این خط کد را اجرا کردهاید، آن حالت را به شما نمیگوید—شما باید تمام حالتهای ممکن برنامه را شناسایی کنید.
متأسفانه، به طور کلی این یک مسئله واقعاً سخت است. سخت به معنای اینکه «خورشید قبل از اینکه بتوانید حلش کنید تبدیل به یک توده سرد و سفت شده است.»
نکته ۹۳: پوششِ حالت (State Coverage) را تست کنید، نه پوششِ کد را
تست مبتنی بر ویژگی (Property-Based Testing)
یک راه عالی برای کاوش اینکه کد شما چگونه حالتهای غیرمنتظره را مدیریت میکند، این است که یک کامپیوتر آن حالتها را تولید کند. از تکنیکهای تست مبتنی بر ویژگی استفاده کنید تا دادههای تست را طبق قراردادها و نامتغیرهای (Invariants) کدِ تحت تست تولید کنید. ما این موضوع را با جزئیات در مبحث ۴۲، تست مبتنی بر ویژگی پوشش میدهیم.
سفت کردن تور
در نهایت، میخواهیم تنها و مهمترین مفهوم در تست را فاش کنیم. این مفهومی بدیهی است و تقریباً هر کتاب درسی میگوید این کار را انجام دهید. اما به دلیلی، بیشتر پروژهها هنوز انجامش نمیدهند.
اگر باگی از تورِ تستهای موجود لیز خورد و رد شد، باید تست جدیدی اضافه کنید تا دفعه بعد به دامش بیندازید.
نکته ۹۴: باگها را یک بار پیدا کنید
وقتی یک تسترِ انسان باگی را پیدا میکند، باید آخرین باری باشد که یک تسترِ انسان آن باگ را پیدا میکند. تستهای خودکار باید اصلاح شوند تا از آن پس آن باگ خاص را چک کنند، هر بار، بدون استثنا، مهم نیست چقدر پیشپاافتاده باشد، و مهم نیست توسعهدهنده چقدر شکایت کند و بگوید «اوه، اون دیگه هرگز اتفاق نمیفته.»
چون دوباره اتفاق خواهد افتاد. و ما وقت نداریم دنبال باگهایی بدویم که تستهای خودکار میتوانستند برایمان پیدا کنند. ما باید وقتمان را صرف نوشتن کد جدید—و باگهای جدید—کنیم.
اتوماسیون کامل
همانطور که در ابتدای این بخش گفتیم، توسعه مدرن متکی بر رویههای اسکریپتنویسی شده و خودکار است. چه از چیزی ساده مثل اسکریپتهای شل با rsync و ssh استفاده کنید، یا از راهحلهای پرامکاناتی مثل Ansible، Puppet، Chef یا Salt، فقط به مداخله دستی تکیه نکنید.
روزی روزگاری، در سایت یک مشتری بودیم که همه توسعهدهندگان از یک IDE یکسان استفاده میکردند. مدیر سیستم به هر توسعهدهنده مجموعهای از دستورالعملها برای نصب پکیجهای افزودنی روی IDE داده بود. این دستورالعملها صفحات زیادی را پر میکردند—صفحات پر از اینجا کلیک کن، اونجا اسکرول کن، اینو درگ کن، اونو دابلکلیک کن، و دوباره انجامش بده.
جای تعجب نبود که ماشین هر توسعهدهنده کمی متفاوت بارگذاری شده بود. تفاوتهای ظریفی در رفتار اپلیکیشن رخ میداد وقتی توسعهدهندگان مختلف همان کد را اجرا میکردند. باگها روی یک ماشین ظاهر میشدند اما روی بقیه نه. ردیابی تفاوتهای نسخه هر کامپوننت معمولاً یک سورپرایز را آشکار میکرد.
نکته ۹۵: از رویههای دستی استفاده نکنید
آدمها به اندازه کامپیوترها تکرارپذیر نیستند. نباید هم انتظار داشته باشیم باشند. یک اسکریپت شل یا برنامه، دستورالعملهای یکسان را به همان ترتیب، بارها و بارها اجرا میکند. خودِ اسکریپت هم تحت کنترل نسخه است، بنابراین میتوانید تغییراتِ رویههای بیلد/انتشار را در طول زمان بررسی کنید («ولی قبلاً کار میکرد...»).
همه چیز به اتوماسیون بستگی دارد. نمیتوانید پروژه را روی یک سرور ابری ناشناس بسازید مگر اینکه بیلد کاملاً خودکار باشد. نمیتوانید خودکار دیپلوی کنید اگر مراحل دستی در کار باشد. و به محض اینکه مراحل دستی را معرفی کنید («فقط برای همین یه تیکه...»)، یک پنجره بسیار بزرگ را شکستهاید. [۸۳]
با این سه پایه: کنترل نسخه، تست بیرحمانه و اتوماسیون کامل، پروژه شما فونداسیون محکمی خواهد داشت که نیاز دارید تا بتوانید روی بخش سخت ماجرا تمرکز کنید: خوشحال کردن کاربران.
بخشهای مرتبط شامل:
- مبحث ۱۱: برگشتپذیری
- مبحث ۱۲: گلولههای رسام
- مبحث ۱۷: بازیهای پوسته (Shell Games)
- مبحث ۱۹: کنترل نسخه
- مبحث ۴۱: تست برای کد
- مبحث ۴۹: تیمهای عملگرا
- مبحث ۵۰: نارگیلها کار را راه نمیاندازند
چالشها
- آیا بیلدهای شبانه یا مداوم شما خودکار هستند، اما استقرار به پروداکشن نه؟ چرا؟ چه چیزی در مورد آن سرور خاص است؟
- آیا میتوانید پروژهتان را به طور کامل و خودکار تست کنید؟ بسیاری از تیمها مجبورند پاسخ «نه» بدهند. چرا؟ آیا تعریف نتایج قابلقبول خیلی سخت است؟ آیا این کار اثبات «تمام شدن» پروژه به اسپانسرها را سخت میکند؟ آیا تست منطق اپلیکیشن مستقل از رابط گرافیکی (GUI) خیلی سخت است؟ این درباره GUI چه میگوید؟ درباره وابستگی (Coupling) چطور؟
مبحث ۵۲: کاربران خود را به وجد بیاورید
«وقتی مردم را مسحور میکنید، هدفتان پول درآوردن از آنها یا وادار کردنشان به انجام آنچه میخواهید نیست، بلکه پر کردن آنها از لذت و سرور است.»
— گای کاوازاکی
هدف ما به عنوان توسعهدهنده، به وجد آوردن (Delight) کاربران است. اصلاً برای همین اینجاییم. نه برای استخراج دادههایشان، یا شمردن تعداد نگاههایشان (Eyeballs) یا خالی کردن کیف پولشان.
اهداف شوم و بدطینت به کنار، حتی تحویل به موقعِ نرمافزارِ کارآمد هم کافی نیست. آن به تنهایی آنها را به وجد نمیآورد.
کاربران شما انگیزه خاصی از کد نمیگیرند. در عوض، آنها یک مشکل تجاری (Business problem) دارند که باید در چارچوب اهداف و بودجهشان حل شود. باور آنها این است که با کار کردن با تیم شما قادر به انجام این کار خواهند بود. انتظارات آنها مربوط به نرمافزار نیست. این انتظارات حتی در هیچ مشخصاتی (Specification) که به شما میدهند هم به طور ضمنی وجود ندارد (چون آن مشخصات ناقص خواهد بود تا زمانی که تیم شما چندین بار با آنها روی آن کار کرده باشد).
پس چگونه انتظارات آنها را کشف میکنید؟ یک سوال ساده بپرسید:
«چطور خواهید فهمید که همه ما یک ماه (یا یک سال، یا هر چه) بعد از اتمام این پروژه موفق بودهایم؟»
ممکن است از پاسخ شگفتزده شوید.
پروژهای برای بهبود توصیههای محصول، ممکن است در واقع بر اساس «حفظ مشتری» قضاوت شود؛ پروژهای برای ادغام دو پایگاه داده ممکن است بر اساس «کیفیت داده» سنجیده شود، یا شاید درباره «صرفهجویی در هزینه» باشد.
اما این انتظاراتِ ارزش تجاری است که واقعاً اهمیت دارد—نه فقط خودِ پروژه نرمافزاری. نرمافزار تنها وسیلهای برای رسیدن به این اهداف است.
و حالا که برخی از انتظاراتِ ارزشیِ زیربناییِ پروژه را رو آوردهاید، میتوانید شروع به فکر کردن درباره این کنید که چگونه میتوانید در راستای آنها تحویل دهید:
- مطمئن شوید همه اعضای تیم کاملاً درباره این انتظارات توجیه و شفاف هستند.
- هنگام تصمیمگیری، فکر کنید کدام مسیرِ پیشِ رو، به آن انتظارات نزدیکتر میشود.
- نیازمندیهای کاربر را در پرتوِ این انتظارات، نقادانه تحلیل کنید.
در بسیاری از پروژهها ما کشف کردهایم که «نیازمندیِ» بیانشده، در واقع فقط یک حدس درباره کاری بوده که میتوان با تکنولوژی انجام داد: در واقع یک «برنامه پیادهسازیِ آماتور» بوده که لباسِ «سند نیازمندیها» را پوشیده است. نترسید از اینکه پیشنهادهایی بدهید که نیازمندی را تغییر دهد، البته اگر بتوانید نشان دهید که آن تغییرات پروژه را به هدف (Objective) نزدیکتر میکند.
- همانطور که در پروژه پیش میروید، به فکر کردن درباره این انتظارات ادامه دهید.
ما دریافتهایم که با افزایش دانش ما از دامنه (Domain)، بهتر میتوانیم پیشنهادهایی درباره کارهای دیگری بدهیم که میتواند برای حل مسائل تجاریِ زیربنایی انجام شود. ما قویاً معتقدیم که توسعهدهندگان، که در معرض جنبههای بسیار متفاوتی از یک سازمان هستند، اغلب میتوانند راههایی برای بافتنِ بخشهای مختلفِ کسبوکار به هم ببینند که همیشه برای دپارتمانهای جداگانه آشکار نیست.
نکته ۹۶: کاربران را به وجد بیاورید، فقط کد تحویل ندهید
اگر میخواهید مشتریتان را به وجد بیاورید، رابطهای با آنها ایجاد کنید که بتوانید فعالانه به حل مشکلاتشان کمک کنید. با اینکه عنوان شغلی شما ممکن است تنوعی از «توسعهدهنده نرمافزار» یا «مهندس نرمافزار» باشد، در حقیقت باید «حلکننده مشکل» (Problem Solver) باشد.
این کاری است که ما میکنیم، و این جوهره یک برنامهنویس عملگراست. ما مشکلات را حل میکنیم.
بخشهای مرتبط شامل:
- مبحث ۱۲: گلولههای رسام
- مبحث ۱۳: پروتوتایپها و کاغذهای یادداشت
- مبحث ۴۵: گودال نیازمندیها
مبحث ۵۳: غرور و تعصب
«شما به اندازه کافی ما را مشعوف کردهاید.»
— جین آستین، غرور و تعصب
برنامهنویسان عملگرا از مسئولیت شانه خالی نمیکنند. در عوض، ما از پذیرفتن چالشها و شناساندن تخصصمان خوشحال میشویم. اگر مسئول یک طراحی یا قطعهای کد هستیم، کاری میکنیم که بتوانیم به آن افتخار کنیم.
نکته ۹۷: پایِ کارِ خود را امضا کنید
صنعتگرانِ اعصار گذشته مفتخر بودند که پای کارشان را امضا کنند. شما هم باید باشید.
البته، تیمهای پروژه هنوز از انسانها تشکیل شدهاند و این قانون میتواند باعث دردسر شود. در برخی پروژهها، ایده «مالکیت کد» میتواند باعث مشکلات همکاری شود. افراد ممکن است قلمروطلب (Territorial) شوند، یا مایل نباشند روی عناصر بنیادین مشترک کار کنند. پروژه ممکن است در نهایت شبیه دستهای از «ملوکالطوایفیهای کوچک و جزیرهای» شود. شما به نفع کدِ خودتان و علیه همکارانتان دچار تعصب میشوید.
این چیزی نیست که ما میخواهیم. شما نباید با حسادت از کدِ خود در برابر مداخلهگران دفاع کنید؛ به همان ترتیب، باید با کدِ دیگران با احترام رفتار کنید.
«قانون طلایی» (با دیگران همانطور رفتار کن که میخواهی با تو رفتار کنند) و یک بنیانِ احترام متقابل میان توسعهدهندگان، برای عملی کردن این نکته حیاتی است.
گمنامی، بهویژه در پروژههای بزرگ، میتواند بستری برای شلختگی، اشتباهات، تنبلی و کدِ بد فراهم کند. خیلی آسان میشود که خودتان را فقط چرخدندهای در یک چرخ بزرگ ببینید و به جای کدِ خوب، در گزارشهای وضعیتِ بیپایان، بهانههای لنگ بیاورید.
در حالی که کد باید «مالک» داشته باشد، لزومی ندارد که مالکِ آن یک فرد باشد. در واقع، «برنامهنویسی مفرط» (XP) کنت بِک، مالکیت اشتراکی (Communal ownership) کد را توصیه میکند (اما این هم نیازمند شیوههای اضافی مثل برنامهنویسی دونفره است تا در برابر خطرات گمنامی محافظت کند). [۸۴]
ما میخواهیم «غرورِ مالکیت» را ببینیم. «من این را نوشتم، و پای کارم میایستم.»
امضای شما باید به عنوان نشانگر کیفیت شناخته شود. مردم باید نام شما را روی یک قطعه کد ببینند و انتظار داشته باشند که مستحکم، خوشنوشت، تستشده و مستند باشد. یک کارِ واقعاً حرفهای. نوشته شده توسط یک حرفهای.
یک برنامهنویس عملگرا.
متشکریم.