مفهوم Clean Code در PHP

مفهوم Clean Code در PHP

در این نوشته به بررسی مباحث مربوط به کد تمیز یا clean code در زبان برنامه نویسی PHP می پردازیم.

در این نوشته یک ریپوزیتوری از گیت هاب را ترجمه و بازنویسی کرده ام.

 

آپدیت : لینک ترجمه ی من به پروژه ی اصلی اضافه شد. 🙂

 

آدرس ریپوزیتوری اصلی:

https://github.com/jupeter/clean-code-php

آدرس این ترجمه روی گیت هاب:

https://github.com/amirshnll/clean-code-php

پیشنهاد نویسنده: کد تمیز در javascript

 

مفهوم Clean Code در PHP

اصول مهندسی نرم افزار ، از کتاب Robert Code Martin Clean Code ، اقتباس گرفته شده است تا در این نوشته اصول آن برای زبان برنامه نویسی PHP را بررسی کنیم. این یک راهنمای ساده نیست. این یک راهنما برای تولید نرم افزارهای قابل خواندن با خوانایی بالا، قابل استفاده مجدد در زبان برنامه نویسی پی اچ پی است.

لازم نیست که هر اصلی که گفته شد دقیقاً رعایت شود، و حتی تعداد کمتر مورد توافق همه توسعه دهدگان قرار خواهند گرفت. این ها رهنمودهایی هستند و چیز دیگری فراتر از این نیستند، اما مواردی هستند که در طول چندین سال تجربه جمعی توسط نویسندگان Clean Code نوشته شده است.

اگرچه بسیاری از توسعه دهندگان هنوز از PHP 5 استفاده می کنند ، اما بیشتر نمونه های این مقاله فقط با PHP 7.1+ کار می کنند.

 

متغیرها در Clean Code

از نام های متغیر معنی دار و قابل تلفظ استفاده کنید:
روش نادرست نام گذاری معنا دار متغیرها:

روش صحیح نام گذاری معنا دار متغیرها:

از همان واژگان برای همان نوع متغیر استفاده کنید:
روش نادرست انتخاب واژگان برای نوع متغیرها:

روش صحیح انتخاب واژگان برای نوع متغیرها:

 

از نام های قابل جستجو استفاده کنید

ما بیشتر از آنچه را که می نویسیم کدها را می خوانیم. مهم است که کدی که می نویسیم قابل خواندن و قابل جستجو باشد. با انتخاب نام برای متغیرهایی که در نهایت برای درک برنامه ما معنی دار تر هستند کدهای خود را ساده تر می کنیم. نام های متغیرهای خود را در برنامه ی مورد نظرتان قابل جستجو انتخاب کنید.

روش نادرست انتخاب متغیرهای قابل جستجو حالت اول:

روش صحیح انتخاب متغیرهای قابل جستجو حالت اول:

یک حالت دیگر هم :

روش نادرست انتخاب متغیرهای قابل جستجو حالت دوم:

روش صحیح انتخاب متغیرهای قابل جستجو حالت دوم:

 

از متغیرهای توضیحی استفاده کنید
روش نادرست برای متغیرهای توضیحی:

روش معمول برای متغیرهای توضیحی:

این حالت از حالت بالایی بهتر است، اما هنوز به شدت به regex وابسته هستیم.

روش صحیح برای متغیرهای توضیحی:

با نامگذاری الگوهای فرعی وابستگی به regex را کاهش می دهیم.

 

خودداری از ساختارهای تودرتو

با if-else های زیاد و طولانی و تو در تو خواندن کد شما دشوار می شود. برای این کار از متغیرهای صریح استفاده کنید.

حالت نادرست ساختارهای تودرتو – حالت اول:

حالت صحیح متغیرهای تودرتو – حالت اول:

حالت نادرست ساختارهای تودرتو – حالت دوم:

حالت صحیح متغیرهای تودرتو – حالت دوم :

 

از نگاشت ذهنی خودداری کنید (Avoid Mental Mapping)

خواننده کد خود را مجبور نکنید که معنی متغیر را ترجمه کند. همیشه استفاده از نام های صریح بهتر از نام های ضمنی است.

حالت نادرست انتخاب نام متغیر به صورت نگاشت ذهنی:

حالت صحیح انتخاب نام متغیر به صورت نگاشت ذهنی:

 

نیاز به تکرار نام شی در متغیرها نیست

برای نام گذاری اعضای یک کلاس نیاز به استفاده از نام کلاس در نام آن ها نیست.

حالت نادرست استفاده از نام شی در کنار اعضا کلاس:

