(برنامه‌نویسی راهبردی در برابر برنامه‌نویسی تاکتیکی)

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

۳.۱ برنامه‌نویسی تاکتیکی

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

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

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

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

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

اگر مدتی روی یک پروژه نرم‌افزاری بزرگ کار کرده باشید، احتمالاً برنامه‌نویسی تاکتیکی را از نزدیک دیده‌اید و مشکلات ناشی از آن را تجربه کرده‌اید. وقتی وارد مسیر تاکتیکی شوید، تغییر مسیر کار سختی است.

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

۳.۲ برنامه‌نویسی راهبردی

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

برنامه‌نویسی راهبردی نیازمند ذهنیت سرمایه‌گذاری است. به‌جای این‌که سریع‌ترین مسیر برای اتمام پروژه فعلی را انتخاب کنید، باید زمانی را صرف بهبود طراحی سیستم کنید. این سرمایه‌گذاری‌ها در کوتاه‌مدت ممکن است کمی سرعت شما را کاهش دهند، اما در بلندمدت سرعت کارتان را افزایش می‌دهند، همان‌طور که در شکل ۳.۱ نشان داده شده است.

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

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

۳.۳ چقدر باید سرمایه‌گذاری کرد؟

خب، مقدار مناسب سرمایه‌گذاری چقدر است؟ سرمایه‌گذاری عظیم از ابتدا — مثل تلاش برای طراحی کل سیستم از همان اول — مؤثر نیست. این همان روش آبشاری (Waterfall) است و می‌دانیم که جواب نمی‌دهد. طراحی ایده‌آل معمولاً به‌تدریج و با تجربه‌ای که از کار با سیستم به‌دست می‌آید، شکل می‌گیرد. بنابراین بهترین رویکرد این است که به‌طور مستمر سرمایه‌گذاری‌های کوچک زیادی انجام دهید. من پیشنهاد می‌کنم حدود ۱۰ تا ۲۰ درصد از کل زمان توسعه خود را به سرمایه‌گذاری اختصاص دهید. این مقدار آن‌قدر کم هست که برنامه‌ زمان‌بندی‌تان را به‌طور قابل توجهی مختل نکند، اما آن‌قدر زیاد هست که در طول زمان، مزایای چشمگیری ایجاد کند.

پروژه‌های ابتدایی شما حدود ۱۰ تا ۲۰ درصد بیشتر از حالت تاکتیکی طول خواهند کشید. اما این زمان اضافه منجر به طراحی نرم‌افزاری بهتر می‌شود، و در عرض چند ماه شروع به دیدن نتایج آن خواهید کرد. خیلی طول نمی‌کشد که سرعت توسعه شما حداقل ۱۰ تا ۲۰ درصد بیشتر از حالتی شود که تاکتیکی برنامه می‌نوشتید. در این مرحله، سرمایه‌گذاری‌هایتان عملاً رایگان می‌شوند: مزایای حاصل از سرمایه‌گذاری‌های گذشته، زمان کافی برای پوشش دادن هزینه‌ی سرمایه‌گذاری‌های آینده صرفه‌جویی می‌کنند. خیلی زود، هزینه‌ی سرمایه‌گذاری اولیه جبران خواهد شد. شکل ۳.۱ این پدیده را به‌تصویر می‌کشد.

شکل 3.1

شکل 3.1

 

شکل ۳.۱: در ابتدا، رویکرد تاکتیکی به برنامه‌نویسی سریع‌تر از رویکرد راهبردی پیش می‌رود. اما پیچیدگی در رویکرد تاکتیکی با سرعت بیشتری انباشته می‌شود، که بهره‌وری را کاهش می‌دهد. در بلندمدت، رویکرد راهبردی منجر به پیشرفت بیشتری می‌شود.
توضیح: این شکل صرفاً یک تصویر کیفی است؛ نویسنده از هیچ داده تجربی برای شکل دقیق این منحنی‌ها آگاه نیست.

 

برعکس، اگر به‌صورت تاکتیکی برنامه‌نویسی کنید، پروژه‌های ابتدایی خود را ۱۰ تا ۲۰ درصد سریع‌تر به پایان می‌رسانید، اما با گذشت زمان و انباشت پیچیدگی‌ها، سرعت توسعه کاهش می‌یابد. خیلی زود متوجه می‌شوید که دست‌کم ۱۰ تا ۲۰ درصد کندتر از قبل برنامه می‌نویسید. تمام زمانی که در ابتدا ذخیره کرده بودید را خیلی سریع از دست می‌دهید، و در ادامه‌ی عمر سیستم، توسعه‌ی شما کندتر از حالتی خواهد بود که رویکرد راهبردی را در پیش گرفته بودید.

اگر هیچ‌وقت با یک پایگاه کد نابسامان و به‌هم‌ریخته کار نکرده‌اید، با کسی صحبت کنید که کرده است؛ او به شما خواهد گفت که کیفیت پایین کد، توسعه را دست‌کم ۲۰ درصد کند می‌کند.

۳.۴ استارتاپ‌ها و سرمایه‌گذاری

در برخی محیط‌ها، نیروهای قوی‌ای علیه رویکرد راهبردی عمل می‌کنند. برای مثال، استارتاپ‌های نوپا تحت فشار شدیدی هستند تا نسخه‌های اولیه‌ی محصول خود را سریع عرضه کنند. در چنین شرکت‌هایی ممکن است حتی یک سرمایه‌گذاری ۱۰ تا ۲۰ درصدی نیز غیرقابل‌تحمل به‌نظر برسد. در نتیجه، بسیاری از استارتاپ‌ها رویکرد تاکتیکی را در پیش می‌گیرند و تلاش کمی برای طراحی می‌کنند و حتی زمان کمتری برای پاکسازی مشکلات صرف می‌کنند. آن‌ها این تصمیم را با این فکر توجیه می‌کنند که اگر موفق شوند، آن‌قدر پول خواهند داشت که مهندسان بیشتری استخدام کنند تا اوضاع را سامان دهند.

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

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

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

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

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

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

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

این نمونه‌ها نشان می‌دهند که شرکت می‌تواند با هر دو رویکرد موفق شود. اما کار کردن در شرکتی که به طراحی نرم‌افزار اهمیت می‌دهد و پایگاه کد تمیزی دارد، به‌مراتب لذت‌بخش‌تر است.

۳.۵ نتیجه‌گیری

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

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

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

موثرترین رویکرد این است که هر مهندس به‌طور مداوم سرمایه‌گذاری‌های کوچکی در طراحی خوب انجام دهد.