در کتاب قبلیام¹ مفصل دربارهٔ ساختار و ماهیت «کد تمیز» نوشتهام. این فصل دربارهٔ خودِ عمل کدنویسی است و زمینهای که آن عمل را احاطه میکند.
وقتی ۱۸ سالم بود، نسبتاً خوب تایپ میکردم، اما مجبور بودم به کلیدها نگاه کنم. تایپ کور بلد نبودم. یک شب چند ساعت طولانی را پشت یک دستگاه IBM 029 keypunch گذراندم؛ با این تصمیم که هنگام تایپ برنامهای که قبلاً روی چند فرم کدنویسی نوشته بودم، اصلاً به انگشتانم نگاه نکنم. بعد از تایپ هر کارت، آن را بررسی میکردم و اگر اشتباه تایپ شده بود، دور میانداختم.
اوایل کارتهای زیادی را اشتباه میزدم. اما تا آخر شب، تقریباً بینقص تایپ میکردم. آن شب طولانی به این نتیجه رسیدم که تایپ کور، بیش از هر چیز، مسئلهٔ اعتمادبهنفس است. انگشتانم میدانستند کلیدها کجا هستند؛ فقط باید به این اطمینان میرسیدم که اشتباه نمیکنم. یکی از چیزهایی که به این اعتمادبهنفس کمک کرد این بود که میتوانستم لحظهٔ اشتباه را حس کنم. تا پایان شب، اگر خطایی میکردم، تقریباً بلافاصله متوجه میشدم و بدون نگاه کردن، کارت را بیرون میانداختم.
تواناییِ حس کردنِ خطاها واقعاً مهم است؛ نه فقط در تایپ، بلکه در هر کاری. داشتن «حس خطا» یعنی حلقهٔ بازخورد را خیلی سریع میبندید و خیلی سریعتر از اشتباهاتتان یاد میگیرید. از آن شب روی دستگاه 029، چندین رشتهٔ دیگر را مطالعه کردهام و به آنها مسلط شدهام. در همهٔ آنها به این نتیجه رسیدهام که کلیدِ تسلط، اعتمادبهنفس و حس خطا است.
این فصل مجموعهٔ شخصیِ قوانین و اصول من برای کدنویسی را توصیف میکند. این قوانین و اصول دربارهٔ خودِ کد نیستند؛ بلکه دربارهٔ رفتار، حالوهوا و نگرش من هنگام نوشتن کد هستند. آنها زمینهٔ ذهنی، اخلاقی و احساسی من برای کدنویسی را شرح میدهند. اینها ریشههای اعتمادبهنفس و حس خطای مناند.
احتمالاً با همهٔ حرفهایم موافق نخواهید بود. بالاخره اینها کاملاً شخصیاند. حتی ممکن است با بعضی از نگرشها و اصولم شدیداً مخالف باشید. اشکالی ندارد—اینها قرار نیست حقیقتهای مطلق برای کسی جز خود من باشند. اینها صرفاً رویکرد یک نفر به حرفهای بودن در کدنویسی است.
شاید با مطالعه و تأمل در فضای شخصیِ کدنویسی من، بتوانید سنگریزه را از دستم بقاپید.
کدنویسی فعالیتی ذهنی، چالشبرانگیز و فرساینده است. به سطحی از تمرکز و توجه نیاز دارد که در کمتر رشتهای پیدا میشود. دلیلش این است که کدنویسی شما را مجبور میکند همزمان چند عامل متعارض را مدیریت کنید.
-
کد شما باید کار کند. باید بفهمید دقیقاً چه مسئلهای را حل میکنید و چگونه باید آن را حل کرد. باید مطمئن شوید کدی که مینویسید، بازنمایی دقیقی از آن راهحل است. باید همهٔ جزئیات راهحل را مدیریت کنید و همزمان با زبان، پلتفرم، معماری فعلی و همهٔ زگیلهای سیستم موجود سازگار بمانید.
-
کد شما باید مسئلهای را که مشتری مطرح کرده حل کند. اغلب، نیازمندیهای مشتری در واقع مشکل واقعی او را حل نمیکنند. تشخیص این موضوع و مذاکره با مشتری برای برآورده کردن نیازهای واقعیاش، وظیفهٔ شماست.
-
کد شما باید بهخوبی در سیستم موجود جا بیفتد. نباید سختی، شکنندگی یا ابهام سیستم را افزایش دهد. وابستگیها باید بهخوبی مدیریت شوند. خلاصه اینکه کد شما باید از اصول مهندسی درست پیروی کند.²
-
کد شما باید برای برنامهنویسان دیگر قابلخواندن باشد. این صرفاً به نوشتن کامنتهای خوب مربوط نیست؛ بلکه مستلزم این است که کد را طوری بسازید که نیت شما را آشکار کند. این کار سخت است—در واقع شاید سختترین چیزی باشد که یک برنامهنویس میتواند در آن به مهارت برسد.
مدیریت همزمان همهٔ این دغدغهها سخت است. از نظر فیزیولوژیک، حفظ تمرکز لازم برای مدتهای طولانی دشوار است. حالا مشکلات و حواسپرتیهای کار تیمی، سازمانی، و نگرانیهای زندگی روزمره را هم به آن اضافه کنید. نتیجه این است که احتمال حواسپرتی بسیار بالاست.
وقتی نتوانید به اندازهٔ کافی تمرکز کنید، کدی که مینویسید غلط خواهد بود. باگ خواهد داشت. ساختار نادرست خواهد داشت. مبهم و پیچیده خواهد بود. مشکلات واقعی مشتری را حل نخواهد کرد. خلاصه اینکه باید دوبارهکاری یا از نو نوشته شود. کار کردن در حالت حواسپرتی یعنی اتلاف.
اگر خسته یا حواسپرت هستید، کدنویسی نکنید. فقط مجبور میشوید کاری را که انجام دادهاید دوباره انجام دهید. در عوض، راهی پیدا کنید که حواسپرتیها را حذف کنید و ذهنتان را آرام سازید.
بدترین کدی که تا به حال نوشتهام، ساعت ۳ صبح بود. سال ۱۹۸۸. در یک استارتاپ مخابراتی به نام Clear Communications کار میکردم. همهمان ساعتهای طولانی کار میکردیم تا «سرمایهٔ عرقریزی» بسازیم. البته همهمان هم رویای پولدار شدن داشتیم.
یک شبِ خیلی دیر—یا بهتر بگویم، یک صبحِ خیلی زود—برای حل یک مشکل زمانبندی، کاری کردم که کدم از طریق سیستم توزیع رویداد، به خودش پیام بفرستد (ما به این کار میگفتیم «فرستادن نامه»). این راهحل غلط بود، اما ساعت ۳ صبح خیلی هم عالی به نظر میرسید. بعد از ۱۸ ساعت کدنویسیِ مداوم (بهعلاوهٔ هفتههای ۶۰–۷۰ ساعته)، تنها چیزی بود که به ذهنم میرسید.
یادم هست که از ساعتهای طولانی کارم احساس غرور میکردم. احساس تعهد میکردم. فکر میکردم کار کردن ساعت ۳ صبح کاری است که حرفهایهای جدی انجام میدهند. چقدر اشتباه میکردم!
آن کد بارها و بارها به ما ضربه زد. یک ساختار طراحیِ معیوب را پایهگذاری کرد که همه از آن استفاده میکردند، اما مدام مجبور بودند دورش بزنند. انواع خطاهای عجیب زمانبندی و حلقههای بازخورد غریب ایجاد میکرد. وارد حلقههای بینهایت «نامه» میشدیم؛ یک پیام باعث ارسال پیام دیگر میشد و همینطور ادامه پیدا میکرد. هیچوقت «وقت» بازنویسی آن تودهٔ کثیف را نداشتیم (یا اینطور فکر میکردیم)، اما همیشه برای اضافه کردن یک وصله یا زگیل جدید وقت پیدا میشد. این چرک و کثافت مدام رشد میکرد و کدِ ساعت ۳ صبح را با بار اضافی و عوارض جانبی احاطه میکرد. سالها بعد تبدیل به شوخی تیم شد. هر وقت خسته یا کلافه میشدم، میگفتند: «مواظب باشید! باب میخواهد به خودش نامه بفرستد!»
اخلاق این داستان ساده است: وقتی خستهاید، کد ننویسید. تعهد و حرفهایگری بیشتر از آنکه به ساعت کار ربط داشته باشد، به انضباط مربوط است. خواب، سلامتی و سبک زندگیتان را طوری تنظیم کنید که بتوانید روزی هشت ساعتِ واقعاً مفید کار کنید.
تا حالا شده بعد از یک دعوای جدی با همسرتان یا دوستتان بنشینید کدنویسی کنید؟ متوجه شدهاید که یک فرایند پسزمینه در ذهنتان در حال اجراست که سعی میکند دعوا را حل کند یا دستکم مرورش کند؟ گاهی میشود استرس این فرایند پسزمینه را در سینه یا دلتان حس کرد. آدم را مضطرب میکند؛ شبیه حالتی که کافئین زیادی مصرف کرده باشید. حواسپرتکن است.
وقتی نگران دعوایی با همسرم هستم، یا بحران مشتری دارم، یا بچهام بیمار است، نمیتوانم تمرکز کنم. تمرکزم میپرد. خودم را میبینم که چشمهایم به صفحه است و انگشتهایم روی کیبورد، اما هیچ کاری نمیکنم. کاتاتونیک. فلج. کیلومترها دورتر، در حال حلوفصل مشکل پسزمینه، نه حل مسئلهٔ کدی که جلویم است.
گاهی خودم را مجبور میکنم به کد فکر کنم. شاید بتوانم یک خط یا دو خط بنویسم. شاید بتوانم یک یا دو تست را پاس کنم. اما دوام نمیآورد. دیر یا زود به حالت کرختیِ مبهوت فرو میروم؛ چشمها باز، اما چیزی نمیبینم، و در درونم نگرانیِ پسزمینه میچرخد.
یاد گرفتهام که این زمان، زمانِ کدنویسی نیست. هر کدی که تولید کنم آشغال خواهد بود. پس بهجای کدنویسی، باید نگرانی را حل کنم.
البته بسیاری از نگرانیها را نمیشود در یکی دو ساعت حل کرد. ضمن اینکه کارفرماها هم بعید است مدت زیادی ناتوانی ما در کار کردن را به بهانهٔ حل مسائل شخصی تحمل کنند. ترفند این است که یاد بگیرید فرایند پسزمینه را خاموش کنید، یا دستکم اولویتش را پایین بیاورید تا حواسپرتیِ دائمی نباشد.
من این کار را با تقسیمبندی زمان انجام میدهم. بهجای اینکه خودم را مجبور کنم در حالی که نگرانی پسزمینه آزارم میدهد کدنویسی کنم، یک بازهٔ زمانی مشخص—مثلاً یک ساعت—را به مسئلهای اختصاص میدهم که آن نگرانی را ایجاد کرده. اگر بچهام بیمار است، با خانه تماس میگیرم. اگر با همسرم دعوا کردهام، زنگ میزنم و مسئله را صحبت میکنم. اگر مشکل مالی دارم، زمانی را صرف فکر کردن به راههای مواجهه با آن میکنم. میدانم احتمالاً در این یک ساعت مشکل حل نمیشود، اما بسیار محتمل است که اضطراب کم شود و فرایند پسزمینه آرام بگیرد.
در حالت ایدهآل، این زمان باید زمان شخصی باشد. حیف است یک ساعت از وقت اداره را اینگونه خرج کنیم. توسعهدهندگان حرفهای زمان شخصیشان را طوری تنظیم میکنند که زمانِ محل کارشان تا حد ممکن پربازده باشد. یعنی باید عمداً در خانه زمانی را برای آرام کردن نگرانیها کنار بگذارید تا آنها را با خود به محل کار نیاورید.
از سوی دیگر، اگر در محل کار هستید و اضطرابهای پسزمینه بهرهوریتان را میمکند، بهتر است یک ساعت را صرف آرام کردن آنها کنید تا اینکه با زور بنشینید و کدی بنویسید که بعداً مجبور شوید دور بیندازید (یا بدتر از آن، با آن زندگی کنید).
دربارهٔ حالتِ فوقمولدی که به «جریان» یا Flow معروف است، زیاد نوشته شده. بعضی برنامهنویسها به آن میگویند «زون». هر اسمی که داشته باشد، احتمالاً با آن آشنا هستید. حالتی از آگاهی با تمرکز شدید و دیدِ تونلی که برنامهنویسها هنگام کدنویسی به آن میرسند. در این حالت احساس میکنند بسیار مولدند. احساس میکنند خطاناپذیرند. و به همین دلیل دوست دارند به آن حالت برسند و حتی ارزشِ خودشان را با مقدار زمانی که میتوانند در آن بگذرانند بسنجند.
بگذارید یک نکتهٔ کوچک از کسی که رفته و برگشته بگویم: از زون دوری کنید. این حالتِ آگاهی واقعاً فوقمولد نیست و قطعاً خطاناپذیر هم نیست. در حقیقت چیزی شبیه یک حالت مراقبهٔ خفیف است که در آن برخی تواناییهای عقلانی تضعیف میشوند، به نفعِ حسِ سرعت.
بگذارید واضح بگویم. در زون، کد بیشتری مینویسید. اگر TDD تمرین میکنید، حلقهٔ قرمز/سبز/ریفکتور را سریعتر طی میکنید. و احساس سرخوشی خفیف یا حسِ فتح به شما دست میدهد. مشکل اینجاست که در زون، بخشی از تصویرِ بزرگ را از دست میدهید؛ بنابراین احتمالاً تصمیمهایی میگیرید که بعداً مجبور میشوید برگردید و آنها را معکوس کنید. کدی که در زون نوشته میشود شاید سریعتر بیرون بیاید، اما مجبور میشوید بارها به سراغش برگردید.
این روزها وقتی حس میکنم دارم وارد زون میشوم، چند دقیقهای از کار فاصله میگیرم. با جواب دادن به چند ایمیل یا دیدن چند توییت ذهنم را خالی میکنم. اگر نزدیکِ ظهر باشد، برای ناهار وقفه میدهم. اگر تیمی کار میکنم، دنبال یک همجفت (pair) میگردم.
یکی از بزرگترین مزایای برنامهنویسی دونفره این است که تقریباً غیرممکن است یک جفت وارد زون شود. زون حالتی غیرارتباطی است، در حالی که کار دونفره نیازمند ارتباطِ شدید و مداوم است. در واقع یکی از شکایتهایی که اغلب دربارهٔ pairing میشنوم این است که جلوی ورود به زون را میگیرد. عالی است! زون جایی نیست که بخواهید در آن باشید.
خب، این کاملاً هم درست نیست. زمانهایی هست که زون دقیقاً همانجایی است که میخواهید باشید؛ وقتی دارید تمرین میکنید. اما دربارهٔ آن در فصل دیگری صحبت میکنیم.
اواخر دههٔ ۷۰، در تراداین، دفتر خصوصی داشتم. مدیر سیستم PDP 11/60 بودم و به همین دلیل از معدود برنامهنویسهایی بودم که اجازه داشت ترمینال خصوصی داشته باشد. آن ترمینال یک VT100 با سرعت 9600 baud بود که با ۸۰ فوت کابل RS232، از بالای سقف کاذب دفترم تا اتاق کامپیوتر کشیده شده بود.
در دفترم یک سیستم صوتی داشتم؛ صفحهگردان قدیمی، آمپلیفایر و اسپیکرهای ایستاده. مجموعهٔ قابلتوجهی از صفحههای وینیل داشتم؛ از جمله Led Zeppelin، Pink Floyd و… خب، خودتان تصویرش را دارید.
عادت داشتم صدا را تا ته زیاد کنم و کدنویسی کنم. فکر میکردم کمک میکند تمرکز کنم. اما اشتباه میکردم.
یک روز برگشتم سراغ ماژولی که هنگام گوش دادن به آغازِ The Wall رویش کار کرده بودم. کامنتهای کد شامل شعرهای آن قطعه و یادداشتهای تحریری دربارهٔ بمبافکنهای شیرجهرو و نوزادان گریان بود.
آنجا بود که فهمیدم. بهعنوان خوانندهٔ کد، داشتم بیشتر دربارهٔ سلیقهٔ موسیقی نویسنده (خودم) یاد میگرفتم تا دربارهٔ مسئلهای که کد قرار بود حل کند.
فهمیدم که من هنگام گوش دادن به موسیقی خوب کد نمینویسم. موسیقی تمرکزم را زیاد نمیکند؛ بلکه به نظر میرسد گوش دادن به موسیقی بخشی از یک منبع حیاتی ذهنی را مصرف میکند که برای نوشتن کدی تمیز و با طراحی خوب به آن نیاز دارم.
شاید برای شما اینطور نباشد. شاید موسیقی به شما کمک کند کد بنویسید. افراد زیادی را میشناسم که با هدفون کدنویسی میکنند. میپذیرم که موسیقی ممکن است به آنها کمک کند، اما همیشه مشکوکم که آنچه واقعاً اتفاق میافتد این است که موسیقی به آنها کمک میکند وارد زون شوند.
خودتان را هنگام کدنویسی پشت میزتان تصور کنید. وقتی کسی از شما سؤال میپرسد، چه واکنشی نشان میدهید؟ تند میشوید؟ اخم میکنید؟ زبان بدنتان میگوید «برو، سرم شلوغ است»؟ خلاصه، بیادب میشوید؟
یا اینکه کارتان را متوقف میکنید و مؤدبانه به کسی که گیر کرده کمک میکنید؟ همانطور که دوست دارید اگر خودتان گیر کرده بودید با شما رفتار شود؟
رفتارِ بیادبانه اغلب از زون میآید. ممکن است از اینکه از زون بیرون کشیده میشوید ناراحت باشید، یا از اینکه کسی مانع ورودتان به زون میشود. در هر دو حالت، این بیادبی اغلب از رابطهٔ شما با زون ناشی میشود.
البته گاهی مشکل زون نیست؛ بلکه این است که دارید سعی میکنید چیز پیچیدهای را بفهمید که تمرکز میخواهد. برای این وضعیت چند راهحل وجود دارد.
کار دونفره میتواند راه بسیار خوبی برای مدیریت وقفهها باشد. همجفت شما میتواند زمینهٔ ذهنی مسئله را نگه دارد، در حالی که شما به یک تماس تلفنی یا سؤال همکار جواب میدهید. وقتی برمیگردید، او خیلی سریع کمکتان میکند تا زمینهٔ ذهنی قبلی را بازسازی کنید.
TDD هم کمک بزرگی است. اگر یک تستِ failing داشته باشید، آن تست زمینهٔ کاری شما را نگه میدارد. بعد از وقفه میتوانید برگردید و دوباره روی پاس شدن همان تست ادامه دهید.
در نهایت، البته وقفههایی خواهند بود که حواستان را پرت میکنند و وقتتان را میگیرند. وقتی این اتفاق افتاد، یادتان باشد که دفعهٔ بعد شاید شما کسی باشید که مجبور است دیگری را قطع کند. پس نگرش حرفهای یعنی آمادگی مؤدبانه برای کمک کردن.
گاهی کد اصلاً نمیآید. برای خودم پیش آمده و برای دیگران هم دیدهام. پشت میز مینشینید و هیچ اتفاقی نمیافتد.
معمولاً کارهای دیگری پیدا میکنید. ایمیل میخوانید. توییت میخوانید. کتابها، برنامهها یا اسناد را ورق میزنید. جلسه میگذارید. با دیگران وارد گفتگو میشوید. هر کاری میکنید جز اینکه با آن میز کار روبهرو شوید و ببینید کد حاضر نیست ظاهر شود.
چه چیزی باعث این قفلها میشود؟ دربارهٔ خیلی از عواملش قبلاً صحبت کردهایم. برای من، عامل مهم دیگر خواب است. اگر به اندازهٔ کافی نخوابیده باشم، اصلاً نمیتوانم کد بنویسم. عوامل دیگر نگرانی، ترس و افسردگی هستند.
جالب اینجاست که یک راهحل بسیار ساده وجود دارد. تقریباً همیشه جواب میدهد. انجامش آسان است و میتواند شتاب لازم برای نوشتن حجم زیادی کد را به شما بدهد.
راهحل: یک همجفت پیدا کنید.
باورکردنی نیست که چقدر خوب کار میکند. همین که کنار شخص دیگری مینشینید، مسائلی که سد راهتان شده بودند آب میشوند. یک تغییر فیزیولوژیک رخ میدهد وقتی با کسی کار میکنید. نمیدانم دقیقاً چیست، اما کاملاً حسش میکنم. انگار یک تغییر شیمیایی در مغز یا بدنم رخ میدهد که سد را میشکند و دوباره راهم میاندازد.
این راهحل کامل نیست. گاهی این تغییر یک یا دو ساعت دوام دارد و بعدش آنقدر خسته میشوم که مجبورم از همجفتم جدا شوم و جایی برای ریکاوری پیدا کنم. گاهی حتی وقتی کنار کسی نشستهام، کاری از دستم برنمیآید جز اینکه با کار او موافقت کنم. اما برای من، واکنش معمول به pairing، بازگشتِ شتاب است.
کارهای دیگری هم هست که برای جلوگیری از قفل شدن انجام میدهم. مدتها پیش یاد گرفتم که خروجیِ خلاقانه به ورودیِ خلاقانه وابسته است.
خیلی مطالعه میکنم، و از هر جنسی. دربارهٔ نرمافزار، سیاست، زیستشناسی، اخترشناسی، فیزیک، شیمی، ریاضیات و خیلی چیزهای دیگر میخوانم. با این حال، متوجه شدهام چیزی که بیش از همه پمپِ خلاقیت را برایم پر میکند، علمی–تخیلی است.
برای شما شاید چیز دیگری باشد؛ مثلاً یک رمان معمایی خوب، شعر، یا حتی یک رمان عاشقانه. فکر میکنم مسئلهٔ اصلی این است که خلاقیت، خلاقیت میآورد. یک عنصر فرار از واقعیت هم وجود دارد. ساعتهایی که دور از مشکلات معمولم میگذرانم، در حالی که با ایدههای چالشبرانگیز و خلاقانه تحریک میشوم، فشاری تقریباً مقاومتناپذیر برای خلقِ چیزی جدید در من ایجاد میکند.
همهٔ شکلهای ورودی خلاقانه برای من جواب نمیدهد. تماشای تلویزیون معمولاً کمکی به خلق نمیکند. سینما بهتر است، ولی فقط کمی. گوش دادن به موسیقی به من در خلق کد کمک نمیکند، اما در ساخت ارائهها، سخنرانیها و ویدیوها کمککننده است. از میان همهٔ انواع ورودی خلاقانه، هیچچیز برای من بهتر از یک اپرای فضاییِ درستوحسابی نیست.
یکی از بدترین جلسات دیباگ زندگی حرفهایام در سال ۱۹۷۲ رخ داد. ترمینالهای متصل به سیستم حسابداری Teamsters روزی یکی دو بار قفل میکردند. هیچ راهی برای بازتولید این مشکل وجود نداشت. خطا به ترمینال یا برنامهٔ خاصی علاقه نداشت. مهم نبود کاربر قبل از قفل شدن چه کاری انجام میداد. یک لحظه ترمینال کاملاً سالم کار میکرد و لحظهٔ بعد، بهطور ناامیدکنندهای قفل میشد.
تشخیص این مشکل هفتهها طول کشید. در این مدت Teamsters هر روز عصبانیتر میشدند. هر بار که ترمینالی قفل میکرد، کاربرش باید کار را متوقف میکرد و منتظر میماند تا بتوانند همهٔ کاربران دیگر را هماهنگ کنند که کارشان را تمام کنند. بعد به ما زنگ میزدند و ما ریبوت میکردیم. کابوس بود.
چند هفتهٔ اول را صرف جمعآوری داده کردیم؛ با مصاحبه با افرادی که قفل شدن را تجربه کرده بودند. از آنها میپرسیدیم آن لحظه چه میکردند و قبلش چه کرده بودند. از کاربران دیگر میپرسیدیم آیا هنگام قفل شدن چیز خاصی روی ترمینالشان دیدهاند یا نه. همهٔ این مصاحبهها تلفنی بود، چون ترمینالها در مرکز شیکاگو بودند و ما ۳۰ مایل آنطرفتر، وسط زمینهای ذرت کار میکردیم.
لاگ نداشتیم، شمارنده نداشتیم، دیباگر نداشتیم. تنها دسترسی ما به درون سیستم، چراغها و کلیدهای جلوی پنل بود. میتوانستیم کامپیوتر را متوقف کنیم و بعد کلمهبهکلمه حافظه را نگاه کنیم. اما نمیتوانستیم بیش از پنج دقیقه این کار را بکنیم، چون Teamsters سیستمشان را میخواستند.
چند روز وقت گذاشتیم و یک بازرس سادهٔ بلادرنگ نوشتیم که از طریق تلهتایپ ASR-33 (کنسول ما) قابل استفاده بود. با آن میتوانستیم هنگام اجرای سیستم، حافظه را بررسی و دستکاری کنیم. پیامهای لاگ اضافه کردیم که در لحظات حساس روی تلهتایپ چاپ میشد. شمارندههایی در حافظه ساختیم که رویدادها را میشمردند و تاریخچهٔ وضعیت را نگه میداشتند تا با بازرس ببینیمشان. و البته همهٔ اینها باید از صفر با اسمبلی نوشته و شبها—وقتی سیستم در حال استفاده نبود—تست میشد.
ترمینالها وقفهمحور بودند. کاراکترهایی که به ترمینالها ارسال میشدند در بافرهای حلقوی نگه داشته میشدند. هر بار که یک پورت سریال ارسال یک کاراکتر را تمام میکرد، یک وقفه فعال میشد و کاراکتر بعدی از بافر حلقوی آمادهٔ ارسال میشد.
در نهایت فهمیدیم وقتی ترمینالی قفل میکند، به این دلیل است که سه متغیری که بافر حلقوی را مدیریت میکنند از هم ناهمگام شدهاند. نمیدانستیم چرا این اتفاق میافتد، اما دستکم یک سرنخ بود. جایی در آن ۵ هزار خط کد نظارتی، باگی وجود داشت که یکی از آن اشارهگرها را بد مدیریت میکرد.
این دانش جدید اجازه داد ترمینالها را دستی هم از حالت قفل خارج کنیم! میتوانستیم با بازرس، مقادیر پیشفرض را در آن سه متغیر تزریق کنیم و ترمینالها بهطرز جادویی دوباره راه میافتادند. بعداً یک هک کوچک نوشتیم که همهٔ شمارندهها را بررسی میکرد و اگر ناهمراستا بودند، تعمیرشان میکرد. اول هر وقت Teamsters تماس میگرفتند و قفل شدن را گزارش میدادند، این هک را با زدن یک کلید وقفهٔ مخصوص روی پنل اجرا میکردیم. بعدتر، آن ابزار تعمیر را هر ثانیه یکبار اجرا میکردیم.
حدود یک ماه بعد، از نظر Teamsters مشکل قفل شدن تمام شده بود. گاهی یکی از ترمینالها نیمثانیه مکث میکرد، اما با نرخ پایهٔ ۳۰ کاراکتر در ثانیه، کسی متوجه نمیشد.
اما چرا شمارندهها از هم میپاشیدند؟ من نوزده ساله بودم و مصمم که بفهمم.
کد نظارتی را ریچارد نوشته بود که بعداً رفته بود دانشگاه. هیچکدام از ما با آن کد آشنا نبودیم، چون ریچارد نسبت به آن بسیار مالکانه رفتار میکرد. آن کد مالِ خودش بود و ما اجازه نداشتیم بشناسیمش. اما حالا ریچارد رفته بود، پس لیستینگِ چنداینچی را بیرون آوردم و صفحهبهصفحه شروع به خواندنش کردم.
صفهای حلقوی در آن سیستم در واقع ساختارهای FIFO بودند—یعنی صف. برنامههای کاربردی کاراکترها را از یک سر صف وارد میکردند تا صف پر شود. روتینهای وقفه، کاراکترها را از سر دیگر صف بیرون میکشیدند وقتی چاپگر آماده بود. وقتی صف خالی میشد، چاپگر میایستاد. باگ ما باعث میشد برنامهها فکر کنند صف پر است، اما روتینهای وقفه فکر میکردند صف خالی است.
روتینهای وقفه در «ریسمان» متفاوتی از بقیهٔ کد اجرا میشوند. بنابراین شمارندهها و متغیرهایی که هم توسط وقفهها و هم توسط کد عادی دستکاری میشوند باید در برابر بهروزرسانی همزمان محافظت شوند. در مورد ما، این یعنی باید قبل از هر کدی که آن سه متغیر را دستکاری میکند، وقفهها را غیرفعال میکردیم. وقتی پشت آن کد نشستم، میدانستم دنبال جایی میگردم که یکی از متغیرها را دستکاری کرده، بدون اینکه اول وقفهها را خاموش کند.
امروزه، البته، از انبوه ابزارهای قدرتمند برای پیدا کردن همهٔ جاهایی که کد به آن متغیرها دست میزند استفاده میکنیم. در چند ثانیه میدانستیم کدام خطوط به آنها دست میزنند. در چند دقیقه میفهمیدیم کدامشان وقفهها را غیرفعال نکردهاند. اما این سال ۱۹۷۲ بود و من هیچکدام از آن ابزارها را نداشتم. چیزی که داشتم، چشمهایم بود.
تمام صفحات کد را موشکافانه بررسی کردم و دنبال آن متغیرها گشتم. متأسفانه تقریباً همهجا استفاده شده بودند. تقریباً هر صفحه به شکلی به آنها دست میزد. بسیاری از این ارجاعات وقفهها را خاموش نمیکردند، چون فقط خواندنی بودند و بیخطر. مشکل این بود که در آن اسمبلی خاص، راه خوبی وجود نداشت که بدون دنبال کردن منطق کد بفهمید یک ارجاع فقط خواندنی است یا نه. هر بار که متغیری خوانده میشد، ممکن بود بعداً بهروزرسانی و ذخیره شود. و اگر این کار در حالی انجام میشد که وقفهها فعال بودند، متغیرها میتوانستند خراب شوند.
روزها مطالعهٔ فشرده طول کشید، اما در نهایت پیدایش کردم. آنجا، وسط کد، یک نقطه بود که یکی از آن سه متغیر در حالی بهروزرسانی میشد که وقفهها فعال بودند.
حساب کردم. پنجرهٔ آسیبپذیری حدود دو میکروثانیه طول داشت. دوازده ترمینال با سرعت ۳۰ کاراکتر در ثانیه فعال بودند، یعنی تقریباً هر ۳ میلیثانیه یک وقفه. با توجه به اندازهٔ کد نظارتی و سرعت کلاک CPU، انتظار داشتیم این آسیبپذیری روزی یک یا دو بار به قفل شدن منجر شود. بینگـو!
مشکل را برطرف کردم، البته. اما هیچوقت جرئت نکردم هکِ خودکاری را که شمارندهها را بررسی و تعمیر میکرد خاموش کنم. تا امروز هم مطمئن نیستم که جایِ خالیِ دیگری وجود نداشته باشد.
بهدلایلی عجیب، توسعهدهندگان نرمافزار معمولاً زمان دیباگ را «زمان کدنویسی» حساب نمیکنند. دیباگ را چیزی شبیه یک ضرورت طبیعی میبینند؛ کاری که «بالاخره باید انجام شود». اما زمان دیباگ از نظر کسبوکار دقیقاً بهاندازهٔ زمان کدنویسی هزینه دارد. بنابراین هر کاری که بتواند این زمان را حذف یا کم کند، کارِ درستی است.
امروزه من خیلی کمتر از ده سال پیش دیباگ میکنم. اندازهگیری دقیقی ندارم، اما فکر میکنم حدود ده برابر کمتر شده. این کاهشِ واقعاً چشمگیر را با پذیرش روش توسعهٔ مبتنی بر تست (TDD) به دست آوردم—که در فصل دیگری دربارهاش صحبت خواهیم کرد.
چه TDD را انتخاب کنید چه هر انضباط دیگری با کارایی مشابه، بهعنوان یک حرفهای وظیفه دارید زمان دیباگ را تا جایی که میتوانید به صفر نزدیک کنید. صفر، البته، هدفی حدی است؛ هرگز دقیقاً به آن نمیرسید، اما هدف همچنان صفر است.
پزشکها دوست ندارند بیمار را دوباره باز کنند تا اشتباهشان را اصلاح کنند. وکلا دوست ندارند پروندهای را که خراب کردهاند دوباره محاکمه کنند. پزشکی یا وکیلی که زیاد این کار را بکند، حرفهای تلقی نمیشود. به همان قیاس، برنامهنویسی که باگهای زیادی تولید میکند، رفتاری غیرحرفهای دارد.
توسعهٔ نرمافزار دوی ماراتن است، نه دوی سرعت. مسابقه را با دویدنِ تمامقد از همان ابتدا نمیبری. با حفظ منابع و تنظیم سرعت میبری. یک دوندهٔ ماراتن قبل و حین مسابقه از بدنش مراقبت میکند. برنامهنویسان حرفهای هم با همان دقت از انرژی و خلاقیتشان محافظت میکنند.
«تا حلش نکنی حق نداری بری خونه!»؟ چرا، حق داری—و احتمالاً باید بروی!
خلاقیت و هوش حالتهای زودگذر ذهنیاند. وقتی خستهای، ناپدید میشوند. اگر بعدش ساعتها مغزِ ازکارافتادهات را بکوبی تا مسئلهای را حل کنی، فقط خودت را خستهتر میکنی و احتمال اینکه زیر دوش یا پشت فرمان راهحل به ذهنت برسد را کمتر میکنی.
وقتی گیر کردهای، وقتی خستهای، مدتی فاصله بگیر. به ضمیر ناخودآگاه خلاقات فرصت بده. اگر منابعات را عاقلانه مدیریت کنی، در زمان کمتر و با تلاش کمتر کار بیشتری انجام میدهی. سرعت خودت و تیمت را تنظیم کن. الگوهای خلاقیت و درخشش خودت را بشناس و از آنها بهره بگیر، نه اینکه برخلافشان حرکت کنی.
یکی از جاهایی که تعداد زیادی مسئله را حل کردهام، ماشین است؛ در مسیر برگشت از کار. رانندگی مقدار زیادی از منابع ذهنیِ غیرخلاق را مصرف میکند. چشمها، دستها و بخشی از ذهنت باید صرف رانندگی شود؛ بنابراین ناچار میشوی از مسائل کاری جدا شوی. در این «جداشدن» چیزی هست که به ذهن اجازه میدهد به شکلی متفاوت و خلاقانهتر دنبال راهحل بگردد.
تعداد غیرمنطقیای از مسائل را زیر دوش حل کردهام. شاید پاشش آبِ صبح زود بیدارم میکند و باعث میشود همهٔ راهحلهایی را مرور کنم که مغزم هنگام خواب ساخته است.
وقتی روی مسئلهای کار میکنی، گاهی آنقدر به آن نزدیک میشوی که دیگر گزینهها را نمیبینی. راهحلهای ظریف را از دست میدهی، چون بخش خلاق ذهنت زیر فشار تمرکز شدید سرکوب شده است. گاهی بهترین راه حل یک مسئله این است که بروی خانه، شام بخوری، تلویزیون ببینی، بخوابی، و صبح فردا زیر دوش بایستی.
دیر میشوی. برای بهترینِ ما هم پیش میآید. برای متعهدترینِ ما هم پیش میآید. گاهی تخمینها را خراب میکنیم و دیر میرسیم.
ترفندِ مدیریتِ دیر شدن، تشخیص زودهنگام و شفافیت کامل است. بدترین سناریو این است که تا آخرین لحظه به همه بگویی سر وقت میرسی—و بعد همه را ناامید کنی. این کار را نکن.
در عوض، مرتب پیشرفتت را نسبت به هدف بسنج و سه تاریخِ مبتنی بر واقعیت ارائه بده: بهترین حالت، حالت معمول، و بدترین حالت. تا جایی که میتوانی دربارهٔ هر سه صادق باش. امید را وارد تخمین نکن!
هر سه عدد را به تیم و ذینفعان ارائه بده و هر روز بهروزشان کن.
اگر این اعداد نشان بدهند که ممکن است به ددلاین نرسی چه؟ فرض کن ده روز دیگر نمایشگاه داریم و باید محصول آنجا باشد. اما تخمین سهگانهٔ تو برای فیچری که رویش کار میکنی این است: ۸ / ۱۲ / ۲۰ روز.
امیدوار نباش که در ده روز تمام میشود! امید قاتل پروژه است. امید برنامهها را نابود میکند و اعتبارها را میسوزاند. امید تو را به دردسر جدی میاندازد.
اگر نمایشگاه ده روز دیگر است و تخمین معمول تو ۱۲ روز است، نمیرسی. مطمئن شو تیم و ذینفعان وضعیت را میفهمند و تا وقتی یک برنامهٔ جایگزین ندارید، کوتاه نیا. نگذار هیچکس امیدوار بماند.
اگر مدیرت تو را بنشاند و بگوید «سعی کن به ددلاین برسی» چه؟ اگر اصرار کند «هر کاری لازم است بکن»؟ به تخمینهایت پایبند بمان.
تخمین اولیهٔ تو دقیقتر از هر تغییری است که زیر فشار مدیر ایجاد میکنی. به او بگو گزینهها را قبلاً بررسی کردهای (چون کردهای) و تنها راه بهبود زمانبندی، کاهش دامنهٔ کار است. وسوسهٔ عجله را نپذیر.
وای به حال برنامهنویسی که زیر فشار میشکند و قبول میکند «سعی کند» به ددلاین برسد. او شروع میکند به میانبُر زدن و اضافهکاری، با امید واهی به معجزه. این نسخهٔ قطعیِ فاجعه است، چون به تو، تیم و ذینفعان امیدِ دروغین میدهد و تصمیمهای سختِ لازم را عقب میاندازد.
راهی برای عجله وجود ندارد. نمیتوانی خودت را وادار کنی سریعتر کد بزنی. نمیتوانی خودت را وادار کنی سریعتر مسئله حل کنی. اگر تلاش کنی، فقط کندتر میشوی و گندی میزنی که بقیه را هم کند میکند.
پس باید با محروم کردن دیگران از امید پاسخ بدهی.
حالا رئیست میگوید: «اگر روزی دو ساعت بیشتر کار کنی چی؟ شنبه بیای چی؟ بالاخره باید راهی باشد.»
اضافهکاری گاهی جواب میدهد و گاهی لازم است. گاهی میشود با چند روز دهساعته و یکی دو شنبه، به تاریخی رسید که در حالت عادی ناممکن است. اما این کار بسیار پرریسک است. بعید است با ۲۰٪ ساعت بیشتر، ۲۰٪ کار بیشتر تحویل بدهی. بدتر اینکه اگر بیش از دو یا سه هفته طول بکشد، تقریباً قطعاً شکست میخورد.
پس فقط وقتی با اضافهکاری موافقت کن که:
- شخصاً توانش را داشته باشی،
- کوتاهمدت باشد (حداکثر دو هفته)،
- مدیرت یک برنامهٔ جایگزین در صورت شکست داشته باشد.
شرط سوم خط قرمز است. اگر مدیرت نتواند بگوید در صورت شکست اضافهکاری چه خواهد کرد، نباید با آن موافقت کنی.
از میان همهٔ رفتارهای غیرحرفهای، شاید بدترینشان این باشد که بگویی «تمام شد» در حالی که خودت میدانی تمام نشده. گاهی این یک دروغ آشکار است—و همانقدر بد. اما حالت موذیانهتر زمانی است که تعریف جدیدی از «تمامشده» برای خودت میسازی. خودت را قانع میکنی که «بهاندازهٔ کافی تمام شده» و میروی سراغ کار بعدی، با این توجیه که باقیاش را بعداً درست میکنی.
این رفتار مسری است. اگر یک نفر انجامش بدهد، بقیه هم میبینند و تقلید میکنند. یکی تعریف «تمامشده» را کمی بیشتر میکشد، بقیه هم همان را میپذیرند. من این را به شکلهای وحشتناک دیدهام. یکی از مشتریانم «تمامشده» را برابر با «کامیتشده» تعریف کرده بود. حتی لازم نبود کد کامپایل شود! وقتی هیچچیز نباید کار کند، «تمام شدن» خیلی آسان است.
وقتی تیم به این دام میافتد، مدیران گزارشهایی میشنوند که همهچیز عالی پیش میرود. همه سر وقتاند. مثل آدمهای کوری که روی ریل قطار پیکنیک گرفتهاند: هیچکس قطارِ باریِ کارهای نیمهتمام را نمیبیند تا وقتی که خیلی دیر شده.
برای جلوگیری از تحویل دروغین، یک تعریف مستقل از «تمامشده» بسازید. بهترین راه این است که تحلیلگران کسبوکار و تسترها تستهای پذیرش خودکار بنویسند که قبل از اعلام «تمام شد» باید پاس شوند. این تستها باید با زبانی مثل FitNesse، Selenium، RobotFX، Cucumber و امثال آن نوشته شوند؛ برای ذینفعان قابل فهم باشند و مرتب اجرا شوند.
برنامهنویسی سخت است. هرچه جوانتر باشی، کمتر این را باور میکنی. بالاخره فقط چند if و while است. اما با تجربه میفهمی که ترکیبِ درستِ همین if و whileها چقدر حیاتی است. نمیشود آنها را شلخته به هم چسباند و امید داشت درست دربیاید. باید سیستم را با دقت به واحدهای کوچک و قابلفهم تقسیم کنی که کمترین وابستگی را به هم داشته باشند—و این کار سخت است.
برنامهنویسی آنقدر سخت است که عملاً از توان یک نفر خارج است. هرچقدر هم ماهر باشی، قطعاً از افکار و ایدههای یک برنامهنویس دیگر سود میبری.
به همین دلیل، وظیفهٔ برنامهنویسهاست که در دسترس هم باشند. پنهان شدن در اتاق یا کیوبیکل و رد کردن سؤالهای دیگران، نقض اخلاق حرفهای است. کار تو آنقدر مهم نیست که نتوانی زمانی برای کمک به دیگران بگذاری. در واقع، بهعنوان یک حرفهای، موظفی هر وقت نیاز شد این کمک را ارائه بدهی.
این به آن معنا نیست که به زمان تنهایی نیاز نداری. داری، قطعاً. اما باید منصف و مؤدب باشی. مثلاً میتوانی اعلام کنی که از ۱۰ تا ۱۲ نباید مزاحمت شد، اما از ۱ تا ۳ درت باز است.
به وضعیت همتیمیهایت توجه کن. اگر کسی را دیدی که به نظر در دردسر است، پیشنهاد کمک بده. احتمالاً از تأثیر عمیق کمکت شگفتزده میشوی. نه اینکه تو خیلی باهوشتر باشی؛ فقط یک دید تازه میتواند کاتالیزور قدرتمندی برای حل مسئله باشد.
وقتی به کسی کمک میکنی، بنشینید و با هم کد بزنید. آماده باش حداقل یک ساعت یا بیشتر وقت بگذاری. شاید زودتر تمام شود، اما نباید عجول به نظر برسی. خودت را وقف کار کن و جدی تلاش کن. بهاحتمال زیاد، در پایان بیشتر از آنچه دادهای یاد گرفتهای.
وقتی کسی به شما پیشنهاد کمک میدهد، با روی خوش بپذیرید. با قدردانی کمک را قبول کنید و خودتان را به آن بسپارید. از قلمرو خودتان دفاع نکنید. کمک را فقط به این دلیل که زیر فشار هستید، پس نزنید. حدود سی دقیقه به آن فرصت بدهید. اگر بعد از این مدت دیدید که کمک چندان مؤثر نیست، مؤدبانه عذرخواهی کنید و جلسه را با تشکر تمام کنید. یادتان باشد همانطور که از نظر اخلاق حرفهای موظفید کمک ارائه دهید، به همان اندازه هم موظفید کمک را بپذیرید.
یاد بگیرید چطور درخواست کمک کنید. وقتی گیر کردهاید، گیج شدهاید، یا ذهنتان بهکلی دور مسئله میچرخد و جلو نمیرود، از کسی کمک بخواهید. اگر در اتاق تیم نشستهاید، کافی است کمی به عقب تکیه بدهید و بگویید: «کمک لازم دارم.» اگر نه، از یامر، توییتر، ایمیل، یا تلفن روی میزتان استفاده کنید. درخواست کمک بدهید. باز هم این موضوع به اخلاق حرفهای برمیگردد. غیرحرفهای است که وقتی کمک بهسادگی در دسترس است، در بنبست بمانید.
تا اینجا شاید انتظار داشته باشید ناگهان سرود کومبایا سر بدهم، خرگوشهای پشمالو روی پشت اسبهای تکشاخ بپرند و همه با هم بر فراز رنگینکمانهای امید و تغییر پرواز کنیم. نه، دقیقاً اینطور نیست. واقعیت این است که برنامهنویسها اغلب متکبر، خودمحور و درونگرا هستند. ما وارد این حرفه نشدیم چون عاشق آدمها هستیم. بیشترِ ما برنامهنویسی را انتخاب کردیم چون ترجیح میدهیم عمیقاً روی جزئیات استریل تمرکز کنیم، همزمان چندین مفهوم را در هوا نگه داریم، و در کل به خودمان ثابت کنیم که مغزی در اندازهٔ یک سیاره داریم—آن هم بدون اینکه مجبور شویم با پیچیدگیهای کثیفِ آدمها سروکار داشته باشیم.
بله، این یک کلیشه است. بله، تعمیمی است با استثناهای فراوان. اما واقعیت این است که برنامهنویسها معمولاً اهل همکاری نیستند. و در عین حال، همکاری برای برنامهنویسی مؤثر حیاتی است. بنابراین، چون برای بسیاری از ما همکاری غریزی نیست، به انضباطهایی نیاز داریم که ما را وادار به همکاری کند.
بعدتر در این کتاب یک فصل کامل را به این موضوع اختصاص دادهام. فعلاً بگذارید فقط این را بگویم: آموزش برنامهنویسان کمتجربهتر، مسئولیت کسانی است که تجربهٔ بیشتری دارند. دورههای آموزشی کافی نیستند. کتابها هم کافی نیستند. هیچچیز نمیتواند یک توسعهدهندهٔ جوان را سریعتر از انگیزهٔ درونی خودش و منتورینگ مؤثرِ ارشدها به سطح عملکرد بالا برساند.
بنابراین، یکبار دیگر، این هم مسئلهای از اخلاق حرفهای است: برنامهنویسان ارشد وظیفه دارند بخشی از وقت خود را صرف حمایت از برنامهنویسان جوانتر و منتورینگ آنها کنند. و به همان نسبت، برنامهنویسان جوانتر هم وظیفهٔ حرفهای دارند که فعالانه به دنبال چنین منتورینگی از ارشدهای خود بروند.
- [Martin09]: Robert C. Martin، Clean Code، انتشارات Prentice Hall، ۲۰۰۹
- [Martin03]: Robert C. Martin، Agile Software Development: Principles, Patterns, and Practices، انتشارات Prentice Hall، ۲۰۰۳