مقدمه
هرکسی که (هر چند کم) برنامهنویسی کرده باشد، به خوبی میداند که دانش برنامهنویسی به هیچ عنوان یادگیری نحو یک زبان برنامهنویسی نیست. این که یک پروژۀ نرمافزاری را از کجا شروع کنیم، چه معیارهایی را در طراحی آن لحاظ کنیم، چطور نظم پروژه را حفظ کنیم، با پیغامهای خطا چگونه برخورد کنیم، با تغییرات احتمالی چگونه برخورد کنیم، چگونه پروژه و خود را برای این تغییرات آماده کنیم و چگونه خطای برنامه را پیدا کنیم از مشغولیتهای ذهنی متداول یک برنامهنویس است که هیچ کدام از این موارد ربط مستقیمی به نحو زبان برنامهنویسی ندارد. کتاب برنامه نویس عملگرا موضوعاتی از این دست را مورد بررسی قرار میدهد.
اگر بخواهیم کمی در مورد تاریخچۀ کتاب صحبت کنیم، باید به ویرایش اول کتاب که در سال ۱۹۹۹ منتشر شده نگاهی داشته باشیم. برنامهنویس عملگرا کتاب معروفی در حوزۀ مهندسی نرمافزار بوده که توسط اندی هانت و دیو توماس نوشته شده است. موفقیت ویرایش اول این کتاب به حدی بود که نویسندگان این کتاب تصمیم به تاسیس انتشاراتی به نام «قفسه کتاب عملگرا» گرفتند. این انتشارات، کتابهای متعددی با شعار «بهبود زندگی توسعهدهندگان حرفهای نرمافزار» به چاپ رسانده است. در گذر زمان و با پیشرفتهای روزبهروز حوزۀ نرمافزار، کتاب برنامه نویس عملگرا از یک کتاب مرجع به یک کتاب قدیمی تبدیل شد که تنها خاطرۀ خوشی از آن به یاد ماند. در سال ۲۰۱۹ به مناسبت بیستمین سالگرد انتشار این کتاب، ویرایش دوم آن با تغییرات عمده منتشر شد و توانست محبوبیت نسخۀ اول را تکرار کند. ویرایش جدید کتاب در سایت آمازون، به عنوان یکی از پرفروشترین کتابهای حوزههای مهندسی نرمافزار، تست نرمافزار و زبانهای برنامهنویسی معرفی شده است. با همین ذهنیت، ما هم مشتاق شدیم که به بهانۀ جلسۀ کتابخوانی سحاب، این کتاب را خوانده و پیرامونش با هم صحبت کنیم.
این کتاب دربارۀ چه چیزی صحبت میکند؟
در داستان شکلگیری کتاب آمده که وقتی اندی هانت و دیو توماس به شرکتهای نرمافزاری مختلف مشاوره میدادند، به مواردی برمیخوردند که بارها و بارها برایشان تکرار میشد. مطالب اولیۀ این کتاب شامل همین نکات مشاورهای جمعآوریشده بوده و تا حد زیادی مشخص میکند که محتویات کتاب چیست و مخاطب آن، چه کسانی میتوانند باشند. منتقدان و طرفداران نیز تصریح میکنند که با چنین محتوایی در کتاب مواجه شدهاند. علت جلب نظر موافقان کتاب را میتوان نگارش تجربیات مختلف به صورت مدون و با بیانی زیبا دانست که باید سالها برای کسب آنها زمان صرف میشد. از طرف دیگر، منتقدان کتاب میگویند که این کتاب فاقد یک نظریۀ جدید بوده و مجموع تجربیاتی است که برنامهنویسهای حرفهای در طول عمر کاری خود، آنها را به مرور و از جاهای مختلف کسب میکنند. کتاب برنامه نویس عملگرا (همانطور که از اسمش پیداست)، بیشتر به تواناییهای فردی پرداخته و یک کتاب تخصصی محسوب میشود. این کتاب کمتر به تواناییهای مدیریتی و تیمی میپردازد. در جلسۀ کتاب سحاب نیز تلاش میکنیم تا کتابهای خوانده شده، یکدرمیان مدیریتی و تخصصی باشند.
من از طرفداران این کتاب هستم. طبعاً مفاهیم تازهای که با آن مواجه میشدم، برایم جذابتر بود؛ اما وقتهایی که همۀ مطالب یک فصل را از قبل میدانستم نیز آن فصل برایم جذاب بود! برای مثال، مطالب فصل مربوط به اشکالزدایی برنامه برای من کمابیش تکراری بود. اشکالزدایی برنامه (چه برنامههایی که خودم نوشتم و چه برنامههای دیگران)، همیشه برای من مثل حل یک معما است که برای آن در کمترین زمان باید تکنیکهای مختلفی به کار گرفته شود. بعضاً برای کسانی که به دنبال برنامهنویسی مسابقهای (مثل المپیاد کامپیوتر و یا ICPC) هستند، تکنیکهایی که خودم به مرور یاد گرفته یا از بقیه شنیدهام را توضیح میدهم؛ اما این حس که مشابه همین تکنیکها را در یک فصل این کتاب میخواندم، برایم خوشایند بود. بعداً فهمیدم که نامگذاری روی بعضی از این تکنیکها مثل «اشکالزدایی با اردک پلاستیکی»، برای اولین بار در نسخۀ اول این کتاب انجام شده است.
در جلسات کتابخوانی این کتاب چه خبر بود؟
جلسات کتاب برنامه نویس عملگرا در سحاب، جلسات پرشوری بودند. تعداد صفحاتی که برای هر جلسه انتخاب میکردیم خیلی زیاد نبود (بین ۴۰ تا ۵۰ صفحه با فونت بزرگ). عامل محدودکننده برای انتخاب تعداد صفحات نیز نه زمان خواندن آنها، بلکه زمانی بود که میخواستیم برای بحث دربارۀ مطالب هر فصل و بیان تجربیات مرتبط اختصاص دهیم. روال جلسات بر این نبود که کسی کتاب را ارائه دهد و فرض بر این بود که تمام افراد حاضر در جلسه قسمت مربوطه را مطالعه کردهاند. بنابراین کل جلسه، پیرامون برداشت و نظر هر کدام از ما از مطالب کتاب میگذشت. نکتۀ مهمی که این جلسات را بسیار مفید میکرد این بود که همۀ محتوای کتاب، نهتنها بدون چون و چرا پذیرفته نمیشد، بلکه برعکس در جلساتمان به مباحث چالشی بسیاری برمیخوردیم. گاهی اوقات دو گروه موافق و مخالف، نظرات خود را پیرامون موضوع مربوطه مطرح میکردند و گاهی از بیان کتاب دو برداشت مختلف میشد.
برای مثال در این کتاب گفته میشد که هر پروژۀ نرمافزاری باید همیشه آمادۀ تغییر باشد. تا اینجای کار تمام افراد جلسه با نویسندگان کتاب همنظر بودند؛ اما در ادامه، کتاب پیشنهاد میداد (یا میشد برداشت کرد) که با گذاشتن APIها و wrapperهای متعدد در پروژۀ نرمافزاری، تأثیر تغییرات را محدود کنید. در مقابل افراد جلسه با این روش مخالف بودند و میگفتند تعدد APIها و wrapperها فقط برنامه را شلوغ و پیچیده کرده و اکثر آنها در نهایت بلااستفاده خواهند بود. حتی فراتر از آن، عقیده داشتند که حسب پروژههایی که تجربه کردهاند، برنامه معمولاً از جاهای پیشبینی شده تغییر نمیکند و از جایی تغییر خواهد کرد که انتظار آن را نداریم. APIها و wrapperها معمولاً در جایی قرار داده میشوند که انتظار تغییر را داریم و عملاً کارایی نخواهند داشت.
پس پیشنهاد جایگزین چیست؟ این که نظم برنامه را (با تکنیکهای دیگری که در همین کتاب نیز به آنها اشاره شده) حفظ کرده و از تغییر نترسیم. با این کار در مجموع زمانی که برای تغییر گذاشته میشود کمتر از مقدار زمانی است که برای نوشتن APIها و wrapperهای بلااستفاده گذاشته میشود.
این کتاب از ۹ بخش اصلی تشکیل شده که هرکدام از شامل چند فصل است که هر فصل نیز به مبحثی خاص میپردازد. در نگاه اول، فصول کتاب مستقل از هم هستند؛ ولی اگر کمی عمیقتر نگاه کنیم، به وجود ارتباطی میانشان پی خواهیم برد. در ادامه، هرکدام از بخشهای کتاب را معرفی میکنیم.
بخش ۱. فلسفۀ عملگرایی
بخش اول قصد دارد بدون ورود به مفاهیم نرمافزاری، دید و تفکری درست به برنامهنویس بدهد. بحث با روانشناسی انگیزشی شروع میشود که هر فرد به جای انفعال، باید خودش آیندۀ شغلیاش را تعیین کرده و همیشه به شرایط موجود راضی نباشد.
بحث دیگر، مسئولیتپذیری در برابر اشتباهات است که به گفتۀ نویسندگان، حل مشکل را نیز تسریع میکند. موضوع دیگری که مبحث مهمی در تمام کتاب به حساب میآید، حفظ نظم در پروژۀ نرمافزاری است. در واقع پروژه، به یک سیستم ترمودینامیکی تشبیه شده که به صورت معمول، به سمت بینظمی (آنتروپی بیشتر) حرکت میکند؛ مگر اینکه با صرف انرژی نظم آن حفظ شود. در پروژههای نرمافزاری نیز برای حفظ نظم باید انرژی گذاشته شود. ضمن این که اولین بینظمی، راه را برای بینظمیهای دیگر باز کرده و دقت در این موضوع ضروری است. اصل پنجرۀ شکسته در روانشناسی که به همین موضوع اشاره دارد، برای اولین بار در نسخۀ اول این کتاب در حوزۀ نرمافزار مطرح شده است. روانشناسی تغییر نیز در این فصل طرح موضوع شده و در ادامۀ کتاب مورد استفاده قرار میگیرد.
این موضوع که چقدر لازم است ویژگیهای متعدد به نرمافزار اضافه کنیم، از دیگر بحثهای چالشی این فصل است. تجربه نشان داده که مهندسین نرمافزار دوست دارند ویژگیهایی به نرمافزار اضافه کنند که در نهایت به درد نمیخورد. بنابراین در این کتاب پیشنهاد میشود از اضافه کردن ویژگیهای غیر ضروری خودداری شود. از دیگر ویژگیهای یک برنامهنویس حرفهای، آشنایی با حوزههای مختلف و محدود نشدن به یک نرمافزار و یک چارچوب و همچنین توانایی ارتباط است.
بخش ۲. رویکرد عملگرایانه
بخش دوم، سراغ یک پروژۀ نرمافزاری میرود. از دیگر مفاهیم مهم این بخش نیز میتوان به موضوعاتی از قبیل «طراحی خوب چیست؟» یا «آیا مولفههای مختلف باید با هم مرتبط و یا بر هم عمود باشند» اشاره کرد. یکی از دیگر مباحث مهم این بخش، تکرار نکردن یک چیز در جاهای مختلف است که در دنیای نرمافزار، به اصل DRY معروف بوده و اولین بار در نسخۀ اول این کتاب مطرح شده است.
موضوع جالبی که در این راستا مطرح میشود این که است که ممکن است چند خط کد ظاهرا تکراری باشد؛ اما در واقع تنها با یک شباهت مواجه باشیم. در این موارد استخراج کد تکراری، مرتبط کردن دو کد نامربوط به هم و اشتباه است! نکتۀ دیگر این است که اجتناب از تکرار نباید فقط به کد محدود باشد. برای مثال برای نوشتن همین کتاب، عکسها و کدهای موجود در کتاب به صورت اتوماتیک وارد کتاب میشوند و در صورت تغییر نسخۀ اصلی عکس و کد، در کتاب نیز تغییر داده شده و اعمال میشود.
موضوع دیگر این فصل، چگونگی شروع کردن یک پروژه از صفر بوده که دغدغۀ بسیاری از برنامهنویسان است. زبان خاص دامنه و تخمین زمانی در پروژههای نرمافزاری نیز از دیگر بحثهای چالشی این بخش هستند.
بخش ۳. ابزارهای اساسی
بخش سوم، برخی ابزارهایی را که یک برنامهنویس باید به آنها مجهز باشد، مرور میکند؛ اما قبل از آن، برتری فایلهای تنظیمات متنی بر باینری مطرح میشود. برای مثال در لینوکس بیشتر تنظیمات با تغییر یک فایل متنی انجام میشود؛ ولی در ویندوز با تعداد زیادی پنجرۀ تنظیمات مواجه هستیم و برای تنظیمات فراتر از آن، معمولاً به registry ویندوز وابستهایم؛ چراکه این تنظیمات به صورت باینری ذخیره شدهاند. کار با پوسته، تسلط بر یک ویرایشگر متنی، تسلط بر نرمافزارهای کنترل نسخه مثل git، توانایی اشکالزدایی نرمافزار، توانایی دستکاری فایلهای متنی و استخراج اطلاعات از آن، از تواناییهایی هستند که در این کتاب بیان شده و هر برنامهنویس حرفهای باید به آنها مسلط باشد.
بخش ۴. بدگمانی در عملگرایی
بخش چهارم در رابطه با مواجهه با خطاهای نرمافزاری است. این کتاب طرفدار رویکرد سختگیرانه در مواجهه با خطا است: خطا را سریع تشخیص داده و با شدت با آن برخورد کنیم. در این بخش، مفاهیم برنامهنویسی دفاعی، برنامهنویسی قاطعانه و مباحث مشابه مطرح میشود. در جلسهای که به این مطالب میپرداختیم، یک مثال جالب در حوزۀ پروتکلهای شبکه مطرح شد که ذکر آن، درستی رویکرد این کتاب را مشخص میکند. در پروتکلهای شبکه، یک اصل به نام robustness وجود دارد که توسط جان پاستل (طراح پروتکل TCP) در سال ۱۹۸۹ مطرح شده و به قانون پاستل نیز معروف است. در این اصل پیشنهاد میشود که اطلاعاتی که با پروتکل مطابقت صد در صدی ندارند نیز در صورت امکان پذیرفته شوند؛ ولی خروجی تولید شده همیشه صد در صد سازگار با پروتکل باشد. هدف این اصل این است که بروز خطا را کم کرده و ناسازگاری بین نسخههای مختلف را نیز به حداقل برساند. این رویکرد، مشابه رویکرد مخفی کردن خطا در نرمافزار است. در سالهای ۲۰۱۵ تا ۲۰۱۸ در تعدادی Internet Draft، مارتین توماس به نقد این اصل و اثرات مخرب آن پرداخته و میگوید این اصل، کاملاً برعکس هدفی که برای آن طراحی شده عمل میکند. در جلسۀ ما نیز مطرح شد که در صورت عدم وجود این اصل، پردازش صفحات وب بسیار آسانتر بود؛ چراکه همۀ سایتها مجبور بودند کد HTML کاملاً صحیح داشته و وقت مرورگر به پیدا کردن مکان بستن شدن تگهایی که بسته نشدهاند، تلف نمیشد. همچنین در مقالهای در سال ۲۰۱۸ نشان داده شده که با سوءاستفاده از اصل پاستل، چگونه میتوان امنیت شبکه Tor را زیر سؤال برد.
بخش ۵. انعطاف در عملگرایی
بخش پنجم که در ادامۀ مباحث طراحی پروژه است، بیشتر در مورد توانایی تغییر است. در همین راستا، برتری composition بر inheritance، مفاهیمی مثل decoupling و جدا کردن تنظیمات از کد مطرح میشود. همچنین نیمنگاهی نیز به برنامهنویسی تابعی و زنجیرههای تبدیلی که ایجاد میکند، صورت میگیرد.
بخش ۶. همروندی
موضوع بخش ششم همروندی (concurrency) در برنامهنویسی است. در ابتدا اشکالاتی که ممکن است در اجرای همروند به وجود بیاید، به خوبی تشریح میشوند. در یکی از فصلها، کتاب به این اشاره میکند که اشکالهایی که به صورت تصادفی و گاهی اوقات پیش میآیند، معمولاً مربوط به اجرای همزمان هستند. در ادامه، به چند نکته برای کمک به رفع این اشکالات اشاره میشود. یکی از این راهحلها، استفاده از ماشین حالات متناهی (finite state machine) است که در درس نظریۀ زبانها و ماشینها (و درسهای دیگری مثل مدارهای منطقی) بهعنوان اتوماتا تدریس میشود. بهعلاوه اشارهای نیز به بحث برنامهنویسی واکنشی (reactive programming) و برخی ایدههای آن میشود که بهطور ذاتی بسیاری از مشکلات همروندی را حل میکند. بحث مربوط به برنامهنویسی واکنشی تا حدی ادامه پیدا کرد که یک جلسه مجزا برای بحث در مورد آن (خارج از جلسۀ کتاب) اختصاص پیدا کرد.
بخش ۷. در حین برنامهنویسی
در بخش هفتم، مباحثی را که در حین کد زدن ایجاد میشود، بیان کرده که شامل موارد مهمی مانند تحلیل زمان اجرای الگوریتم، تست، refactoring و نامگذاری اجزای مختلف میشود. هرکدام از این عناوین بحث زیادی میطلبد و حتی برخی از آنها دارای کتابهای جداگانهای هستند. بالطبع در مورد هر کدام از این مطالب بحثهای مفصلی داشتیم که از بیان آن در اینجا چشمپوشی میکنم. بهعلاوه، مسائلی مثل امنیت نرمافزار نیز در این بخش مطرح شده که دارای نکات ارزشمندی هستند.
در فصل مربوط به امنیت، قسمت کوچکی به ضدالگوهای انتخاب رمز برای کاربران پرداخته که بسیاری از نرمافزارهایی که با آنها سروکار داریم، به این ضدالگوها دچار هستند. این که نباید کاربر را مجبور به استفاده از عدد و حرف کوچک و بزرگ و این که نباید او را به تغییر رمز خود وادار کرد (مگر در مواردی که مجبوریم)، از مواردی هستند که برای همۀ ما خاطرات ناخوشایندی را به یاد میآورند. برای مثال، اجبار برای تعویض رمز اینترنت بانک منجر به انتخاب رمز ساده شده که در تضاد با امنیت است.
از بین همۀ این مطالب، در مورد فصل نامگذاری بحث زیادی در جلسه شد، به حدی که به نظر میآمد مطالب کتاب پوشش کافی روی این موضوع نداشته است!
بخش ۸ و ۹. پروژۀ عملگرا
در بخش هشتم و نهم، کتاب پا را کمی فراتر از برنامهنویسی گذاشته است. تعیین نیازمندیهای پروژه، خلاقیت، کار تیمی، متدولوژیهای چابک و تعریف هدف پروژه، بعضی از مفاهیمی هستند که در این دو بخش مورد بررسی قرار میگیرند. همانند فصلهای قبل، در مورد این فصلها نیز صحبت زیادی شد. برای مثال از جالبترین بحثهای این جلسات این بود که برنامهنویسها نیز باید در فرآیند تعیین نیازمندیها حضور فعال داشته و مثل یک دکتر روانشناس، کارفرمای پروژه را به نیازمندی واقعی خود هدایت کنند.
دانستن مطالب کتاب برنامهنویسی عملگرا برای هر کسی که علاقهمند به برنامهنویسی و در حالت کلی تولید نرمافزار است، ضروری است. یا این مطالب را از جاهای مختلف یاد بگیرید و یا با خواندن یک کتاب همه را مرور کنید.
دیدگاه شما