Skip to content

فصل ۴ — کار تکراری

تکرار (iteration) به‌عنوان «رویه‌ای که تکرار دنباله‌ای از عملیات، نتایجی را که پی‌درپی به نتیجهٔ مطلوب نزدیک‌تر می‌شوند، تولید می‌کند» تعریف می‌شود.[^1]

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

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

انقلاب چابک

تیم‌ها از حداقل دههٔ ۱۹۶۰ رویکردهای تکراری‌تر و بازخورد-محور به توسعه را عمل می‌کردند. اما پس از نشست مشهور رهبران فکری و عملگران در یک استراحتگاه اسکی در کلرادو، بیانیهٔ چابک (Agile Manifesto)[^2] فلسفهٔ مشترکی را که این راهبردهای انعطاف‌پذیرتر و یادگیری-محور را در تضاد با فرایندهای سنگین‌تر رایج آن زمان زیربنای کرد، ترسیم کرد.

بیانیهٔ چابک سند ساده‌ای است: ۹ خط متن و ۱۲ اصل، اما اثر بزرگی داشت.

قبل از آن، حکمت رایج — با چند مخالف خاموش — این بود که اگر چیز «جدی» در نرم‌افزار انجام می‌دهید، به فنون متمرکز بر تولید waterfall نیاز دارید.

تفکر چابک مدتی طول کشید تا رخنه کند، اما اکنون آن — نه waterfall — رویکرد غالب است، حداقل از منظر تفکر.

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

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

این تغییر ادراک مهم است، اما کافی نیست. چرا این گام مهم بود؟ چون گامی به سمت تلقی توسعهٔ نرم‌افزار به‌عنوان تمرین یادگیری — نه مسئلهٔ تولید — بود. فرایندهای Waterfall برای بعضی مسائل تولید مؤثرند، اما برای مسائلی که کاوش دارند بسیار نامناسب‌اند.

این گام مهم است چون اگرچه گام ۱۰ برابری Fred Brooks از نظر فناوری، ابزار یا فرایند در دسترس به نظر نمی‌رسد، بعضی رویکردها آن‌قدر ناکارآمدند که بهبود یک مرتبه‌ای کاملاً ممکن است. Waterfall وقتی به توسعهٔ نرم‌افزار اعمال شود چنین نامزدی است.

تفکر Waterfall از فرض «اگر فقط به‌اندازهٔ کافی فکر/کار کنیم، از ابتدا درست می‌گیریم» شروع می‌کند.

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

[^2]: بیانیهٔ چابک، https://agilemanifesto.org/

تفکر چابک این ایده را با علم به اشتراک می‌گذارد. نزدیک شدن به ایده‌ها از منظر تردیدآمیز و تلاش برای رد کردن ایده‌ها به‌جای اثبات درستی آن‌ها (falsifiability) ذاتی ذهنیت علمی‌تر است.

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

بر اساس فرض‌های تفکر چابک، سازمان تیم‌ها، فرایندها و فناوری را طوری می‌چینیم که بتوانیم ایمن اشتباه کنیم، اشتباه را به‌راحتی ببینیم، تغییر دهیم و — ideally — دفعهٔ بعد بهتر عمل کنیم.

بحث‌های Scrum در برابر Extreme Programming یا continuous integration در برابر feature branching یا TDD در برابر توسعه‌دهندگان ماهر که سخت فکر می‌کنند — یا هر چیز دیگر — بی‌ربط‌اند. در قلبش، هر فرایند واقعاً چابک تمرینی در «کنترل فرایند تجربی» (empirical process control) است.

این تناسب بسیار بهتری با توسعهٔ نرم‌افزار — از هر نوع — نسبت به رویکرد waterfall متمرکز بر تولید و مبتنی بر پیش‌بینی که قبل از آن بود دارد.

کار تکراری از بعضی جهات بنیادین با کار به رویکرد برنامه‌ریزی‌شده و ترتیبی فرق دارد. اما راهبردی به‌مراتب مؤثرتر است.

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

تکرار در قلب همهٔ یادگیری کاوش‌گرانه است و بنیاد هر کسب دانش واقعی.

[^1]: منبع: Merriam Webster Dictionary، https://www.merriam-webster.com/dictionary/iteration

مزایای عملی کار تکراری

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

