فصل ۳ - ابزارهای پایه
هر سازندهای مسیرش را با یک مجموعه ابزار باکیفیت آغاز میکند. یک نجّار شاید به خطکش، گیج، چند اره، رندههای خوب، اسکنههای ظریف، دریل و گیره، چکشهای چوبی و انواع گیرهها نیاز داشته باشد. این ابزارها با دقت انتخاب میشوند، برای دوام ساخته شدهاند، هرکدام وظیفهای مشخص دارند و با دیگری کمترین همپوشانی را ایجاد میکنند، و شاید مهمتر از همه، در دستهای نجار تازهکار «درست» مینشینند.
از همینجا روند یادگیری و سازگار شدن آغاز میشود. هر ابزار شخصیت و癖ِ خودش را دارد و به نوع خاصی از نگهداشتن و استفاده نیازمند است. هرکدام باید به شیوهٔ مخصوص خود تیز شوند یا در زاویهای خاص قرار بگیرند. با گذر زمان و بر اثر استفاده، هر ابزار تغییر میکند؛ دستهٔ آن کمکم شبیه قالب دستهای نجار میشود و لبهٔ برندهاش دقیقاً با زاویهای هماهنگ میشود که ابزار در آن نگه داشته میشود. در این مرحله ابزار تبدیل میشود به یک گذرگاه—رابطی میان مغز سازنده تا محصول نهایی؛ گویی تبدیل به امتداد دستهای او شدهاند. با گذشت زمان، نجار ابزارهای تازهای هم اضافه میکند؛ از دستگاههای برش بیسکویت تا اور فرزهای لیزری و گیرههای اتصالِ دمچلچله—همه ابزارهایی مدرن و شگفتانگیز. اما مطمئن باش که او همچنان بیشترین لذت را از همان ابزارهای اولیه میبرد؛ همان لحظهای که رنده را روی چوب میلغزاند و صدای «خواندن» آن را میشنود.
ابزارها استعدادت را تقویت میکنند. هرچه ابزارهایت بهتر باشد، و هرچه بهتر بدانی چگونه باید از آنها استفاده کرد، بهرهوریات بیشتر میشود. با یک مجموعه ابزار عمومی و پایه شروع کن. هرچه تجربهات بیشتر شود و به نیازهای خاصتری برخورد کنی، ابزارهای تازهای اضافه خواهی کرد. درست مانند یک سازنده، انتظار داشته باش که جعبه ابزارت دائماً در حال رشد باشد. همیشه گوشبهزنگ راههای بهتر انجام کارها باش. اگر جایی احساس کردی ابزارهای فعلیات کم میآورند، یادداشتی بگذار و در جستوجوی تجهیزات بهتر یا توانمندتر باش. نیاز باید موتور انتخابهایت باشد.
بسیاری از برنامهنویسان تازهکار اشتباه میکنند و از همان اول به یک «ابزار قدرتمند» مثل یک محیط توسعهٔ یکپارچه (IDE) میچسبند و هرگز از محیط امنش بیرون نمیآیند. این کار اشتباه است. باید بتوانی فراتر از محدودیتهای یک IDE راحت باشی. تنها راهش این است که مجموعه ابزارهای پایهات را همیشه تیز و آماده نگه داری.
در این فصل دربارهٔ سرمایهگذاری روی جعبهابزار شخصیات صحبت میکنیم. مانند هر بحث خوبی دربارهٔ ابزار، اول از مواد خام شروع میکنیم—چیزی که قرار است شکلش بدهی. در موضوع ۱۶، «قدرت متن ساده»، به همین موضوع میپردازیم. از آنجا به سراغ میزکار میرویم؛ یعنی کامپیوتر. چطور میتوانی بیشترین بهره را از این میزکار ببری؟ این را در موضوع ۱۷، «بازیهای شِل»، بررسی میکنیم. حالا که مواد اولیه و میزکار داریم، به سراغ ابزاری میرویم که احتمالاً بیشتر از هر چیز دیگر از آن استفاده میکنی: ویرایشگرت. در موضوع ۱۸، «ویرایش قدرتمند»، راههایی برای افزایش کارآمدی پیشنهاد میکنیم.
برای اینکه هیچگاه کار ارزشمندمان را از دست ندهیم، همیشه باید از یک «سامانهٔ کنترل نسخه» استفاده کنیم—حتی برای چیزهای شخصی مثل دستور پخت یا یادداشتها. این موضوع را در ۱۹ بررسی میکنیم. و از آنجا که «مورفی» خوشبین بود، هیچکس برنامهنویس خوبی نمیشود مگر اینکه در موضوع ۲۰، یعنی «اشکالزدایی»، مهارت ویژهای پیدا کند.
برای بههم چسباندن بخشهای مختلف این جادو، کمی «چسب» لازم است. در موضوع ۲۱، «پردازش متن»، چند امکان را بررسی میکنیم. و در پایان، ضعیفترین جوهر هم بهتر از قویترین حافظه است. افکار و تاریخچهٔ کارت را ثبت کن. این را در موضوع ۲۲، «دفترچهٔ مهندسی»، توضیح میدهیم.
وقتی زمان کافی برای یادگیری این ابزارها بگذاری، ناگهان روزی میبینی انگشتهایت روی صفحهکلید میچرخند و متن را بیآنکه حتی آگاهانه فکر کنی جابهجا و ویرایش میکنی. ابزارها تبدیل شدهاند به امتداد دستهایت.
موضوع ۱۶ قدرتِ متنِ ساده
برای ما، بهعنوان برنامهنویسان پراگماتیک، مادّهٔ اولیه نه چوب است و نه آهن؛ مادّهٔ ما «دانش» است. ما نیازها را بهصورت دانش گردآوری میکنیم و بعد همان دانش را در طراحیها، پیادهسازیها، آزمایشها و اسناد منتقل میکنیم. و باور داریم بهترین قالب برای ذخیرهٔ پایدار دانش، «متن ساده» است. با متن ساده، این توان را به خود میدهیم که دانش را—چه بهصورت دستی و چه برنامهوار—با تقریباً هر ابزاری که در اختیار داریم دستکاری کنیم.
مشکل بیشتر قالبهای دودویی این است که زمینهٔ لازم برای فهم داده از خود داده جداست. انگار داده را از معنایش جدا میکنی. داده تقریباً مثل رمزگذاری شده است؛ بدون منطق برنامهٔ سازندهاش هیچ معنایی ندارد. اما با متن ساده میتوان جریان دادهای خودتوصیفگر ایجاد کرد؛ جریانی مستقل از برنامهای که آن را ساخته است.
متن ساده چیست؟
متن ساده از کاراکترهای قابلچاپ ساخته میشود و باید اطلاعات منتقل کند. میتواند به اندازهٔ یک فهرست خرید ساده باشد:
- شیر
- کاهو
- قهوه
یا به اندازهٔ متنِ همین کتاب پیچیده—بله، منبع این کتاب کاملاً متن ساده است، البته به ناراحتی ناشر که دوست داشت از یک نرمافزار واژهپرداز استفاده کنیم.
بخش «اطلاعات» در متن ساده اهمیت دارد. اینها متن سادهٔ مفید نیستند:
hlj;uijn bfjxrrctvh jkni'pio6p7gu;vh bjxrdi5rgvhj
این هم نیست:
Field19=467abe
خواننده هیچچیزی دربارهٔ معنای 467abe نمیفهمد. متن ساده باید برای انسان قابلفهم باشد.
نکته ۲۵
دانش را در قالب متن ساده نگه دار.
قدرتِ متن
متن ساده به این معنی نیست که بیساختار باشد؛ HTML، JSON، YAML و موارد مشابه، همگی متن سادهاند. بسیاری از پروتکلهای بنیادی اینترنت هم همینطور—HTTP، SMTP، IMAP و غیره. دلیلهای خوبی هم دارد:
- بیمه در برابر فرسودگی و منسوخ شدن
- امکان استفاده از ابزارهای آماده
- آزمونپذیری آسانتر
بیمه در برابر منسوخ شدن
دادههای انسانیخوان و خودتوصیفگر بیشتر از هر شکل دیگری از داده و بیشتر از برنامههایی که آن را ایجاد کردهاند عمر میکنند—بیهیچ شوخی. تا زمانی که خود داده باقی بماند، احتمال زیادی هست که بتوانی آن را استفاده کنی؛ حتی مدتها بعد از اینکه برنامهٔ اصلی از میان رفته باشد.
در چنین قالبهایی میتوان حتی با دانشی ناقص از ساختار فایل، داده را تجزیه کرد؛ اما در بیشتر فایلهای دودویی باید تمام جزئیات ساختار را بدانی تا بتوانی آن را بخوانی.
فرض کن یک فایل داده از یک سیستم قدیمی به تو دادهاند. اطلاعات زیادی از برنامهٔ اصلی نداری؛ تنها چیزی که برایت مهم است این است که در این فایل، فهرستی از شمارههای بیمهٔ اجتماعی (SSN) وجود دارد و باید آنها را پیدا و استخراج کنی. میان دادهها، اینها را میبینی:
<FIELD10>123-45-6789</FIELD10>
...
<FIELD10>567-89-0123</FIELD10>
...
<FIELD10>901-23-4567</FIELD10>
بهمحض دیدن شکل شمارهٔ بیمهٔ اجتماعی، میتوانی برنامهای کوچک برای استخراجشان بنویسی—حتی اگر هیچچیز دیگری دربارهٔ فایل ندانی.
اما تصور کن داده اینطور بود:
AC27123456789B11P
...
XY43567890123QTYL
...
6T2190123456788AM
در این حالت احتمالاً اصلاً متوجه اهمیت اعداد نمیشدی. این تفاوت میان «قابلخواندن برای انسان» و «قابلفهم برای انسان» است.
اتفاقاً FIELD10 هم کمکی نمیکند. چیزی مثل:
<SOCIAL-SECURITY-NO>123-45-6789</SOCIAL-SECURITY-NO>
کار را بدیهی میکند—و تضمین میکند که داده، عمر پروژه را پشتسر خواهد گذاشت.
بهرهبرداری
تقریباً هر ابزار در جهان کامپیوتر—از سیستمهای کنترل نسخه گرفته تا ویرایشگرها و ابزارهای خط فرمان—میتواند با متن ساده کار کند.
فلسفهٔ یونیکس
یونیکس با فلسفهٔ ابزارهای کوچک و تیز طراحی شده است؛ ابزارهایی که هرکدام یک کار را خوب انجام میدهند. این فلسفه با یک قالب مشترک ممکن شده: فایلهای متنیِ خطمحور. بسیاری از پایگاههای دادهٔ سیستمی—کاربران، گذرواژهها، تنظیمات شبکه و…—همگی در همین قالب نگهداری میشوند.
وقتی سیستم دچار مشکل میشود و تنها یک محیط حداقلی برای بازیابی در اختیار داری، نبودِ رابطهای گرافیکی ناگهان ارزش «متن ساده» را روشن میکند.
متن ساده همچنین جستوجو را آسان میکند. اگر یادت نیست کدام فایل تنظیمات وظیفهٔ تهیهٔ پشتیبان را انجام میدهد، یک grep -r backup /etc کافی است.
مثلاً اگر یک نصبِ تولیدیِ بزرگ با فایل پیکربندی پیچیده داری و این فایل متنی است، میتوانی آن را زیر کنترل نسخه ببری (موضوع ۱۹: کنترل نسخه). ابزارهایی مثل diff و fc میتوانند تغییرات را نشان بدهند و sum برای تولید چکسام بهکار میآید تا از فساد یا تغییر مخرب جلوگیری کنی.
آزمون آسانتر
اگر دادهٔ مصنوعی برای تست سیستم را به صورت متن ساده بسازی، اضافه و اصلاحکردن یا تغییر آن بدون نیاز به هیچ ابزار ویژهای ممکن است. خروجی متنی از آزمونهای پسرفت نیز بهآسانی با ابزارهای شِل یا اسکریپتهای کوچک قابلتحلیل است.
کمترین مخرج مشترک
حتی در آیندهای که عاملهای هوشمند مبتنی بر بلاکچین در اینترنت پرهیاهو سرگرداناند و خودشان مذاکره و تبادل داده میکنند، فایل متنی همچنان پابرجاست. در محیطهای ناهمگون، مزایای متن ساده ممکن است از همهٔ کمبودهایش مهمتر باشد. باید مطمئن شد همهٔ طرفها بتوانند با یک استاندارد مشترک ارتباط برقرار کنند. متن ساده همان استاندارد است.
بخشهای مرتبط
موضوع ۱۷: بازیهای شِل
موضوع ۲۱: دستکاری متن
موضوع ۳۲: پیکربندی
چالشها
یک پایگاهدادهٔ کوچک دفترچهٔ آدرس بساز (نام، شمارهٔ تلفن و…) با استفاده از یک نمایش دودویی ساده در زبان دلخواهت. این کار را قبل از خواندن ادامهٔ چالش انجام بده.
حال همان قالب را با استفاده از XML یا JSON به شکل متن ساده ترجمه کن.
برای هر نسخه، یک فیلد جدید با طول متغیر به نام directions اضافه کن؛ جایی برای نوشتن نشانی یا مسیر رسیدن به خانهٔ هر شخص.
به مشکلات نسخهبندی و توسعهپذیری توجه کن. تغییر در کدام قالب آسانتر است؟ تبدیل دادههای موجود چطور؟
موضوع ۱۷ بازیهای شِل
هر نجّاری به یک میزکارِ محکم، قابلاعتماد و درستحسابی نیاز دارد؛ جایی که بتواند قطعات کار را در ارتفاع مناسب نگه دارد تا شکلشان بدهد. میزکار تبدیل میشود به مرکز کارگاه، جایی که سازنده بارها و بارها به آن برمیگردد تا قطعه کمکم شکل نهایی بگیرد.
برای برنامهنویسی که با فایلهای متنی کار میکند، آن میزکار همان command shell است. از خط فرمان میتوان کل مجموعه ابزارها را فراخواند، و با کمک pipe ها آنها را به روشهایی ترکیب کرد که احتمالاً سازندگان اصلی ابزار هرگز تصورش را هم نمیکردند. از شِل میتوان برنامهها، دیباگرها، مرورگرها، ویرایشگرها و ابزارهای گوناگون را اجرا کرد. میتوان فایل جستوجو کرد، وضعیت سیستم را پرسید، خروجیها را فیلتر کرد. و با برنامهنویسی شِل، میتوان برای کارهای پرتکرار، ماکروهای پیچیده ساخت.
برای برنامهنویسانی که با رابطهای گرافیکی و IDEها بزرگ شدهاند، این حرف شاید کمی افراطی بهنظر برسد. مگر نمیتوان همهچیز را با کلیک کردن انجام داد؟
پاسخ کوتاه «نه» است. رابطهای گرافیکی عالیاند و برای برخی کارهای ساده حتی سریعتر و راحتتر هم هستند. جابهجایی فایلها، خواندن و نوشتن ایمیل، یا ساخت و استقرار پروژه شاید در محیط گرافیکی خوشدستتر باشد. اما اگر همهٔ کارهایت را با GUI انجام دهی، بخش عظیمی از توان محیط کارت را از دست میدهی. نمیتوانی کارهای پرتکرار را خودکار کنی، یا از قدرت واقعی ابزارهای موجود بهره ببری. و هیچوقت نمیتوانی ابزارها را ترکیب کنی تا یک ابزار سفارشیشدهٔ مخصوص خودت بسازی.
مزیت GUI این است که WYSIWYG است—آنچه میبینی همان چیزی است که میگیری. اما عیبش هم WYSIAYG است—آنچه میبینی تمام چیزی است که میگیری.
محیطهای گرافیکی معمولاً محدود به امکاناتی هستند که طراحشان در نظر گرفته. اگر نیاز داشته باشی از مدل فکری طراح جلوتر بروی، در اکثر مواقع شانس زیادی نداری—و اغلب واقعاً نیاز داری از آن مدل فراتر بروی. برنامهنویس پراگماتیک فقط کد نمیزند، فقط مدل شیءگرا نمیسازد، فقط مستندات نمینویسد، یا فقط فرآیند build را خودکار نمیکند—ما همهٔ اینها را انجام میدهیم. دامنهٔ هر ابزار معمولاً محدود به کاری است که برایش طراحی شده. فرض کن بخواهی یک preprocessor خاص را (مثلاً برای design-by-contract یا پردازش چندمسیره) وارد IDE کنی. اگر طراح IDE چنین «قلاب»هایی را پیشبینی نکرده باشد، عملاً کاری از دستت برنمیآید.
نکته ۲۶
از قدرت شِل بهره بگیر.
وقتی با شِل آشنا شوی، بهرهوریت پرواز میکند. مثلاً اگر بخواهی فهرست تمام package nameهای یکتا که در کد جاوایت import شدهاند را استخراج کنی، دستور زیر آن را در فایلی به نام list ذخیره میکند:
sh/packages.sh
grep '^import ' *.java |
sed -e's/.*import *//' -e's/;.*$//' |
sort -u >list
اگر زیاد با تواناییهای شِل کار نکرده باشی، شاید اینها سنگین به نظر برسد. اما کمی وقت و انرژی برای آشنایی با شِل بگذاری، همهچیز سر جای خودش مینشیند. با شِل بازی کن، و از دیدن اینکه چقدر بهرهورتر میشوی تعجب میکنی.
یک شِل برای خودت
همانطور که نجّار جای کارش را شخصیسازی میکند، توسعهدهنده هم باید شِل را برای خودش تنظیم کند. معمولاً این کار شامل تغییراتی در تنظیمات برنامهٔ ترمینالی است که از آن استفاده میکنی.
تغییرات رایج:
تنظیم رنگها.
انسان میتواند ساعتها بین تمهای رنگی مختلف چرخ بزند تا یکی را انتخاب کند.
پیکربندی prompt.
پرومت شِل که نشان میدهد آمادهٔ دریافت فرمان است، میتواند هر اطلاعاتی که بخواهی نمایش دهد. سلیقه نقش اول را دارد؛ معمولاً یک پرومت ساده با مسیر کوتاهشدهٔ دایرکتوری و وضعیت کنترل نسخه و زمان کافی است.
aliases و توابع شِل.
دستورهای پرتکرارت را به alias تبدیل کن. مثلاً اگر همیشه فراموش میکنی update قبل از upgrade است یا برعکس، یک alias بساز:
alias apt-up='sudo apt-get update && sudo apt-get upgrade'
اگر یک بار زیاد فایل اشتباهی پاک کرده باشی:
alias rm='rm -iv'
تکمیل خودکار.
بیشتر شلها نام دستور یا فایل را با زدن tab کامل میکنند. اما میتوانی آن را فراتر ببری: شِل را طوری تنظیم کنی که زمینهٔ دستور را تشخیص بدهد و بر اساس آن گزینههای تکمیل هوشمندانه پیشنهاد بدهد. بعضی شلها حتی بسته به دایرکتوری جاری تکمیل را تغییر میدهند.
وقت زیادی در یکی از این شِلها خواهی گذراند. مثل خرچنگِ صدفبهدوش، پوستهات را خانهٔ خودت کن.
بخشهای مرتبط
موضوع ۱۳: نمونهسازی و برگههای یادداشت
موضوع ۱۶: قدرت متن ساده
موضوع ۲۱: دستکاری متن
موضوع ۳۰: دگرگونسازی برنامهنویسی
موضوع ۵۱: ابزارهای شروع پراگماتیک
چالشها
آیا کارهایی داری که هنوز در GUI و بهصورت دستی انجامشان میدهی؟ آیا به همکارانت دستورالعملهایی میدهی که شامل چند مرحلهٔ «روی این کلیک کن»، «آن را انتخاب کن» است؟ آیا میشود آنها را خودکار کرد؟
هر وقت به محیط تازهای منتقل میشوی، تلاش کن بفهمی چه شلهایی در دسترساند. ببین میتوانی شِل فعلیات را با خودت بیاوری.
گزینههای جایگزین برای شِل فعلیات را بررسی کن. اگر به مشکلی برخوردی که شِل کنونیات نمیتواند حل کند، ببین آیا شِل دیگری از پسش برمیآید.
موضوع ۱۸ ویرایش قدرتمند
پیشتر گفتیم ابزارها تبدیل به امتداد دست میشوند. این موضوع دربارهٔ ویرایشگرها بیشتر از هر ابزار نرمافزاری دیگری صدق میکند. باید بتوانی متن را تا حد ممکن بیزحمت جابهجا و دستکاری کنی، چون متن مادّهٔ خامِ اصلیِ برنامهنویسی است.
در نسخهٔ اول کتاب توصیه کرده بودیم که برای همهچیز فقط از یک ویرایشگر استفاده کنید: برای کد، مستندات، یادداشتها، مدیریت سیستم و غیره. حالا کمی از آن موضع نرمتر شدهایم. از اینکه چند ویرایشگر مختلف استفاده کنی کاملاً راضی هستیم—فقط میخواهیم در هر کدام به سمت «روانبودن» حرکت کنی.
نکته ۲۷
به روانی در ویرایشگر برس.
چرا این موضوع مهم است؟ آیا واقعاً وقت زیادی ذخیره میکنی؟
بله—در طول یک سال، اگر ویرایشت را فقط چهار درصد کارآمدتر کنی و هفتهای بیست ساعت ویرایش انجام دهی، یک هفتهٔ کامل وقت آزاد بهدست میآوری.
اما این اصل ماجرا نیست. سود بزرگتر این است که وقتی روان شوی، دیگر لازم نیست دربارهٔ «مکانیکِ ویرایش» فکر کنی. فاصلهٔ میان «فکر کردن» و «ظاهر شدن متن» در بافرِ ویرایشگر بهشدت کم میشود. فکرهایت جریان پیدا میکنند و برنامهنویسیات از آن سود میبرد. اگر تا به حال به کسی رانندگی یاد داده باشی، دقیقاً میفهمی منظور چیست؛ تفاوت میان تازهکاری که برای هر حرکت فکر میکند و رانندهٔ باتجربهای که غریزی فرمان را کنترل میکند.
روانبودن یعنی چه؟
چه چیزی نشان میدهد روان هستی؟ فهرست چالش این است:
- هنگام ویرایش، بتوانی بر اساس کاراکتر، واژه، خط و پاراگراف جابهجا شوی و انتخاب انجام دهی.
- هنگام ویرایش کد، بتوانی بر اساس واحدهای نحوی (delimiterهای جفت، تابعها، ماژولها و …) حرکت کنی.
- بتوانی پس از هر تغییری، کد را دوباره و درست باز-تورفتگی بدهی.
- بتوانی با یک فرمان، بلوکهای کد را کامنت یا از کامنت خارج کنی.
- بتوانی تغییرات را undo و redo کنی.
- بتوانی پنجرهٔ ویرایشگر را به چند بخش تقسیم و بین آنها جابهجا شوی.
- بتوانی به یک شمارهٔ خط مشخص بروی.
- بتوانی خطوط انتخابشده را مرتبسازی کنی.
- بتوانی هم رشتهها و هم regular expressionها را جستوجو و جستوجوی قبلی را تکرار کنی.
- بتوانی «خصیصهٔ چند-مکان» ایجاد کنی—استفاده از چند cursor موقت برای ویرایش همزمان جاهای مختلف یک الگوی مشترک.
- بتوانی خطاهای کامپایل پروژه را نمایش بدهی.
- بتوانی تستهای پروژه را اجرا کنی.
و مهمترین سؤال: آیا میتوانی همهٔ اینها را بدون استفاده از موس یا تاچپد انجام دهی؟
اگر ویرایشگر فعلیات بخشی از اینها را ندارد، شاید وقتش رسیده به سراغ دیگری بروی.
حرکت به سمت روانبودن
بهاحتمال زیاد تعداد آدمهایی که همهٔ فرمانهای یک ویرایشگر قدرتمند را بدانند از انگشتان یک دست بیشتر نیست. ما هم چنین انتظاری نداریم. نگاه پراگماتیک این است: فرمانهایی را یاد بگیر که زندگیات را سادهتر میکنند.
دستورالعملش ساده است:
اول، در حین ویرایش خودت را نگاه کن. هر وقت دیدی کاری را تکراری و کسالتبار انجام میدهی، با خودت بگو «حتماً راه بهتری هست»—و پیدایش کن.
وقتی یک قابلیت تازه پیدا کردی، حالا باید آن را وارد حافظهٔ عضلانی کنی. راهش فقط تکرار است. فرصتهای روزمره برای استفاده از قابلیت جدیدت پیدا کن—ترجیحاً چندین بار در روز. یک هفته که بگذرد، میبینی بدون فکر از آن استفاده میکنی.
رشد دادن ویرایشگرت
بیشتر ویرایشگرهای قدرتمند مبتنی بر یک هستهٔ سادهاند که با افزونهها گسترش پیدا میکند. بسیاری از این افزونهها همراه ویرایشگر عرضه میشوند؛ بقیه را بعداً میتوانی نصب کنی.
وقتی به محدودیتی ظاهری در ویرایشگرت برخوردی، جستوجو کن تا افزونهای که آن کار را انجام میدهد پیدا کنی. احتمالاً تنها کسی نیستی که چنین نیازی دارد، و شاید کسی پیش از تو راهحلش را منتشر کرده باشد.
یک گام جلوتر برو. به زبان توسعهٔ افزونههای ویرایشگرت سر بزن. ببین چطور میتوان با چند خط کد ساده بخشی از کارهای تکراریات را خودکار کرد.
گاهی قدم را بیشتر برمیداری و میبینی بهکلی در حال نوشتن یک افزونهٔ کامل هستی. اگر چنین شد، آن را منتشر کن؛ اگر تو به آن نیاز داشتی، دیگران هم خواهند داشت.
بخشهای مرتبط
موضوع ۷: ارتباط برقرار کن!
چالشها
دیگر autorepeat نه!
همه انجامش میدهند: میخواهی آخرین کلمهای را که تایپ کردهای حذف کنی، انگشتت را روی backspace نگه میداری تا autorepeat روشن شود. احتمالاً مغزت آنقدر این کار را کرده که زمان دقیق رها کردن کلید را ناخودآگاه میداند.
بنابراین autorepeat را خاموش کن، و کلیدهای حرکت، انتخاب و حذف براساس کاراکتر، کلمه، خط و بلوک را یاد بگیر. این یکی سخت است—اما ارزش دارد.
یک هفته بدون موس/تاچپد.
یک هفته کامل فقط با کیبورد ویرایش کن. خیلی زود چیزهایی را کشف میکنی که بدون کلیککردن بلد نیستی. زمان یادگیری همین است. کلیدهایی را که یاد میگیری یادداشت کن—ترجیحاً با خودکار و کاغذ.
چند روز اول بهرهوریات پایین میآید. اما وقتی یاد بگیری بدون برداشتن دستها از home row کار کنی، ویرایشت از همیشه سریعتر و روانتر میشود.
به دنبال ادغامها باش.
همینطور که این فصل را مینوشتیم، دیو wondered که آیا میتواند نسخهٔ نهایی PDF را در یک بافر ویرایشگر ببیند. یک دانلود بعد، چیدمان PDF کنار متن اصلی نشسته بود.
فهرستی از چیزهایی بیاور که دوست داری در ویرایشگرت ببینی، و بعد دنبالشان بگرد.
و اگر پیدا نمیشود؟ بساز!
اگر افزونهای که دنبالش هستی وجود ندارد، یکی بساز. اندی همیشه عادت دارد افزونههای wiki محلیِ سفارشی برای ویرایشگر محبوبش بسازد. اگر پیدا نکردی، بساز.
موضوع ۱۹ کنترل نسخه
پیشرفت، بهجای آنکه صرفاً وابسته به تغییر باشد،
بر «توان حفظ و نگهداری گذشته» تکیه دارد.
کسانی که گذشته را به یاد نمیآورند، محکوماند آن را تکرار کنند.
جورج سانتایانا، زندگی خردمندانه
یکی از مهمترین چیزهایی که در یک واسط کاربری بهدنبال آن میگردیم، کلید undo است—دکمهای که اشتباهاتمان را میبخشد. حتی بهتر این است که محیط، چند مرحلهٔ undo و redo داشته باشد تا بتوان به چند دقیقه قبل برگشت و از یک اشتباه قدیمی نجات پیدا کرد.
اما اگر اشتباه هفتهٔ گذشته رخ داده باشد؟ و اگر در این فاصله ده بار دستگاهت را خاموش و روشن کرده باشی؟
اینجاست که کنترل نسخه وارد صحنه میشود: سیستمی که حکم یک کلید undo عظیم را دارد—ماشین زمانِ پروژه، که میتواند تو را به همان روزهای خوشِ هفتهٔ پیش برگرداند، زمانی که کد واقعاً کامپایل میشد و کار میکرد.
برای خیلیها، همینجا استفاده از VCS تمام میشود. آنها دنیای بزرگتری را از دست میدهند: همکاری تیمی، استقرار خودکار (deployment pipelines)، مدیریت خطا و مسئله، و هماهنگی گروهی.
پس بیاییم به کنترل نسخه نگاه کنیم—ابتدا بهعنوان مخزن تغییرات، و سپس بهعنوان محلِ مرکزی همکاری برای تیم و کدشان.
دایرکتوریهای مشترک، کنترل نسخه نیستند
هنوز تیمهایی را میبینیم که فایلهای پروژهشان را از طریق شبکه یا فضای ابری مشترک نگه میدارند.
این روش کار نمیکند.
این تیمها مدام کار یکدیگر را خراب میکنند، تغییرات را از دست میدهند، خروجی پروژه را میشکنند، و در نهایت در پارکینگ دعوا میشود. این درست مثل نوشتن کد همزمان با دادهٔ مشترک و بدون مکانیسم همگامسازی است. از کنترل نسخه استفاده کنید.
اما بدتر هم هست! برخی افراد از VCS استفاده میکنند ولی مخزن اصلی را روی درایو شبکه یا فضای ابری نگه میدارند. تصورشان این است که «بهترین ترکیب» است: هم همهجا قابل دسترس است و هم پشتیبانگیری خارج از محل دارد.
در واقع این کار بدتر است: کنترل نسخه از مجموعهای از فایلها و دایرکتوریها تشکیل شده که با هم تعامل دارند. اگر دو نمونه همزمان روی آنها تغییر ایجاد کنند، وضعیت مخزن ممکن است خراب شود—و هیچکس نمیداند میزان آسیب چقدر خواهد بود. دیدن گریهٔ برنامهنویسها چیز خوشایندی نیست.
همهچیز از «سورس» آغاز میشود
سیستمهای کنترل نسخه همهٔ تغییرات کد و مستنداتت را ثبت میکنند. با VCS درست پیکربندی شده، همیشه میتوانی به هر نسخهٔ قبلی برگردی.
اما کنترل نسخه فقط برای undo کردن اشتباه نیست. یک VCS خوب میتواند پرسشهایی مثل این را پاسخ بدهد:
- این خط را چه کسی تغییر داده؟
- تفاوت نسخهٔ فعلی با نسخهٔ هفتهٔ قبل چیست؟
- در این انتشار چند خط تغییر دادیم؟
- کدام فایلها بیشتر تغییر میکنند؟
این اطلاعات برای ردیابی خطا، ممیزی، تحلیل عملکرد و کیفیت، فوقالعاده ارزشمندند.
VCS اجازه میدهد نسخههای رسمی نرمافزار را «برچسبگذاری» کنی تا هر زمان لازم شد بتوانی آن نسخهٔ منتشرشده را بازسازی کنی—صرفنظر از تغییرات بعدی.
مخزن کنترل نسخه مکان خوبی برای آرشیو است.
و البته، کنترل نسخه اجازه میدهد چند نفر همزمان روی یک فایل کار کنند و تغییراتشان را با هم ادغام کنند. این کار شاید خطرناک به نظر برسد، اما در عمل برای پروژههای کوچک تا عظیم بسیار خوب جواب میدهد.
نکته ۲۸
همیشه از کنترل نسخه استفاده کن.
همیشه. حتی اگر تنها یک نفر هستی و پروژهات یکهفتهای است.
حتی اگر «نمونهٔ دورریختنی» میسازی.
حتی اگر چیزی که روی آن کار میکنی اصلاً کد منبع نیست.
همهچیز را زیر کنترل نسخه ببر: مستندات، فهرست شمارهتماسها، نامهها، makefileها، مراحل build و انتشار، اسکریپت کوچک پاکسازی لاگها—همهچیز. ما تقریباً برای هر چیزی که تایپ میکنیم از VCS استفاده میکنیم (از جمله همین کتاب). حتی اگر روی پروژهای کار نکنیم، کار روزمرهمان در یک مخزن ذخیره میشود.
شاخهزدن (Branching)
سیستمهای کنترل نسخه فقط یک رشتهتاریخ ندارند. یکی از قدرتمندترین قابلیتها، امکان جدا کردن مسیرهای توسعه در قالب «branch» است.
میتوانی در هر نقطهای از تاریخ پروژه یک branch ایجاد کنی و تمام کارهایی که در آن انجامدهی از شاخههای دیگر جدا میماند. بعداً میتوانی تغییراتش را در یک شاخهٔ دیگر ادغام کنی. چند نفر همزمان میتوانند روی یک branch کار کنند—branch مثل یک «کلون کوچک» از پروژه است.
مزایا:
۱) ایزولهکردن کارها. اگر تو روی ویژگی A کار میکنی و همتیمیات روی ویژگی B، دخلی به هم ندارید.
۲) هستهٔ جریان کاری تیم. در بسیاری پروژهها، روند توسعه بر اساس branch طراحی میشود.
اما مراقب باش: درست مثل تستنویسی، دربارهٔ branch هم هزاران نفر هستند که میگویند «فقط این روش درست است». اغلب این توصیهها همان است: روش من برای من جواب داد. تو باید با تحقیق و تجربه، جریان کاری مناسب تیم خودت را پیدا کنی.
یک آزمایش ذهنی
فنجانی چای داغ را روی کیبورد لپتاپت بریز. دستگاه را به تعمیرکار بسپار، اخم و فریادها را تحمل کن، و یک لپتاپ نو بخر.
حالا: چقدر طول میکشد دستگاه جدید را دقیقاً به وضعیتی برسانی که قبل از ریختن چای بود؟ همهٔ کلیدهای SSH، تنظیمات ویرایشگر، تنظیمات شِل، برنامههای نصبشده و…؟
اینچنین اتفاقی برای یکی از ما افتاد. تقریباً همهچیز زیر کنترل نسخه ذخیره شده بود:
- تمام dotfileها و تنظیمات کاربری
- تنظیمات ویرایشگر
- فهرست برنامههای Homebrew
- اسکریپت Ansible برای نصب برنامهها
- تمام پروژههای فعلی
نتیجه؟ دستگاه جدید تا پایان همان بعدازظهر بهطور کامل بازیابی شد.
کنترل نسخه بهعنوان مرکز پروژه
کنترل نسخه در پروژههای شخصی سودمند است، اما ارزش واقعیاش هنگام کار تیمی مشخص میشود. و بخش بزرگی از این ارزش بستگی به نحوهٔ میزبانی مخزن دارد.
بسیاری VCSها نیاز به میزبانی ندارند و کاملاً غیرمتمرکز هستند. اما حتی با اینها هم داشتن یک مخزن مرکزی بسیار مفید است، چون میتوانی از دهها ادغام و قابلیت اتوماتیک بهره ببری.
اگرچه میتوانی سیستم مخزن را در شرکت خودت نصب و اجرا کنی، اما معمولاً این حوزهٔ کاری شرکت نیست. به همین دلیل، پیشنهاد ما برای بیشتر افراد این است که از میزبانهای ثالث استفاده کنند.
به دنبال قابلیتهایی مثل:
- امنیت و کنترل دسترسی خوب
- رابط کاربری واضح
- امکان انجام همهچیز از خط فرمان
- build و تست خودکار
- ادغام قدرتمند branchها (pull request / merge request)
- مدیریت issueها
- داشبوردهای مدیریتی مثل Kanban
- ابزار ارتباط تیمی: اعلانها، ایمیلها، wiki و غیره
بسیاری تیمها VCS را طوری تنظیم میکنند که هر push به شاخهٔ مشخص، سیستم را build کند، تستها را اجرا کند و اگر همهچیز درست بود، کد جدید را منتشر کند.
ترسناک به نظر میرسد؟
وقتی از کنترل نسخه استفاده میکنی، نه—چون همیشه میتوانی rollback کنی.
بخشهای مرتبط
موضوع ۱۱: بازگشتپذیری
موضوع ۴۹: تیمهای پراگماتیک
موضوع ۵۱: بستهٔ شروع پراگماتیک
چالشها
توانایی rollback داشتن یک چیز است—اما آیا واقعاً میتوانی انجامش دهی؟ فرمانهای لازم را یاد بگیر—نه زمانی که سیستم سوخته و زیر فشار هستی، بلکه الآن.
زمان بگذار و به بازیابی لپتاپ خودت فکر کن. چه چیزهایی لازم داری؟
بسیاریشان فایل متنیاند. اگر در VCS ذخیره نشدهاند، روشی برای افزودنشان پیدا کن.
به چیزهای دیگر فکر کن: برنامههای نصبشده، تنظیمات سیستم و … چگونه میتوانی آنها را هم در قالب متن ثبت کنی تا قابل ذخیره و بازیابی شوند؟
یک آزمایش جالب: یک کامپیوتر قدیمی بردار و ببین آیا میتوانی محیط فعلیات را از طریق تنظیماتی که در VCS داری روی آن بسازی یا نه.
امکانات VCS یا میزبان مخزن خود را که استفاده نمیکنی کشف کن:
Branchها، pull requestها، ادغامها، CI، build pipeline، حتی انتشار خودکار.
ابزارهای ارتباطی تیم، ویکیها، کانبان—همه را امتحان کن.
لازم نیست همه را استفاده کنی—اما باید بدانی چه میکنند تا بتوانی تصمیم درست بگیری.
و در آخر: از کنترل نسخه برای چیزهای غیرپروژهای هم استفاده کن.
موضوع ۲۰ اشکالزدایی
دردناک است
به مشکل خودت نگاه کنی
و بدانی که خودت، و نه هیچکس دیگر،
آن را ایجاد کردهای.
سوفوکل، آژاکس
واژهٔ bug از قرن چهاردهم برای اشاره به «چیزی هراسانگیز» استفاده شده است. دریاسالار گریس هاپر، مخترع COBOL، معمولاً کسی است که نخستین «باک» رایانهای را مشاهده کرد—واقعاً یک «بید» که در رلهٔ یک سیستم اولیهٔ کامپیوتری گیر کرده بود.
وقتی از تکنسین پرسیدند چرا دستگاه رفتار درست ندارد، گفت: «یک bug داخل سیستم است.» و طبق وظیفه آن حشره—بالها و همهچیز—را داخل دفتر ثبت چسباند.
افسوس که هنوز هم در سیستمها bug داریم—گرچه از نوع پرنده نیستند. و شاید معنای قدیمی «هیولای ترسناک» اکنون از همیشه مناسبتر باشد. خطاهای نرمافزاری از راههای گوناگونی رخ میدهند: از برداشت نادرست نیازمندیها گرفته تا اشتباههای برنامهنویسی. متأسفانه کامپیوترها هنوز فقط همان کاری را انجام میدهند که به آنها میگویی، نه چیزی که منظورت باشد.
هیچکس نرمافزار بینقص نمینویسد. بنابراین روشن است که اشکالزدایی بخش بزرگی از روزت را خواهد گرفت. بیاییم نگاهی بیندازیم به مسائل درگیر در اشکالزدایی و چند راهبرد عمومی برای یافتن باگهای گریزان.
روانشناسی اشکالزدایی
اشکالزدایی برای بسیاری از توسعهدهندگان موضوعی حساس و احساسی است. بهجای برخورد با آن بهعنوان یک معما، ممکن است با انکار، مقصرشناسی، بهانهآوردن یا حتی بیاعتنایی روبهرو شوی.
بپذیر که اشکالزدایی همان حل مسئله است، و با همین ذهنیت به سراغش برو.
وقتی باگ کسی دیگر را پیدا میکنی، ممکن است وقت و انرژیات را صرف پیدا کردن «مقصر کثیف» کنی. در برخی محیطها این فرهنگ جا افتاده و شاید هم تخلیهٔ روانی باشد. اما در عرصهٔ فنی، باید روی رفع مشکل تمرکز کنی، نه روی یافتن گناهکار.
نکته ۲۹
مشکل را درست کن، نه مقصر را.
مهم نیست باگ تقصیر توست یا دیگری؛ در هر حال این مشکل توست.
ذهنیتِ اشکالزدایی
پیش از شروع، باید ذهنیت درست را پیدا کنی. باید بسیاری از مکانیسمهای دفاعی روزمره را خاموش کنی، فشارهای پروژه را کنار بگذاری، و خودت را در وضعیت راحت قرار بدهی. و بالاتر از همه، قانون اول اشکالزدایی را به یاد بسپار:
نکته ۳۰
وحشت نکن.
آسان است که با دیدن خطا—مخصوصاً زیر فشار مهلت یا رئیس نگران—وحشتزده شوی. اما لازم است یک گام عقب بروی و فکر کنی چه چیزی ممکن است این نشانهها را ایجاد کرده باشد.
اگر نخستین واکنش تو به دیدن یک باگ این باشد: «این غیرممکن است»، اشتباه میکنی. یک لحظه هم صرف این فکر نکن که «این نمیتواند اتفاق بیفتد»، چون واضح است که افتاده است.
از نزدیکبینی در اشکالزدایی دوری کن. فقط نشانههای سطحی را رفع نکن؛ ممکن است ریشهٔ واقعی چندین گام دورتر باشد. همیشه بهدنبال علت ریشهای باش، نه صرفاً نمودِ ظاهری.
از کجا شروع کنیم؟
قبل از بررسی باگ، مطمئن شو که با کدی کار میکنی که بهدرستی—و بدون هشدار—کامپایل شده است. ما همیشه سطح هشدارهای کامپایلر را تا حد ممکن بالا میگذاریم. منطقی نیست برای یافتن مشکلی وقت تلف کنی که خود کامپیوتر میتواند پیدایش کند.
برای حل هر مسئلهای باید دادههای مرتبط را جمعآوری کنی. گزارشهای باگ معمولاً دقیق نیستند. اتفاقات تصادفی بهراحتی آدم را گمراه میکنند. باید مشاهدات دقیق داشته باشی.
و دقت گزارشهای باگ وقتی از طریق واسطه منتقل میشوند کمتر هم میشود—ممکن است لازم باشد کاربر را هنگام بازتولید مشکل تماشا کنی.
یک نمونهٔ واقعی:
در پروژهای گرافیکی، تسترها گزارش دادند برنامه هنگام کشیدن یک نوع stroke میترکد. برنامهنویس بخش مربوطه گفت همهچیز درست کار میکند—او stroke را تست کرده بود.
اما چند روز بعد و پس از دعوا، متوجه شدیم:
تستر stroke را از بالا-راست به پایین-چپ میکشید.
برنامهنویس فقط از پایین-چپ به بالا-راست تست کرده بود!
دو نکته:
۱) گاهی باید کاربر را از نزدیک مشاهده کرد.
۲) تست تکحرکتی مصنوعی کافی نیست. باید مرزها و گروهی رفتارهای واقعی کاربر را آزمود—سیستماتیک.
راهبردهای اشکالزدایی
وقتی فکر میکنی دلیل احتمالی را پیدا کردهای، باید بدانی برنامه چه فکر میکند.
بازتولید باگها
باکها واقعاً «تکثیر» نمیشوند—گرچه بعضیشان آنقدر قدیمیاند که شاید حق قانونیاش را داشته باشند!
منظور این است که بهترین راه رفع یک باگ، این است که بتوانی آن را بهطور قابل اعتماد بازتولید کنی.
اگر نتوانی باگ را بازتولید کنی، چگونه میفهمی درست شده یا نه؟
و بهتر از آن، باید بتوانی با یک فرمان باگ را بازتولید کنی. باگی که فقط بعد از ۱۵ مرحله ظاهر میشود، دشوارتر حل میشود.
نکته ۳۱
برای هر باگ، اول تست شکستخورده بنویس، بعد سراغ کد برو.
گاهی همین فرایند نوشتن تست، دید تازهای میدهد و راهحل را روشنتر میکند.
برنامهنویس در سرزمین عجیب
وقتی با یک کد ۵۰ هزار خطی و یک ساعتِ تیکتاککننده روبهرو هستی، چه باید کرد؟
اگر برنامه crash کرده، اکثر توسعهدهندگان در مواجهه با استثنا فوراً به کد میپرند.
نکته ۳۲
خطای لعنتی را بخوان.
همین.
نتایج غلط
اگر crash نیست ولی خروجی اشتباه است؟
با دیباگر وارد شو و از تست شکستخورده برای مشاهدهٔ مشکل استفاده کن.
اول مطمئن شو در دیباگر هم مقدار اشتباه را میبینی—بارها در پی یک باگ بودهایم و دیدهایم آن اجرای خاص مشکلی نداشته!
گاهی مشکل واضح است، مثل interest_rate=4.5 به جای 0.045.
اغلب باید در عمق بیشتر جست. باید بلد باشی بین فریمهای call stack حرکت کنی و محیط محلی هر سطح را بررسی کنی.
داشتن کاغذ و قلم کمک زیادی میکند—ردگیری سرنخهایی که ممکن است بین راه بینتیجه بمانند.
گاهی stacktrace آنقدر طولانی است که اسکرول تمام نمیشود. در این مواقع روش سریعتر «برش دودویی» است—که بعداً میرسیم.
حساسیت به ورودیها
برنامه با همهٔ دادههای تست خوب کار میکند، یک هفته هم در تولید زنده میماند، بعد ناگهان روی یک ورودی خاص منفجر میشود.
میتوانی از نقطهٔ crash عقب بروی. اما گاهی بهتر است با داده شروع کنی: dataset را بگیر، روی نسخهٔ محلی برنامه بزن، و بعد داده را تقسیمدودویی کن تا ورودی دقیق مشکلساز مشخص شود.
بازگشت خطا بین نسخهها
اگر کدی که هفتهٔ پیش خوب کار میکرد حالا باگ دارد، باید بدانی کدام تغییر باعثش شده.
دوباره:
زمانِ برش دودویی است.
برش دودویی (Binary Chop)
در کلاسهای درس بارها مجبور شدهای باینریسرچ بنویسی. ایده واضح است: داده را نصف کن، درستترین بخش را پیدا کن، تکرار کن.
در جستوجو از پیچیدگی
و در chop از
استفاده میکنیم—سریع و کارآمد.
همین تکنیک را در اشکالزدایی هم میتوان بهکار برد:
- بررسی فریمهای stacktrace: یک فریم وسط انتخاب کن، ببین خطا آنجاست یا نه.
- دادهٔ ورودی: مجموعه را نصف کن، سرچ کن.
- نسخههای محصول: نسخهٔ وسط بین نسخهٔ درست و نسخهٔ خراب را تست کن.
بیشتر VCSهای مدرن حتی این فرایند را خودکار انجام میدهند.
لاگگذاری و ردگیری (Tracing)
دیباگر وضعیت اکنون را نشان میدهد.
اما گاهی باید زمان را هم ببینی: روند تغییر وضعیت، نه فقط آخر خط.
Tracing پیامهای «رسیدم اینجا»، «x=2» و… هستند. سطحشان ساده است، اما برای خطاهایی که دیباگر نمیگیرد بسیار مؤثرند—بهخصوص سیستمهای همزمان، رویدادمحور و real-time.
Tracing را میتوان لایهبهلایه در طول call tree افزود. فرمت پیامها باید هموار باشد تا بتوان با ابزارهای متن و شِل آنها را تحلیل کرد.
اردکِ پلاستیکی (Rubber Ducking)
یکی از مؤثرترین راههای پیبردن به باگ این است:
آن را بلند برای کسی توضیح بده.
حتی اگر آن «کسی» یک اردک پلاستیکی، عروسک یا گلدان باشد.
وقتی توضیح میدهی، مجبور میشوی چیزهایی را که در ذهن بدیهی گرفتهای صریح بیان کنی—و همین اغلب باعث میشود باگ ناگهان خودش را نشان دهد.
فرایند حذف
کدی که اشکالزدایی میکنی ترکیبی از کد تو، کد همتیمیها، کتابخانهها، سیستمعامل و کامپایلر است.
بله—ممکن است باگ در OS یا کامپایلر باشد…
اما احتمال آن بسیار کمتر از این است که باگ در کد خودتان باشد.
یک مهندس ارشد میگفت select سیستمعامل «خراب» است، چون برنامهٔ خودش کار نمیکرد—در حالی که همهٔ برنامههای دیگر روی همان سیستم کاملاً سالم بودند. هفتهها workaround نوشت، و هیچ کارش نتیجه نداد. بالاخره اسناد select را خواند… و مشکل در ۲ دقیقه حل شد.
نکته ۳۳
select خراب نیست.
اگر ردپا دیدی، اول به اسب فکر کن، نه گورخر.
اگر «فقط یک چیز را تغییر دادی» و سیستم شکست، همان یک چیز—مستقیم یا غیرمستقیم—مظنون است.
بهروزرسانیهای OS، کامپایلر و کتابخانهها میتوانند کد درست را خراب کنند. باگها ناپدید میشوند، workaroundها شکسته میشوند، APIها تغییر میکنند.
بنابراین هنگام بهروزرسانی عجله نکن—شاید بهتر باشد تا انتشار بعدی صبر کنی.
عنصر غافلگیری
اگر خودت را در حال گفتن «این غیرممکن است» دیدی، باید مفروضاتت را بازنگری کنی.
کدی که عمیقاً به آن اعتماد داشتی ممکن است زیر همین داده یا همین شرایط خراب شود.
در مواجهه با شکست غافلگیرکننده باید بپذیری یکی از فرضهایت غلط است.
نکته ۳۴
گمان نکن—اثبات کن.
بعد از رفع باگ:
- چرا زودتر گرفته نشد؟
- آیا تستها باید کاملتر شوند؟
- آیا دادهٔ خراب در لایههای مختلف پخش شده؟ آیا باید بررسی پارامترها را بهتر کنی؟
- آیا نقاط دیگری در سیستم هستند که شاید همین باگ را داشته باشند؟
- آیا میتوانی ابزار/لاگ/هُکهایی بسازی که پیدا کردن این باگ را در آینده سادهتر کنند؟
- اگر یک سوءبرداشت باعث باگ شده، کل تیم را در جریان بگذار.
چکلیست اشکالزدایی
- مشکل گزارششده خودِ باگ است، یا فقط یک نشانه؟
- باگ واقعاً در فریمورک است؟ در سیستمعامل؟ یا در کد خودتان؟
- اگر این مشکل را برای همکار توضیح میدادی، چه میگفتی؟
- اگر کد مظنون تستهای واحد را گذرانده، آیا آن تستها کافیاند؟
- آیا شرایط این باگ در نقاط دیگری از سیستم وجود دارد؟ آیا باگهای دیگری در «مرحلهٔ لاروی» منتظر خروج هستند؟
بخش مرتبط
موضوع ۲۴: برنامههای مرده دروغ نمیگویند
چالشها
خودِ اشکالزدایی بهقدر کافی چالشبرانگیز است.
موضوع ۲۱ دستکاری متن
برنامهنویسان پراگماتیک با متن همانگونه رفتار میکنند که نجّاران با چوب؛ آن را شکل میدهند، تراش میدهند، و تبدیلش میکنند. در بخشهای پیشین دربارهٔ برخی ابزارهای مشخص صحبت کردیم—شِل، ویرایشگر، دیباگر—ابزارهایی که هرکدام مثل اسکنه یا اره یا رنده هستند: ابزارهای تخصصی که یک یا دو کار را فوقالعاده انجام میدهند. اما گاهی لازم است تبدیلی انجام دهیم که با ابزارهای پایه راحت ممکن نیست. در چنین لحظهای به یک ابزار «عمومیِ دستکاری متن» نیاز داریم.
زبانهای دستکاری متن برای برنامهنویسی همان نقشی را دارند که روترها برای نجاری دارند. ابزارهایی پردردسر، پرسروصدا، پرریسک؛ خطا با آنها میتواند یک قطعهٔ کامل را نابود کند. برخی میگویند جایی در جعبهابزار ندارند. اما در دستان درست، روترها و زبانهای دستکاری متن هر دو خارقالعاده قدرتمند و چندمنظورهاند. میتوانی کار را سریعتر شکل بدهی، برش بزنی، اتصال ایجاد کنی، و حکاکی انجام دهی. وقتی درست استفاده شوند، ظرافت و دقتی شگفتانگیز دارند—فقط باید برای یادگیریشان وقت گذاشت.
خوشبختانه چند زبان بزرگ برای این کار موجود است. توسعهدهندگان یونیکس (و macOS) غالباً از قدرت شِل، همراه ابزارهایی مانند awk و sed استفاده میکنند. کسانی که ابزار ساختارمندتر میپسندند، Python یا Ruby را انتخاب میکنند.
این زبانها فناوریهای توانمندساز مهمیاند. با آنها میتوانی سریعاً ابزارهای کمکی درست کنی و ایدهها را نمونهسازی کنی—کاری که با زبانهای متداول شاید پنج یا ده برابر زمان ببرد. و همین عاملِ ضربکننده برای نوع آزمایشگری که ما انجام میدهیم حیاتی است. نیم ساعت برای امتحان یک ایدهٔ عجیب بهتر از پنج ساعت است. یک روز برای خودکارسازی قطعهای مهم خوب است؛ یک هفته نه.
در کتاب The Practice of Programming، کرنیگان و پایک همین برنامه را در پنج زبان مختلف نوشتند. نسخهٔ Perl کوتاهترین بود: ۱۷ خط در برابر ۱۵۰ خط C. با Perl میتوانی متن دستکاری کنی، با برنامهها تعامل کنی، شبکه را صدا بزنی، صفحات وب را کنترل کنی، محاسبات با دقت دلخواه انجام دهی، و برنامههایی بنویسی که شبیه فحشدادن اسنوپی هستند!
نکته ۳۵
یک زبان دستکاری متن یاد بگیر.
نمونههایی از کاربرد
برای نشاندادن گسترهٔ این زبانها، چند نمونه از کارهایی که ما با Ruby و Python در تولید همین کتاب انجام دادهایم:
ساخت کتاب
سیستم build انتشارات Pragmatic Bookshelf با Ruby نوشته شده. نویسندگان، ویراستاران، صفحهآراها و تیم پشتیبانی از taskهای Rake برای ساخت PDF و نسخهٔ الکترونیکی استفاده میکنند.
درج و هایلایت کد
اعتقاد داریم هر قطعهٔ کدی که در کتاب میآوریم باید تست شده باشد. بیشتر کدهای این کتاب واقعاً تست شدهاند. و چون بر اصل DRY پایبندیم (Topic 9)، نمیخواستیم کدها را copy/paste کنیم. Ruby اینجا ناجی شد: اسکریپتی ساده بخش موردنظر از فایل را استخراج میکند، هایلایت میکند، و تبدیلش میکند به زبان حروفچینی کتاب.
بهروزرسانی وبسایت
اسکریپتی داریم که بخشی از کتاب را میسازد، فهرست مطالب را استخراج میکند و روی صفحهٔ کتاب در سایت آپلود میکند. اسکریپت دیگری بخشهایی از کتاب را برداشته و بهعنوان نمونه منتشر میکند.
درج معادلهها
اسکریپت Python داریم که LaTeX ریاضی را به متن فرمتشدهٔ مناسب تبدیل میکند.
تولید نمایه (Index)
نمایهٔ کتاب درون متن علامتگذاری میشود، و اسکریپتی Ruby آن را جمع و دستهبندی میکند.
و …
بهواقع کل سازوکار نشر Pragmatic Bookshelf روی دستکاری متن بنا شده است. اگر توصیهٔ ما دربارهٔ نگهداشتن دانش در متن ساده را جدی بگیری، این زبانها در دستکاری آن متن جهان کاملی از مزایا فراهم میکنند.
بخشهای مرتبط
موضوع ۱۶: قدرت متن ساده
موضوع ۱۷: بازیهای شِل
تمرینها
تمرین ۱۱
برنامهای را بازنویسی میکنی که قبلاً YAML را برای پیکربندی استفاده میکرد، اما شرکت اکنون روی JSON استاندارد شده است. اسکریپتی بنویس که یک دایرکتوری را بگیرد و تمام فایلهای .yaml را به .json متناظر تبدیل کند (database.yaml → database.json).
تمرین ۱۲
تیمت ابتدا از camelCase برای نامگذاری متغیرها استفاده کرده، اما حالا تصمیم گرفته به snake_case برگردد. اسکریپتی بنویس که تمام فایلهای سورس را بگردد و موارد camelCase را گزارش کند.
تمرین ۱۳
روی تمرین قبلی بساز: توان تبدیل خودکار camelCase به snake_case در یک یا چند فایل را اضافه کن. از نسخهٔ اصلی فایلها نسخهٔ پشتیبان بگیر—برای آن لحظات که اوضاع وحشتناک اشتباه میشود.
موضوع بعدی: ۲۲
دفترچهٔ مهندسی
دِیو زمانی در یک شرکت سازندهٔ رایانه کار میکرد، کنار مهندسان الکترونیک و گاهی مکانیک. بسیاری از آنها همیشه یک دفترچهٔ چرمی یا کاغذی همراه داشتند، با یک قلم لای جلد. گاهی وسط صحبت جلد دفتر را باز میکردند و چیزی یادداشت میکردند.
وقتی جویا شد، متوجه شد که آنها آموزش دیدهاند «دفترچهٔ مهندسی» نگه دارند: دفتری که در آن کارهای روزانه، چیزهای آموختهشده، طرحهای ذهنی، اندازهگیریهای ابزارها—هرچیزی مرتبط با کار—را ثبت میکنند. وقتی دفتر پر میشد، بازهٔ تاریخ را روی ستون جلد مینوشتند و دفتر را کنار قبلیها روی قفسه میگذاشتند. یک رقابت دوستانهٔ پنهان هم بود: چه کسی قفسهٔ بلندتری از دفترچهها دارد!
ما هم دفترچه را برای یادداشت جلسهها، وضعیت کار جاری، مقادیر متغیرها هنگام اشکالزدایی، پیدا کردن چیزهایی که جا گذاشتهایم، ثبت ایدههای وحشی، و گاهی برای نقاشیکردن استفاده میکنیم.
دفترچه سه مزیت اصلی دارد:
۱) قابل اعتمادتر از حافظه است. اگر بپرسند «اسم آن شرکت تأمینکنندهٔ پاور دقیقی که هفتهٔ پیش زنگ زدی چه بود؟» کافی است چند صفحه برگردانی.
۲) محل ذخیرهٔ ایدههای بیروناززمینه است. ایدههایی که اکنون وقت پرداختن به آنها نیست، اما نمیخواهی از دست بروند.
۳) مثل اردک پلاستیکی عمل میکند. نوشتن باعث تغییر زاویهٔ ذهن میشود—مثل حرفزدن با کسی. بارها پیش آمده هنگام نوشتن، ناگهان متوجه میشوی کاری که انجام دادهای اشتباه بوده است.
و البته یک مزیت فرعی هم هست: میتوانی سالها بعد صفحات قدیمی را ورق بزنی و به پروژهها، آدمها، و از همه بدتر، مدلمو و لباسها فکر کنی.
پس یک دفترچهٔ مهندسی امتحان کن. روی کاغذ—نه فایل دیجیتال یا ویکی. نوشتن با دست چیزی دارد که تایپ ندارد. یک ماه ادامه بده و ببین نتیجهاش چیست.
اگر هم هیچ نشد، لااقل نوشتن زندگینامه را راحتتر میکند—وقتی ثروتمند و مشهور شدی!