در فرایند توسعهٔ نرمافزار، اغلب با مسائلی تکراری مواجه میشویم و نکتهٔ جالب اینجا است که لازم نیست برای حل این دست مسائل کار خود را از صفر شروع کنیم چرا که راهکارهای مربوط به معماری که توسط دولوپرهای حرفهای ابداع شدهاند تا حد زیادی مشکلات ما را مرتفع خواهند کرد (مانند معماریهای برای برای مشکلات مختلف ابداع شدهاند). به هر حال مهارت توسعهٔ نرمافزار چیزی است که با چالشهای خاص خود همراه است که در این بین برخی اشتباهات هستند که بیش از بقیه، توسط دولوپرهای مبتدی بارها و بارها تکرار میشوند.
الگوهای طراحی معمولاً راهحلهایی با قابلیت استفادهٔ مجدد در سناریوهای مختلف هستند که میتوانند برای حل مسائل رایج هم مورد استفاده قرار گیرند و به ما کمک کنند تا کدمان را بهینه کنیم. در حالی که الگوهای طراحی به دلیل استفاده از فرمولها و روشهای تست شده برای بهبود فرایند توسعه کاربردی هستند، بعضی وقتها هم ممکن است ما را دچار اشتباه کنند که در این صورت آنها را Anti Pattern (آنتی پترن یا ضد الگو) مینامیم.
عبارت آنتی پترن در کتابی به نام AntiPatterns در سال 1998 استفاده شد به معنی راهحلهای قابل استفادهٔ مجدد که در ابتدا مفید به نظر میرسند، ولی بعداً مشخص میشود که ضرر آنها از فایدهٔشان بیشتر است!
این اتفاق ممکن است به دلایل مختلفی رخ دهد؛ برای مثال اگر از الگوها در جای درست، در تنظیمات یا زمان مناسب استفاده نکنیم، راهحلهایی که در گذشته مؤثر واقع شدهاند ممکن است در حال حاضر اینگونه نباشند یا در مواردی ممکن است این الگوها از همان ابتدا نامناسب به نظر برسند.
از ضدالگوها گاهیاوقات با عنوان الگوهای شکست نام برده میشود. خبر خوب این است که میتوان آنها را به موقع تشخیص داد و از آنها اجتناب کرد. در این مقاله قصد داریم به بررسی 10 ضدالگوی رایج کدنویسی در توسعه نرمافزار بپردازیم که ممکن است ما را دربارهٔ اینکه کدمان بهینه است یا خیر، به اشتباه بیاندازند (لازم به ذکر است که این موارد الزاماً با مطالب کتابی که قبلاً اشاره شد، همخوانی ندارند).
Premature Optimization
زمانبندی دقیق، عامل مهمی در بهینهسازی کدها است و این در حالی است که به راحتی ممکن است دچار ضد الگوی بهینهسازی زودرس شویم. به عبارت دیگر، اگر به بهینهسازیها و کارایی کوچک در فرایند توسعه بیش از حد توجه کنیم و آنها را زودتر از موعد بهینه کنیم قبل از اینکه بدانیم دقیقاً قصد انجام چه کاری را داریم، گفته میشود که دچار Premature Optimization شدهایم. طبق نقل قول معروف Donald Knuth که میگوید «بهینهسازی زودرس ریشهٔ همه بدیهاست». این گزاره شاید کمی اغراقآمیز باشد ولی نشان میدهد ممکن است بعدها مشکلات بزرگتری را به وجود بیاورند.
اگر قبل از اینکه معماری مؤثری را پیاده کرده باشیم کارایی را بهبود بدهیم، این کار ممکن است باعث کاهش خوانایی کد شود و دیباگ و نگهداری را سختتر کنیم و قسمتهای غیرضروری به کدمان اضافه گردد.
برای جلوگیری از بهینهسازی زودرس، استفاده از قانون کدنویسی YAGNI مخفف (You Aren’t Gonna Need It) مفید است به این معنی که «شما به آن نیازی نخواهید داشت» به طوری که این اصل حاکی از آن است که همیشه چیزهایی را به کار ببرید که واقعاً به آنها نیاز دارید نه وقتی که پیشبینی میکنید به آنها نیاز خواهید داشت.
Reinventing the Wheel
این ضدالگو گاهیاوقات «طراحی در خلاء» نیز نامیده میشود و وقتی اتفاق میافتد که میخواهیم هر چیزی را خودمان انجام دهیم و بدون مطالعهٔ APIها و لایبرریهای موجود از ابتدا کدنویسی کنیم. اختراع مجدد چرخ فقط اتلاف وقت نیست، بلکه این راهحلهای سفارشی، مخصوصاً برای کاربردهای اصلی و بنیادی، به ندرت به خوبی نمونههای استانداردی هستند که توسط بسیاری از کاربران و توسعهدهندگان آزمایش شدهاند.
Dependency Hell
در سمت مخالف «اختراع مجدد چرخ» چیزی به عنوان «جهنم وابستگیها» وجود دارد. اگر به جای نوشتن هرچیزی از ابتدا، از تعداد زیادی لایبرری به اصطلاح Third-party استفاده کنیم که خود آنها وابسته به نسخههای خاصی از لایبرریهای دیگر هستند، در موقعیتی قرار میگیریم که هنگام آپدیت مشکل ایجاد خواهد شد چرا که این وابستگیهای فرعی در بسیاری از موارد با یکدیگر ناسازگار هستند!
این ضدالگو میتواند با استفاده از ابزار مدیریت پکیج که اقدام به آپدیت هوشمند وابستگیهای لازم و ملزوم یکدیگر میکنند حل شود. اگر مشکلتان بزرگتر از اینها است، ریفکتور کردن میتواند راهکار خوبی باشد.
Spaghetti Code
اسپاگتی کد شاید شناختهشدهترین آنتی پترن در فرایند توسعهٔ نرمافزار باشد و به طور کلی Spaghetti Code حاکی از آن است که به خاطر عدم استفاده از معماری مناسب، دیباگ و اصلاح اپلیکیشن سخت خواهد شد.
نتیجهٔ طراحی ضعیف نرمافزار، ایجاد مجموعهای کد است که به خاطر پیچ و تاب خوردن داخل یکدیگر، ساختار آن بیشتر به یک ظرف ماکارونی شبیه است. خوانایی اسپاگتی کد بسیار پایین است و یکی از غیرممکنترین کارها، درک نحوهٔ انجام کار در این نوع کدنویسی است.
اسپاگتی کد معمولاً ترکیبی از اشکال مختلف کدنویسیهای نادرست است؛ مثل استفاده نکردن از بلاکهای شرطی مناسب، اکسپشن، ترد، استفاده از بخشهای خاصی که مربوط به جاهای دیگر هستند، ارتباط حداقلی بین آبجکتها، به کارگیری توابع و متدهایی که قابلیت استفادهٔ مجدد ندارند، مستندات نامناسب یا بدتر از آن، عدم وجود مستندات.
Programming by Permutation
برنامهنویسی با جایگشت یا برنامهنویسی تصادفی وقتی اتفاق میافتد که با امتحان کردن تغییرات کوچک، آزمایش کردن و ارزیابی یکی یکی تکه کدها و در آخر پیادهسازی چیزی که برای اولین بار به نتیجه میرسد، اقدام به پیدا کردن راهحل مسئله میکنیم.
این نوع کدنویسی میتواند باعث ایجاد باگهای جدید در کدمان شود، حتی بدتر از آن باگهایی که در اوایل کار اصلاً متوجه آن نیستیم. در بسیاری از موارد، ممکن نیست پیشبینی کنیم این راهحل در همهٔ سناریوها کار میکند یا خیر.
Copy and Paste Programming
برنامهنویسی با کپی/پیست هنگامی رخ میدهد که ما از قاعدهٔ Don’t Repeat Yourself که به اختصار DRY گفته میشود به معنی «کار تکراری نکن» استفاده نکنیم و به جای ایجاد راهحلهای عمومی، اقدام به درج تکه کدهای موجود در جاهای دیگر کنیم و بعداً برای تطبیق با زمینهٔ مورد استفاده، اقدام به ویرایش نماییم. این اقدام باعث ایجاد کدهای تکراری میشود که دارای اختلافات ناچیزی هستند!
برنامهنویسی با کپی/پیست فقط توسط توسعهدهندگان مبتدی استفاده نمیشود بلکه برنامهنویسان باتجربه نیز ممکن است دچار آن شوند چرا که بسیاری از آنها مستعد استفاده از کدهای نوشته شده توسط خودشان هستند به این دلیل که این کدها برای کاربردهای خاص امتحانشان را پس دادهاند. این کار میتواند به راحتی باعث ایجاد کدهای تکرار بیدلیل شود.
Cargo-Cult Programming
نام «برنامهنویسی بارپرستانه» از پدیدهٔ قومی خاصی به نام Cargo Cult به معنی «بارپرستی» گرفته شده است. بارپرستان که در جزایر اقیانوس آرام جنوبی زندگی میکردند، بعد از جنگ جهانی دوم در مواجهه با تمدنهای پیشرفته کشتیهایی را دیده بودند که اجسام و بارهایی برای سفیدپوستان میآوردند از قبیل کوکاکولا، تلویزیون، یخچال و غیره که فکر کردند این بارها فرستادهٔ نیروهای ماورائی است و اگر آنها هم مناسک جادویی شبیه به کارهای غربیها را به درستی انجام دهند، کشتیهای باری دوباره خواهند آمد و به جای سفیدپوستان به آنها هدیه خواهند داد.
وقتی مرتکب ضد الگوی برنامهنویسی بارپرستانه میشویم که در واقع داریم همین کار را در کدنویسی انجام میدهیم. ما از فریمورکها، لایبرریها، راهحلها، الگوهای طراحی و غیره استفاده میکنیم که برای کار دیگران به خوبی جواب دادهاند، بدون اینکه بدانیم چرا باید از آنها استفاده کنیم یا این تکنولوژیها دقیقاً چگونه کار میکنند.
در بسیاری از موارد، توسعهدهندگان تنها از روی رسوم و چیزهای رایج اقدام به اجرای کاری میکنند که در آن زمان خاص استفاده میشده بدون دانستن دلیل و هدف واقعی آنها. این اقدام تنها به این دلیل بد نیست که اپلیکیشن ما را حجیمتر میکند بلکه علاوه بر آن میتواند باعث ایجاد باگهای جدید نیز بشود.
Lava Flow
این ضدالگو مواقعی رخ میدهد که میخواهیم با کدی که قسمتهای زائد و بیکیفیتی دارد کار کنیم ولی به نظر میرسد در برنامه به درستی کار میکنند و نمیدانیم دقیقاً چه کاری انجام میدهند یا چه تأثیری روی عملکرد کلی اپلیکیشن دارند. این مسائل باعث میشوند حذف کردن آنها هم مشکلساز باشد.
این اتفاق معمولاً با کدهای باقیمانده از نسخههای قبلی یا کدهایی که توسط فردی دیگر نوشته شدهاند اتفاق میافتد (که معمولاً مستندات مناسبی هم ندارند) یا وقتی پروژه فاز توسعه به تولید را سریعتر از حد معمول طی کرده است.
نام این ضد الگو، به خاطر شباهت آن با گدازههایی است که از دهانهٔ آتشفشان پایین میآیند انتخاب شده است؛ ابتدا خیلی سریع حرکت میکنند و بدون نیاز به احتیاط قابلتغییر هستند، ولی بعداً یکپارچه شده و حتی حذف آنها نیز سخت است.
در تئوری میتوانیم با آزمایشهای وسیع و ریفکتورینگ از شر جریانهای گدازهای در کدنویسی خلاص شویم ولی در عمل، اجرای این کار اغلب سخت یا حتی غیرممکن است؛ به خاطر اینکه جریانات گدازهای معمولاً در بخش Performance (پرفورمنس یا کارایی) هزینهٔ سنگینی به بار میآورند، پس بهتر است با بهکارگیری معماری یا طراحی مناسب از ابتدا، از این ضد الگو اجتناب کنیم.
Hard Coding
هاردکدینگ یکی از آنتی پترنهای شناخته شده است که بیشتر آموزشهای توسعهٔ نرمافزار هم در ابتدا دربارهٔ آن به ما هشدار میدهند. برای مثال، هاردکدینگ هنگامی اتفاق میافتد که مثلاً به جای گرفتن شناسهٔ کاربر از دیتابیس، آن را به صورت دستی -مثلاً یورز آیدی ۱۲- وارد کنیم. گرچه اپلیکیشن ما به درستی کار خواهد کرد اما این در حالی است که کدهای ما فقط در محیط خاص به درستی کار میکنند و وقتی شرایط تغییر میکند ما هم باید سورسکدمان را معمولاً در جاهای مختلف اصلاح کنیم.
Soft Coding
اگر بیش از حد سعی کنیم دچار هارکدینگ نشویم، ممکن است از آن طرف پشت بام بیفتیم! این مسأله که سافت کدینگ نامیده میشود، دقیقاً در نقطهٔ مقابل هارد کدینگ قرار دارد. در این ضدالگو، ما چیزهایی که باید در سورسکد موجود باشد را در منابع خارجی مثل دیتابیس قرار میدهیم. برای مثال، Business Logic یا «منطق اصلی اپلیکیشن» را در دیتابیس ذخیره میکنیم. رایجترین دلیل برای انجام این کار این است که میترسیم قوانین کاری در آینده تغییر کند، بنابراین نیاز به بازنویسی کدها خواهیم داشت.
در بیشتر موارد، برنامهای با ویژگی سافت کد، میتواند بسیار انتزاعی و پیچیده باشد که درک آن تقریباً غیرممکن است (مخصوصاً برای اعضای جدید تیم) و نگهداری و دیباگ آن هم کار طاقتفرسایی است.
موارد فوقالذکر را میتوان به نوعی به عنوان رایجترین خطاهای برنامهنویسی در توسعهٔ نرمافزار قلمداد کرد؛ اما در عین حال، خطاهای دیگری هم وجود دارند که در این مقاله ذکر نشده اما بسیار حائز اهمیت هستند (به طور مثال، میتوانید به مقالهٔ آشنایی با 10 مورد از رایجترین اشتباهات در برنامهنویسی مراجعه نمایید).
به نظر شما چه آنتی پترنهای دیگری وجود دارند که میبایست به عنوان یک طراح نرمافزار از آنها اجتناب کنیم؟ نظرات، دیدگاهها و تجربیات خود را با سایر کاربران سکان آکادمی به اشتراک بگذارید.