شاید مهم‌ترین ایده این است که اگر شیوه‌های کاری را برای کار تکراری‌تر تغییر دهیم، خودبه‌خود تمرکزمان را باریک می‌کند و به فکر کردن در batchهای کوچک‌تر و جدی‌تر گرفتن modularity و separation of concerns تشویق می‌کند. این ایده‌ها به‌عنوان پیامد طبیعی کار تکراری‌تر شروع می‌شوند، اما در نهایت بخشی از حلقهٔ فضیلت‌آمیز می‌شوند که کیفیت کار را تقویت می‌کند.

یکی از ایده‌های مشترک Scrum و Extreme Programming (XP) این بود که روی واحدهای کوچک کار تا تکمیل کار کنیم. تفکر چابک این بود: «پیشرفت در توسعهٔ نرم‌افزار سخت اندازه‌گیری می‌شود، اما می‌توانیم featureهای تمام‌شده را اندازه بگیریم؛ پس روی featureهای کوچک‌تر کار کنیم تا ببینیم کی تمام شده‌اند.»

این کاهش اندازهٔ batch گام بزرگی به جلو بود. اما وقتی می‌خواهید بدانید «تمام شدن» چقدر طول می‌کشد پیچیده می‌شود. این رویکرد تکراری به توسعه با تفکر سنتی‌تر فرق دارد. مثلاً در continuous delivery طوری کار می‌کنیم که هر تغییر کوچک — چند بار در روز — قابل انتشار باشد. باید آن‌قدر تمام شده باشد که بتوانیم نرم‌افزار را در هر نقطه ایمن و قابل‌اتکا به production منتشر کنیم. پس «تمام شدن» در آن بستر واقعاً چه معنایی دارد؟

هر تغییر تمام شده است چون قابل انتشار است؛ پس تنها معیار معقول «تمام شدن» این است که ارزشی به کاربرانش بدهد. این چیز بسیار ذهنی است. چگونه پیش‌بینی کنیم چند تغییر برای «ارزش» به کاربران لازم است؟ بیشتر سازمان‌ها مجموعه‌ای از featureها را حدس می‌زنند که در ترکیب «ارزش» را نشان می‌دهند، اما اگر در هر نقطه از عمر نرم‌افزار بتوانم منتشر کنم، این مفهوم کمی مبهم است.

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

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

با این حال، هر قصد و هر نتیجه‌ای باشد، این رویکرد مبتنی بر batch کوچک ما را به‌عنوان صنعت تشویق کرد اندازه و پیچیدگی featureهایی که روی آن‌ها کار می‌کردیم را کاهش دهیم — و این گام واقعاً مهمی است.

برنامه‌ریزی چابک تا حد زیادی به تجزیهٔ کار به قطعات به‌اندازهٔ کافی کوچک وابسته بود تا featureها را در یک sprint یا تکرار تمام کنیم. در ابتدا این را برای اندازه‌گیری پیشرفت ترویج می‌کرد، اما اثر عمیق‌تری داشت: بازخورد قطعی دربارهٔ کیفیت و مناسب بودن کارمان به‌طور منظم. این تغییر نرخ یادگیری را بالا می‌برد. آیا این طراحی کار می‌کند؟ آیا کاربران این feature را دوست دارند؟ آیا سیستم به‌اندازهٔ کافی سریع است؟ آیا همهٔ باگ‌ها را حذف کرده‌ام؟ آیا کدم برای کار لذت‌بخش است؟ و غیره.

کار تکراری در گام‌های کوچک، قطعی و آمادهٔ production بازخورد عالی به ما می‌دهد!

تکرار به‌عنوان راهبرد طراحی دفاعی

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

نگاه جالبی به بنیادهای تفکر چابک را نخست دوستم Dan North به من ارائه داد. North تفاوت تفکر waterfall و چابک را — عملاً — مسئله‌ای در اقتصاد توصیف کرد. تفکر Waterfall بر فرض استوار است که تغییر با گذشت زمان گران‌تر می‌شود. کلاسیکاً دربارهٔ مدل هزینهٔ تغییر (Cost of Change) صحبت می‌کند، همان‌طور که در شکل ۴-۱ نشان داده شده.

شکل ۴-۱. مدل کلاسیک هزینهٔ تغییر

هزینه — با گذشت زمان به‌طور تند بالا می‌رود (منحنی نمایی)

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