حالت صحیح استفاده از نام شی در کنار اعضا کلاس:

 

از آرگومان های پیش فرض به جای اتصال کوتاه یا شرطی استفاده کنید
حالت نادرست استفاده از آرگومان های پیش فرض:

استفاده از $breweryName مناسب نیست زیرا می تواند NULL باشد.

حالت معمول تر استفاده از آرگومان های پیش فرض:

این حالت بهتر از حالت قبلی است زیرا قابل درک تر است اما ارزش متغیر را نیز می توان بهتر کنترل کرد.

حالت صحیح استفاده از آرگومان های پیش فرض:

می توانید از type hinting استفاده کنید و مطمئن باشید که مقدار $breweryName برابر NULL نخواهد بود.

 

ساختارهای مقایسه ای در Clean Code

از مقایسه با نوع یکسان استفاده کنید
حالت نادرست مقایسه بدون در نظر گرفتن نوع:

در مقایسه ی ساده رشته ها و اعداد رشته به صورت یکسان در نظر گرفته می شود.

مقایسه متغیر a و b برابر FALSE است اما در واقع TRUE است! رشته 42 با عدد 42 متفاوت است.

حالت صحیح مقایسه بدون در نظر گرفتن نوع:

در این حالت مقایسه هم با نوع متغیر و هم با مقدار آن انجام می شود.

مقایسه ی a با b در کد بالا برابر TRUE خواهد شد.

 

اپراتورهای اتصال NULL

null coalescing عملگر جدیدی است که در PHP 7 معرفی شده است. null coalescing را با علامت ?? می نویسیم که اگر درست باشد عملوند اول خود را برمی گرداند در غیر اینصورت عملوند دوم خود را بر می گرداند؛ به طور کلی به جای isset استفاده می شود.

حالت نادرست کار با عملگر null coalescing

حالت صحیح کار با عملگر null coalescing

 

توابع در Clean Code

آرگومان های توابع (حالت ایده آل 2 آرگومان یا کمتر)

محدود کردن مقدار پارامترهای توابع بسیار مهم است زیرا تست عملکرد کدهای شما آسان تر می شود. داشتن بیش از سه مورد منجر به سختی در عملیات تست و ردگیری خطا می شود.

تعداد صفر ایده آل است؛ بین یک تا دو خوب است؛ بیش از سه مناسب نیست.

اگر بیش از سه آرگومان دارید احتمالا چند کار را در یک کار انجام می دهید که نباید اینگونه باشد و احتمالا استدلال شما از یک شی نادرست است.

حالت نادرست آرگومان های توابع:

حالت صحیح آرگومان های توابع:

 

نام تابع باید بگوید که چه کاری انجام می دهد
انتخاب نادرست نام تابع در PHP:

انتخاب صحیح نام تابع در PHP:

 

توابع فقط باید شامل یک سطح انتزاع باشند

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

حالت نادرست ساخت توابع طولانی:

حالت صحیح شکستن توابع طولانی:

بهترین راه حل ، حذف وابستگی های تابع parseBetterPHPAlternative است.

 

از flagها به عنوان پارامترهای توابع استفاده نکنید
حالت نادرست در استفاده از flagها:

flagها به کاربر شما می گویند که این تابع بیش از یک کار انجام می دهد. توابع باید یک کار انجام دهند. اگر توابع شما براساس کدهای boolean دنبال می شوند، توابع خود را تجزیه کنید.

حالت صحیح در استفاده از flagها:

 

از عوارض جانبی یا Side Effects خودداری کنید

به جای اینکه مقدار یک تابع در یک متغیر global نوشته شود به صورت غیر void آنرا تعریف کنید و مقدار را برگردانید.

استفاده از side effects – نادرست:

عدم استفاده از side effects – صحیح:

 

از نوشتن توابع عمومی جلوگیری کنید.

مفهوم Polluting globals یک عمل بد در بسیاری از زبان های برنامه نویسی می باشد چون شما می توانید با یک کتابخانه یا API دیگری این کار را انجام دهید.

برای مثال: اگر بخواهید یک آرایه ی configuration بسازید چه می کنید؟ شما می توانید یک تابع عمومی config بنویسید یا با یک کتابخانه ی دیگر این کار را انجام دهید.

نوشتن توابع عمومی – نادرست:

نوشتن توابع عمومی – صحیح:

Configuration را یک بار لود کنید و یک نمونه از Configuration بسازید.

و اکنون باید از نمونه ی Configuration که ساخته اید در برنامه خود استفاده کنید.

 

از Singleton pattern استفاده نکنید
حالت نادرست:

حالت صحیح:

