نقل قولهای زیادی، در مورد کیفیت کد وجود دارند. دستور العملهای فراوانی نیز در این راستا وجود دارند. یکی از ابزارهایی که برای نوشتن کدهایی با کیفیت مطلوب وجود دارد، مجموعه الگوهای بد کد نویسی است که به Code smell یا بوی بد کد مشهور هستند.
بوی بد کد، نشانههایی در کد هستند که حکایت از مشکلات عمیقتری دارند. بوی بد کد مساوی با باگ نیست. ولی خطر افزایش باگها و یا مشکلاتی را در آینده، به دنبال خواهند داشت. بوی بد کد معمولا حاصل رعایت نکردن یک سری اصول اولیه برنامه نویسی و یا طراحی شیء گرا هستند.
برای بهبود کیفیت نرم افزار در دراز مدت نیاز است موارد بوی بد کد به دقت بررسی و رفع شوند. رفع شدن آنها ریسک انباشته شدن بوی بد کد را در پروژه کم خواهد کرد. یکی از فواید جلوگیری از انباشته شدن چنین الگوهای بدی در پروژه، بهبود فرآیند نگهداشت آن میباشد که موضوعی بسیار مهم برای چابکی یک تیم نرم افزاری است.
هنگام مشاهدهی بوی بد، در بخشی از کدها، معمولا اولین اقدام، رفع آن است (Refactoring). در فرآیند رفع آن ممکن است الگوهای بد دیگری در کد یافت شوند که با آنها نیز به همین صورت برخورد خواهد شد.
انوع بوهای بد کد به دستههای زیر طبقه بندی میشوند.
کدهای متورم (Bloaters)
این دسته در واقع تکه کدهایی (متد، کلاس و ...) هستند که به دلیل بزرگی بیش از اندازه عملا امکان کار با آنها وجود ندارد. این بخشهای بزرگ کد معمولا با توسعه تدریجی محصول ایجاد و روی هم انباشته میشوند. بوهای بد این دسته بندی به صورت زیر هستند:
1 - متدهای بلند (Long method): در این الگوی بد، متدها تعداد خطهای زیادی از کد را شامل میشوند. به طور معمول متدهایی با تعداد خطوط بیشتر از 10 خط، متدهای بلند محسوب میشوند. نکته قابل توجه این است که هیچ کس متدی را با تعداد خطوط زیاد طراحی نمیکند! معمولا به مرور زمان تعداد خطهای یک متد افزایش مییابند.
2 - کلاسهای بزرگ (Large class): کلاسی که تعداد فیلدها، متدها و خطوط کد زیادی دارد.
3 - وسواس استفاده از متغیرهای دادهای اولیه (Primitive obsession): این بوی بد معمولا به سه شکل بروز میکند.
- استفاده از متغیرهای اولیه بجای ساختارهای کوچک برای کارهای اولیه مانند Currency, DateTime, PhoneNumber
- استفاده از constantها برای کد کردن اطلاعات مانند USER_ADMIN_ROLE = 1
- استفاده از constantهای رشتهای به عنوان نام فیلدها در آرایههای داده
4 - تعداد پارامترهای زیاد متد (Long parameter list): تعداد پارامترهای بیشتر از سه یا چهار عدد در یک متد.
5 - توده داده (Data clumps): در بعضی موارد ممکن است از متغیرها به صورت دستهای در مکانهای مختلف کد استفاده شود. مانند استفاده از دستهای از متغیرها برای نگه داشتن اطلاعات مربوط به اتصال پایگاه داده. این دستهها باید به کلاسهای حمل کننده داده خود تغییر کنند.
بد استفاده کنندگان از شیء گرایی (Object orientation abusers)
تکه کدهای این بخش در واقع بد استفاده کنندگاه یا ناقص استفاده کنندگان از اصول شیء گرایی هستند. در این دسته بندی موارد زیر وجود دارند:
1 - گذارههای switch: وجود یک گذاره switch پیچیده یا دنبالهای از گذارههای if
2 - درخواست رد شده (Refused request): در این حالت یک کلاس مجموعه محدودی از اعضای کلاس پدر خود را پیاده سازی میکند و باقی اعضای کلاس پدر یا بدون استفاده میمانند یا با استفاده از پرتاب کردن استثناء (Exception throwing) از کار انداخته میشوند.
3 - فیلد موقتی (Temporary field): در این حالت متغیرها مقدار خود را در شرایط خاصی میگیرند و در بقیه شرایط خالی هستند.
4 - کلاس هایی دقیقا مشابه در کارایی ولی متفاوت در مشخصات (Alternative Classes with Different Interfaces): دو کلاس دقیقا یک کار را انجام میدهند ولی نام اعضای آنها (متد و ...) متفاوت است.
جلوگیری کنندگان از تغییر(Change preventers)
این نشانهها حاکی از این دارند زمانیکه تغییری در یک بخش کد نیاز باشد، در راستای آن حتما باید دیگر بخشهای کد نیز به مقدار زیادی تغییر کنند. در این حالات اعمال تغییرات و نگهداری کد به شدت سخت خواهد شد.
مواردی که در این دسته بندی قرار دارند به صورت زیر میباشند:
1 - تغییر واگرا (Divergent change): این حالت زمانی اتفاق میافتد که برای اعمال یک تغییر به کلاس نیاز است متدهای زیادی را تغییر دهید. به طور مثال به ازای هر نوع محصولی که به محصولات شما اضافه میشود باید متدهای ذخیره، بازیابی، جستجو را تغییر دهید.
2 - Shotgun Surgery: این حالت شباهت زیادی به تغییر واگرا دارد. تنها تفاوت آن این است که در این حالت شما به ازای هر تغییر نیاز است کلاسهای زیادی را تغییر دهید. تغییر واگرا در بدنه یک کلاس اتفاق میافتد.
3 - سلسله مراتب موازی ارث بری (Parallel inheritance hierarchy): این مورد یکی کمتر درک شدهترین موارد است. در این حالت زمانی که یک زیر کلاس برای یک کلاس ایجاد میکنید به ازای آن ناخودآگاه مجبور میشوید یک زیر کلاس برای کلاس دیگری ایجاد کنید.
کدهای غیر ضروری (Dispensables)
این دسته از کدها معمولا کدهایی هستند بی دلیل و بی استفاده. کدهایی که نبودنشان بهتر از بودنشان است! حذف کردن این کدها به خوانایی و قابلیت نگهداری کد خواهد افزود. بوهای بدی که در این دسته بندی قرار دارند به صورت زیر میباشند:
1 - کامنت: یک متد، با مقادیر فراوانی از کامنتهای توضیحی پر شده است.
2 - کد تکراری: در این بوی بد، دو قطعه کد دقیقا مانند یکدیگر هستند.
3 - کلاس داده (ِData class): کلاسهایی که تنها فیلدهای اطلاعاتی در آنها وجود دارند و متدهای خامی که جهت دریافت یا ذخیره اطلاعات در آنها استفاده میشوند. این کلاسهای معمولا هیچ روال منطقی ای در خود ندارند. یکی از قدرتهای شیء گرایی افزودن رفتار به کلاسها در کنار اقلام اطلاعاتی موجود در آن است.
4 - کلاس تنبل (Lazy class): اگر کلاس کار چندانی که درخور نگهداری و توسعه باشد، انجام نمیدهد بهتر است از بین برود.
5 - کد مرده (Dead code): متغیر، پارامتر، متد یا کلاسی که دیگر هیچ استفادهای از آن متصور نیست و هیچ استفادهای در حال حاضر از آن وجود ندارد.
6 - کلی نگری بیش از اندازه (Speculative Generality): این الگو نیز کدهایی را شامل میشود که بلااستفاده هستند. ولی دلیل بلااستفاده بودن آن کلی نگری و دور اندیشی بدون دلیل است. معمولا کدهای تولیدی برای شرایط فعلی و پیشبینی آینده تولید میشوند. اگر این پیشبینی آینده به درستی و بر مبنای واقعیات انجام نشود، معمولا نتیجه کار، طراحی و پیاده سازی ای بی فایده و بلااستفاده خواهد بود.
کدهایی بیش از اندازه وابسته به هم (Couplers)
کدهایی که در این دسته قرار میگیرند معمولا یا خود درگیر یک وابستگی شدید هستند یا به ایجاد وابستگی بین کلاسها کمک میکنند. بویهای بدی که در این دسته بندی قرار میگیرند به صورت زیر هستند:
1- متد حسود (Feature envy): متدی که از اعضای یک شیء دیگر بیشتر از اعضای کلاس خود استفاده میکند! این اتفاق معمولا زمانی میافتد که فیلدهایی به یک "کلاس داده" منتقل میشوند. وقتی این اتفاق میافتد یکی از راه حلها، انتقال روالهای استفاده کننده از فیلدها به "کلاس داده" مربوطه است.
2 - کلاسهای بیش از اندازه صمیمی (Inappropriate Intimacy): کلاسها از اعضای internal یکدیگر بیش از اندازه استفاده میکنند. کلاسهای خوب کلاسهایی هستند که کمترین اطلاعی را از وضعیت داخلی یکدیگر دارند.
3 - کتابخانههای ناقص (Incomplete Library Class): زمانیکه کتابخانهای آماده میشود، بالاخره روزی میرسد که این کتابخانه نیازهای پروژه را رفع نمیکند و نیاز به توسعه خواهد داشت. ولی از آنجایی که کتابخانهها به صورت فقط خواندنی در اختیار پروژهها قرار میگیرند، در صورتیکه توسعه دهنده اصلی آن از توسعه کتابخانه سر باز بزند، مشکلاتی بوجود خواهد آمد.
4 - زنجیره فراخوانیها (Message chain): زمانیکه یک متد در بدنه خود پیامی به شیء دیگری میفرستد که آن شیء نیز به خودی خود پیامی به شیء دیگری میفرستد (و الی آخر) یک زنجیره فراخوانی بوجود آمده است. در این روش بیرونیترین استفاده کننده از متد در واقع وابسته به یک زنجیرهای از فراخوانیها است که تغییر در هر قدمی از آن باعث خرابی خواهد شد.
5 - دلال (Middle man): اگر کلاسی تنها کاری که انجام میدهد انتقال فراخوانی به کلاس دیگری است، دیگر نیازی به این کلاس وجود نخواهد داشت.
اطلاع از الگوهای بد کد نویسی به همان اندازه اطلاع از الگوهای خوب کد نویسی در کیفیت محصول تولیدی اثر مثبت خواهند داشت. یادگیری طبقه بندی شده این الگوها کار را برای استفاده روزمره از آنها آسانتر خواهد کرد.
Twitter Bootstrap
Foundation
Blueprint
Skeleton
Less Framework
YAML
Gumby
Wirefy
Golden Grid System
BluCSS
Amazium
The 1140 CSS Grid
320 and Up
Titan Framework
Columnal
Gridless
InuitCSS
از فریم ورکها استفاده نمی کنم
قالب ساده خاص خودم را دارم
فریم ورک توسعه یافته شرکتی
جهت هر وب سایت، قالبی خاص خودش را طراحی میکنم
Unsemantic
960 GS
Foundation
Blueprint
Skeleton
Less Framework
YAML
Gumby
Wirefy
Golden Grid System
BluCSS
Amazium
The 1140 CSS Grid
320 and Up
Titan Framework
Columnal
Gridless
InuitCSS
از فریم ورکها استفاده نمی کنم
قالب ساده خاص خودم را دارم
فریم ورک توسعه یافته شرکتی
جهت هر وب سایت، قالبی خاص خودش را طراحی میکنم
Unsemantic
960 GS
As software creation processes continue to become more complicated, development teams are taking a more all-encompassing approach that involves agile testing methodologies. Like agile software development, agile testing involves running test cases that assess the overall integrity of a solution, rather than simply ensuring that each part and piece are technically sound. Viewed as an analogy, agile testing methodologies ensure that software is a well-oiled machine, whereas a linear approach to testing just ensures that each of the gears is in good order. Herein lies the difference between unit tests and test automation.
اشتراکها
ویدیوهای کنفرانس DevTernity 2022
اشتراکها
معماری یک برنامه dotcore
اشتراکها
سری ویدیوهای کدنویسی تمیز
اشتراکها
معنای معمار نرمافزار بودن
اشتراکها