توسعهٔ نرم‌افزار هرگز با «…هر قطعه کار کاملاً فهمیده شده» شروع نمی‌شود، هرچقدر هم قبل از شروع تحلیل کنیم. با توجه به اینکه هرگز با «مجموعهٔ ورودی‌های مشخص‌شده» شروع نمی‌کنیم — هرچقدر هم برنامه‌ریزی کنیم — مدل فرایند تعریف‌شده یا رویکرد waterfall از همان مانع اول می‌افتد. نمی‌توان توسعهٔ نرم‌افزار را در این قالب نامناسب جا داد.

شگفتی‌ها، سوءتفاهم‌ها و اشتباهات در توسعهٔ نرم‌افزار عادی‌اند چون تمرینی در کاوش و کشف است؛ پس باید روی یادگیری تمرکز کنیم تا از لغزش‌هایی که حتماً در مسیر مرتکب می‌شویم محافظت شویم.

دیدگاه جایگزین Dan North این بود: با توجه به اینکه مدل کلاسیک هزینهٔ تغییر به ما کمک نمی‌کند، چه چیزی کمک می‌کند؟ چقدر بهتر بود اگر منحنی هزینهٔ تغییر را صاف کنیم؟ (شکل ۴-۲ را ببینید.)

شکل ۴-۲. هزینهٔ تغییر چابک

هزینه — تقریباً ثابت در طول زمان (منحنی صاف)

چه می‌شد اگر بتوانیم نظرمان را عوض کنیم، ایده‌های تازه کشف کنیم، خطاها را کشف و رفع کنیم — همه با تقریباً همان هزینه — هر وقت اتفاق افتاد؟ چه می‌شد اگر منحنی هزینهٔ تغییر صاف بود؟

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

پس برای دستیابی به منحنی صاف هزینهٔ تغییر چه لازم است؟

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

این یکی از ایده‌های در قلب continuous delivery است (شکل ۴-۳).

شکل ۴-۳. تکرار در continuous delivery

چرخهٔ Lead Time: Design → Develop → Test → Release — با حلقه‌های بازخورد و یادگیری در هر مرحله

فریب برنامه

کسانی که تفکر waterfall را ترویج می‌کردند نیت خیر داشتند. فکر می‌کردند بهترین راه به جلو است. صنعتمان دهه‌ها تلاش کرده این رویکرد کار کند و نمی‌کند.

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

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

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

جنگ‌های فرایند

اگر بهبود ۱۰ برابری از زبان، رسمی‌گرایی یا نمودار در دسترس نیست، کجا دیگر نگاه کنیم؟

شیوهٔ سازماندهی خودمان و رویکرد به مهارت‌ها و فنون یادگیری و کشفی که به نظر ذاتی رشتهٔ ماست، راه مفیدی به نظر می‌رسد.

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

با شروع انقلاب رایانه و ubiquitous شدن توسعهٔ نرم‌افزار، تقاضا به‌سرعت از عرضه پیشی گرفت. به نرم‌افزار بیشتر، بهتر و سریع‌تر نیاز داشتیم! پس به صنایع دیگر نگاه کردیم تا ببینیم چگونه در مقیاس کارآمد کار می‌کنند.

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

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

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

در دهه‌های ۱۹۸۰ و ۱۹۹۰ توسعهٔ نرم‌افزار به‌عنوان رشته منفجر شد و پیچیدگی فرایندهای اعمال‌شده در بسیاری از سازمان‌های بزرگ هم منفجر شد.

این شکست‌ها با وجود اینکه بسیاری از جنبه‌های مسئله توسط اندیشمندان پیشرو رشته خوب فهمیده شده بود، رخ داد.

The Mythical Man Month Fred Brooks — باز هم — این مسائل و چگونگی اجتناب از آن‌ها را در ۱۹۷۰ با جزئیات توصیف کرد. اگر این اثر بنیادین رشتهٔ ما را نخوانده‌اید، احتمالاً شگفت‌زده می‌شوید چقدر دقیق مشکلاتی را که — به احتمال زیاد — تقریباً هر روز در کار توسعه‌دهنده با آن‌ها روبه‌رو هستید توصیف می‌کند — با وجود اینکه بر تجربهٔ Brooks در توسعهٔ سیستم‌عامل IBM 360 در اواخر دههٔ ۱۹۶۰ با فناوری و ابزارهای نسبتاً خام آن روز استوار است. Brooks — باز هم — به چیزی مهم‌تر و بنیادین‌تر از زبان، ابزار یا فناوری اشاره می‌کرد.

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