نمونه ای از کلاس DBConnection ایجاد کرده و آن را با DSN پیکربندی کنید.

و اکنون باید از نمونه DBConnection در برنامه خود استفاده کنید.

 

دستورات شرطی را کپسوله سازی کنید
حالت نادرست – کپسوله سازی دستورات شرطی:

حالت صحیح – کپسوله سازی دستورات شرطی:

 

از استفاده ی شروط منفی جلوگیری کنید
حالت نادرست شروط منفی:

حالت صحیح شروط منفی:

 

از شرطی شدن اجتناب کنید

به نظر می رسد این یک کار غیرممکن است. با شنیدن این موضوع احتمالا همه ی برنامه نویسان عزیز می گویند “چگونه قرار است بدون if ، کاری انجام دهیم؟” پاسخ این است که شما می توانید برای رسیدن به همان کار در بسیاری از موارد از چند case استفاده کنید. سوال دوم معمولاً این است ، “خوب این عالی است اما چرا من می خواهم این کار را انجام دهم؟” پاسخ این است که مفهوم قبلی که در ارتباط با clean code خواندیم این است که یک تابع فقط باید یک کار واحد انجام دهد. وقتی کلاس ها و توابعی را دارید که دستور if دارند ، به خواننده ی کد خود می گویید عملکرد این بخش شما بیش از یک کار را انجام می دهد. به یاد داشته باشید ، فقط یک کار را باید انجام دهید.

حالت نادرست شرطی شدن:

حالت صحیح شرطی شدن:

 

از بررسی نوع خودداری کنید

در زبان برنامه نویسی PHP بررسی نوع نداریم اگر برای این موضوع وسواس دارید باید با یک تابع استفاده کنید که بهتر است این کار را انجام ندهید.

روش نادرست – حالت اول:

روش صحیح – حالت اول:

اگر با مقادیر ابتدایی اولیه مانند رشته ها ، اعداد صحیح و آرایه ها کار می کنید و از PHP 7+ استفاده می کنید و نمی توانید از polymorphism استفاده کنید اما هنوز هم به بررسی نوع نیاز دارید ، باید اعلام نوع یا حالت سخت را در نظر بگیرید. نوع ایستا در بالای نحو استاندارد PHP را برای شما فراهم می کند. مشکلی که در بررسی دستی نوع وجود دارد این است که انجام آن به بخش اضافی نیاز دارد که type-safety ساختگی شما خوانایی از دست رفته را جبران نمی کند.

کدهای PHP خود را به صورت Clean Code نگه دارید ، تست های خوبی بنویسید و بررسی های خوبی در مورد کد داشته باشید. در غیر این صورت ، همه این کارها با اعلام نوع دقیق PHP یا حالت دقیق انجام دهید.

روش نادرست – حالت دوم:

روش صحیح – حالت دوم:

 

حذف کد مرده

کد مرده به همان اندازه ای که کد تکراری بد است نامناسب است. هیچ دلیلی وجود ندارد که آن را در کدهای خود نگه دارید. اگر کدی فراخوانی نمی شود، خلاص شوید!

حالت نادرست – کد مرده

حالت صحیح – کد مرده

 

اشیا و ساختارهای داده (Objects and Data Structures) در Clean Code

استفاده از کپسوله سازی اشیا

در PHP می توانید کلمات کلیدی public, protected, privaten داریم که با استفاده از آن ، می توانید دسترسی به ویژگی ها را روی یک اشیا کنترل کنید.

حالت نادرست:

حالت صحیح:

 

اعضای اشیا را با protected, private تعریف کنید

برای اطلاعات بیشتر این نوشته را از Fabien Potencier بخوانید.

روش نادرست:

روش صحیح:

 

کلاس ها در PHP در Clean Code

ترکیب را بر ارث بری ترجیح دهید

ابتدا بهتر است کمی در ارتباط با Design Patternها بخوانید.

حالت نادرست:

حالت صحیح:

 

از استفاده ی fluent interfaces خودکاری کنید

در ارتباط با fluent interfaces ها بخوانید؛ برای بهتر متوجه شدن این موضوع این نوشته را از Marco Pivetta بخوانید.

حالت نادرست:

حالت صحیح:

 

کلاس های final را ترجیح دهید
حالت نادرست:

حالت صحیح:

 

SOLID در Clean Code

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

 

Single Responsibility Principle یا SRP