اواخر دههٔ ۱۹۹۰، در واکنش به این فرایندهای سنگین، بعضی شروع به تعریف راهبردهای مؤثرتر کردند. Crystal، Scrum، Extreme Programming و چند مورد دیگر سعی کردند این رویکرد بسیار متفاوت را ثبت کنند. این دیدگاه‌ها در بیانیهٔ چابک رسمی شدند.

در نرم‌افزار، انقلاب چابک آن هنجار را برانداخت، اما حتی امروز بسیاری — شاید اکثر — سازمان‌ها در عمق همچنان برنامه‌محور / waterfall هستند.

علاوه بر دشواری تشخیص مسئله، در سازمان‌هایی که به برنامه‌ریزی به سبک waterfall چسبیده‌اند مقداری خواستار بودن (wishful thinking) باقی مانده. lovely بود اگر سازمانی بتواند:

  • نیازهای کاربران را درست شناسایی کند
  • ارزش برای سازمان را اگر آن نیازها برآورده شوند دقیق تخمین بزند
  • هزینهٔ برآورده کردن آن نیازها را دقیق برآورد کند
  • تصمیم عقلانی بگیرد آیا سود از هزینه بیشتر است
  • برنامهٔ دقیق بسازد
  • برنامه را بدون انحراف اجرا کند
  • در پایان پول را بشمارد

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

دادهٔ صنعت می‌گوید برای بهترین شرکت‌های نرم‌افزاری جهان، دو سوم ایده‌ها ارزش صفر یا منفی تولید می‌کنند.[^3] در حدس زدن آنچه کاربران می‌خواهند وحشتناکیم. حتی وقتی از کاربران می‌پرسیم، آن‌ها هم نمی‌دانند چه می‌خواهند. مؤثرترین رویکرد تکرار است: پذیرش اینکه بعضی — شاید بسیاری — از ایده‌هایمان اشتباه‌اند و طوری کار کنیم که بتوانیم آن‌ها را تا حد امکان سریع، ارزان و کارآمد امتحان کنیم.

ارزیابی ارزش تجاری ایده هم notoriously دشوار است. نقل‌قول مشهوری از Thomas J. Watson رئیس IBM هست که روزی پیش‌بینی کرد تقاضای جهانی برای رایانه روزی به پنج دستگاه می‌رسد!

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

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

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

در The Beginning of Infinity David Deutsch تفاوت عمیق میان ایده‌های محدود در دامنه و ایده‌های نامحدود را توصیف می‌کند. مقایسهٔ رویکرد برنامه‌ریزی‌شده waterfall و رویکرد تکراری، کاوش‌گرانه و آزمایشی مقایسهٔ دو ایدهٔ بنیادین متفاوت است. مدل‌های کنترل فرایند تعریف‌شده[^4] به «فرایند تعریف‌شده» نیاز دارند. تعریفاً دامنهٔ محدود دارد. در حد این رویکرد، در سطحی ظرفیت مغز انسان برای نگه‌داشتن جزئیات کل فرایند وجود دارد. می‌توانیم باهوش باشیم و از انتزاع و مفاهی مثل modularity برای پنهان کردن بعضی جزئیات استفاده کنیم، اما در نهایت تعریف فرایند از ابتدا تا انتها در نوعی برنامه نیاز دارد همهٔ آنچه اتفاق می‌افتد را پوشش داده باشیم. این رویکرد ذاتاً محدود به حل مسائلی است که از قبل می‌فهمیم.

رویکرد تکراری بسیار متفاوت است. می‌توانیم وقتی تقریباً هیچ نمی‌دانیم شروع کنیم و باز هم پیشرفت مفید داشته باشیم. می‌توانیم با جنبهٔ ساده و قابل فهم سیستم شروع کنیم. از آن برای کاوش در شیوهٔ کار تیم، امتحان اولین افکار معماری، امتحان فناوری‌های امیدوارکننده و غیره استفاده کنیم. هیچ‌کدام لزوماً ثابت نیست. باز هم پیشرفت کرده‌ایم حتی اگر فهمیدیم فناوری ایدهٔ بدی بود و اولین مفهوم معماری اشتباه بود. حالا بیشتر از قبل می‌دانیم. این فرایندی ذاتاً باز و نامحدود است. تا وقتی نوعی تابع برازندگی (fitness function) — راهی برای فهمیدن نزدیک یا دور شدن از هدف — داشته باشیم، می‌توانیم برای همیشه در این مسیر ادامه دهیم؛ درک، ایده‌ها، مهارت‌ها و محصولاتمان را refine، تقویت و بهبود دهیم. حتی می‌توانید در مسیر «تابع برازندگی» را عوض کنید اگر تصمیم بگیرید اهداف بهتری برای هدف‌گیری هست.