همانطور که در Clean Code بیان شد ، “هرگز نباید بیش از یک کار برای یک کلاس وجود داشته باشد”. بسته بندی کلاس هایی که قابلیت های زیادی دارند ، وسوسه انگیز است ، مانند زمانی که فقط اجازه دارید یک چمدان را در پرواز با خود حمل کنید. مسئله این است که کلاس شما از نظر مفهومی منسجم نخواهد بود و دلایل زیادی برای تغییر در آن ایجاد می کند. به حداقل رساندن تعداد دفعات لازم برای تغییر کلاس مهم است. این مهم است زیرا اگر کارایی بیش از حد در یک کلاس وجود دارد و شما بخشی از آن را اصلاح می کنید ، درک اینکه چگونه این امر بر سایر ماژول های وابسته در کد شما تأثیر می گذارد دشوار است.

حالت نادرست SRP :

حالت صحیح SRP :

 

Open/Closed Principle یا OCP

همانطور که برتراند مایر اظهار داشت ، “نهادهای نرم افزاری (کلاسها ، ماژولها ، توابع و …) باید برای پسوند باز باشند، اما برای اصلاح بسته هستند.”

این به چه معناست؟ این اصل در اصل بیان می کند که شما باید به افرادی که کد شما را می خوانند اجازه دهید ویژگی های جدید را بدون تغییر کد موجود اضافه کنند.

حالت نادرست OCP :

حالت صحیح OCP :

 

Liskov Substitution Principle یا LSP
روش نادرست LSP:

روش صحیح LSP:

 

Interface Segregation Principle یا ISP
روش نادرست ISP:

روش صحیح ISP:

هر کارگری یک کارمند نیست ، بلکه هر کارمندی یک کارگر است.

 

Dependency Inversion Principle یا DIP

این اصل دو چیز اساسی را بیان می کند:

  • ماژول های سطح بالا نباید به ماژول های سطح پایین وابسته باشند. هر دو باید به Abstractionها بستگی داشته باشند.
  • Abstractionها نباید به جزئیات بستگی داشته باشد. جزئیات باید به Abstractionها بستگی داشته باشد.
حالت نادرست DIP :

حالت صحیح DIP :

 

اصل DRY

کلمه ی DRY مخفف Don’t repeat yourself است. سعی کنید اصل DRY را رعایت کنید.

تمام تلاش خود را انجام دهید تا از نوشتن کدهای تکراری جلوگیری کنید. کد تکراری بد است زیرا به این معنی است که در صورت نیاز به تغییر منطق در ساختار برنامه، بیش از یک مکان برای تغییر دادن چیزی وجود دارد که باید آن را انجام دهید.

تصور کنید اگر یک رستوران اداره می کنید و موجودی خود را پیگیری می کنید: تمام گوجه فرنگی ، پیاز ، سیر ، ادویه جات و … را در لیست نوشته باشید. اگر چندین لیست دارید که این مورد را در آن نگه می دارید ، پس هنگام تهیه یک غذا با گوجه فرنگی همه ی لیست ها باید به روز شوند ولی اگر فقط یک لیست موجودی دارید ، فقط یک جا برای به روزرسانی وجود دارد که باید آنرا تغییر دهید!!

اگر غالباً کد تکراری دارید علت آن این است که دو یا چند چیز کمی متفاوت دارید که اشتراکات زیادی با هم دارند، اما تفاوت آن ها شما را مجبور می کند که دو یا چند عملکرد جداگانه برای آن ها داشته باشید که بیشتر کارهای مشابه را انجام می دهند. حذف کد تکراری به معنای ایجاد انتزاعی است که می تواند مجموعه ای از موارد مختلف را فقط با یک تابع / ماژول / کلاس مدیریت کند.

درست گرفتن انتزاع بسیار مهم است، به همین دلیل باید از اصول SOLID مندرج در بخش Class ها پیروی کنید. انتزاعات بد ممکن است از کد تکراری بدتر باشد، بنابراین مراقب باشید! با گفتن این، اگر می توانید انتزاع خوبی انجام دهید، آن را انجام دهید! کدتان را مجددا تکرار نکنید، در غیر این صورت هر زمان که بخواهید یک چیز را تغییر دهید باید بخش های مختلفی را ویرایش کنید.

کد نادرست بدون اصل DRY:

کد صحیح با استفاده از اصل DRY:

حالت عالی (کد فشرده) با استفاده از اصل DRY:

بهتر است از نسخه فشرده کد استفاده کنید.

 

 

منبع:

https://github.com/jupeter/clean-code-php

 

ترجمه:

ترجمه ی این مقاله به زبان های دیگر نیز موجود است:

 

اگر نظری در ارتباط با این نوشته دارید در بخش نظرات همین نوشته برای من بنویسید.

1 Comment

Add Yours →

دیدگاهتان را بنویسید