آغاز بی‌پایان

در کتاب ذهن‌گشای The Beginning of Infinity فیزیک‌دان David Deutsch علم و روشنگری را جستجوی «توضیحات خوب» توصیف می‌کند و توضیح می‌دهد چگونه ایده‌های مختلف در تاریخ بشریت «آغاز بی‌پایان»ی هستند که به ما اجازه می‌دهند با هر کاربرد مرتبط قابل تصور از این توضیحات خوب کنار بیاییم.

نمونهٔ خوب تفاوت میان الفبا و شکل نوشتاری تصویری (pictographic) است.

بشر با شکل‌های تصویری شروع کرد و نوشتار چینی و ژاپنی (در بعضی سبک‌ها) هنوز این شکل را دارد. زیبا به نظر می‌رسند، اما نقص جدی دارند. اگر واژهٔ تازه‌ای بشنوید که نمی‌دانید چگونه بنویسیدش، تا کس دیگری نگوید نمی‌توانید بنویسید. شکل‌های تصویری واقعاً افزایشی (incremental) نیستند؛ باید نماد درست هر واژه را بدانید. (در نوشتار چینی حدود ۵۰٬۰۰۰ نویسه وجود دارد.)

الفبا به‌شکل بنیادین متفاوت کار می‌کند. الفباها صداها را encode می‌کنند، نه واژه‌ها. می‌توانید هر واژه‌ای را — شاید اشتباه — طوری بنویسید که هر کسی حداقل از نظر آوایی بفهمد چه نوشته‌اید.

این حتی اگر واژه را نشنیده یا ندیده باشید درست است.

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

این ایدهٔ دامنه یا reach بی‌پایان برای رویکرد چابک به توسعه درست است و برای رویکرد مبتنی بر waterfall نیست.

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

ظرفیت ذهنی انسان محدود است، اما ظرفیت درکمان لزوماً نیست. می‌توانیم با فنونی که تکامل یافته و توسعه داده‌ایم محدودیت‌های فیزیولوژیک مغز را پوشش دهیم. می‌توانیم چیزها را abstract کنیم و compartmentalize (modularize) کنیم و درکمان را تا حد قابل توجهی scale کنیم.

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

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

این تفاوت عمیقی است و توضیح می‌دهد چرا تفکر چابک گام مهم و قابل‌توجهی به جلو در توانایی پیشرفت در حل — ideally — مسائل سخت‌تر و سخت‌تر است.

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

[^3]: منبع: «Online Controlled Experiments at Large Scale»، https://stanford.io/2LdjvmC

[^4]: Ken Schwaber waterfall را «مدل کنترل فرایند تعریف‌شده» توصیف کرد که تعریف کرد: «مدل کنترل فرایند تعریف‌شده می‌خواهد هر قطعه کار کاملاً فهمیده شود. با مجموعهٔ ورودی‌های مشخص‌شده، همان خروجی‌ها هر بار تولید می‌شوند. فرایند تعریف‌شده را می‌توان شروع کرد و تا تکمیل با همان نتایج هر بار اجرا گذاشت.» Schwaber این را با «مدل کنترل فرایند تجربی» که رویکرد چابک نمایندگی می‌کند مقایسه می‌کند. نگاه کنید به https://bit.ly/2UiaZdS.

فریب برنامه کاذب است. این رویکرد دقیق‌تر، کنترل‌شده‌تر و حرفه‌ای‌تر نیست؛ بلکه محدودتر و بیشتر مبتنی بر حدس و گمان است و واقعاً فقط برای سیستم‌های کوچک، ساده، خوب فهمیده و مشخص‌شده کار می‌کند.

پیامدهای این قابل‌توجه است. یعنی باید — همان‌طور که Kent Beck در زیرعنوان اثر بنیادینش Extreme Programming Explained گفت — «تغییر را بپذیریم» (Embrace change)!

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

حتی برای چیزی به‌ظاهر عادی مثل سفر با ماشین، نمی‌توانید مطمئن باشید چقدر طول می‌کشد یا مسیر انتخابی‌تان بعد از شروع هنوز بهترین مسیر است. امروز ابزارهای wonderful مثل سیستم‌های مسیریاب ماهواره‌ای با ارتباط رادیویی داریم که نه‌تنها در ابتدا مسیر را برنامه‌ریزی می‌کنند بلکه تصویر را با اطلاعات ترافیک به‌روز می‌کنند و به ما اجازه می‌دهند در شرایط متغیر سفر «بازبینی و سازگاری» کنیم.

رویکرد تکراری به برنامه‌ریزی و اجرا به ما اجازه می‌دهد همیشه به‌روزترین تصویر از وضعیتی که واقعاً در آن هستیم را داشته باشیم — نه نسخهٔ پیش‌بینی‌شده، نظری و همیشه نادقیق. اجازه می‌دهد یاد بگیریم، واکنش نشان دهیم و با تغییرات در مسیر سازگار شویم.

کار تکراری تنها راهبرد مؤثر برای وضعیت متغیر است.

عملیات کار تکراری

پس چه می‌توانیم برای کار به این شکل انجام دهیم؟ نخستین کار: در batchهای کوچک‌تر کار کنیم. دامنهٔ هر تغییر را کم کنیم و تغییر را در گام‌های کوچک‌تر — به‌طور کلی هرچه کوچک‌تر بهتر — ایجاد کنیم. این به ما اجازه می‌دهد فنون، ایده‌ها و فناوری را مکررتر امتحان کنیم.

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

تجسم واضح این ایده در تیم‌های چابک، ایدهٔ تکرارها یا sprintهاست. رشته‌های چابک ایدهٔ کار تا کد تمام‌شده و آمادهٔ production در بازهٔ زمانی کوچک و ثابت را ترویج می‌کنند. اثرات مفید متعددی دارد — همان‌هایی که در این فصل توصیف شد. اما این فقط یک تجسم در مقیاس درشت کار تکراری‌تر است.

در مقیاس کاملاً متفاوت، می‌توانید شیوه‌های continuous integration (CI) و test-driven development (TDD) را فرایندهای ذاتاً تکراری بدانید.

در CI تغییرات را مکرراً — چند بار در روز — commit می‌کنیم. یعنی هر تغییر باید atomic باشد، حتی اگر featureای که به آن کمک می‌کند هنوز کامل نباشد. این نحوهٔ برخورد به کار را عوض می‌کند، اما فرصت‌های بیشتری برای یادگیری و فهمیدن اینکه آیا کدمان هنوز کنار کد بقیه کار می‌کند می‌دهد.

TDD اغلب با شیوه‌هایی که به آن کمک می‌کنند توصیف می‌شود: Red, Green, Refactor.

  • Red: آزمون بنویسید، اجرا کنید و fail شدن را ببینید.
  • Green: فقط به‌اندازهٔ کافی کد بنویسید تا آزمون pass شود، اجرا کنید و pass شدن را ببینید.
  • Refactor: کد و آزمون را برای وضوح، بیان، elegance و عمومی‌تر شدن تغییر دهید. بعد از هر تغییر کوچک آزمون را اجرا کنید و pass شدن را ببینید.

این رویکرد تکراری بسیار ریزدانه است. رویکردی به‌مراتب تکراری‌تر به جزئیات فنی بنیادین نوشتن کد تشویق می‌کند.

مثلاً در کدنویسی خودم تقریباً همیشه classها، متغیرها، functionها و parameterهای تازه را از طریق سری چندمرحله‌ای گام‌های refactoring کوچک معرفی می‌کنم و مکرراً با اجرای آزمون بررسی می‌کنم کد همچنان کار می‌کند.

این کار تکراری در وضوح بسیار ریز است. یعنی کدم بیشتر وقت درست و کارکن بودن را دارد و هر گام امن‌تر است.

در هر نقطه از فرایند می‌توانم دوباره ارزیابی کنم و نظر و جهت طراحی و کدم را به‌راحتی عوض کنم. گزینه‌هایم باز می‌ماند!

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

خلاصه

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

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