شیوه های برنامه نویسی بد جهانی (و جایگزین های آنها) pt.1
تمرکز این پست برجسته کردن است شیوه های برنامه نویسی بدی که می تواند در هر زبان برنامه نویسی یا فریم ورک مدرن رخ دهد. ما سعی خواهیم کرد تا اقدامات بدی را شناسایی کنیم که بدون شک اشتباه هستند و باید از آنها اجتناب شود.
برای تجزیه و تحلیل این اعمال بد، درک اینکه چرا اتفاق میافتند و چگونه میتوان آنها را حل کرد، به یک زبان برنامهنویسی برای نشان دادن چند مثال ملموس نیاز داریم. ما از PHP استفاده خواهیم کرد برای این که من بیشتر با آن آشنا هستم.
بنابراین یکی از شیوه های بد غیرقابل انکار استفاده شده این است که …
(برعکس)
مظنونان معمول ما هستند کشورهای جهانی قابل تغییر
جهانی به این معنی است که می تواند باشد از هر نقطه کد ما قابل دسترسی است. یک مثال معمول برای این پارامتر $_POST، $_GET یا $_SESSION در PHP است.
قابل تغییر به این معنی است که آن می تواند ارزش آن را از همه جا تغییر دهد. پارامتر $_SESSION نمونهای از پارامتری است که قرار است در برنامه ما استفاده شود و میتواند وضعیت آن را تغییر دهد.
دولت وضعیت فعلی است. به عنوان مثال یک کلید چراغ دو حالت دارد. روشن یا خاموش بودن بر اساس تاریخ خود، فقط می تواند از یک ایالت به ایالت دیگر برود. اگر روشن باشد تنها حالتی که می تواند به آن برود خاموش بودن است.
یکی از نمونههای بارز استفاده گسترده از حالتهای جهانی قابل تغییر است متغیر $_SESSION در PHP.
نمونه ای از استفاده کنترل نشده از یک متغیر سراسری🔧
فرض کنید در یک جلسه اطلاعات یک سبد خرید را در یک فروشگاه الکترونیکی ذخیره می کنید. $_SESSION[‘cart’]. استفاده شما از متغیر session توجیه می شود زیرا کاربر در طول بازدید خود نیاز به دسترسی به اطلاعات سبد خرید دارد. بیایید به مثالی از تابعی نگاه کنیم که بر اساس طول سبد خرید تصمیم می گیرد
function sendNotificationEmailBasedOnCartLength() {
if (sizeof($_SESSION['cart']) > 4 && $_SESSION['cart']['hasSentEmail'] == 0) {
sendSomeEmail();
}
$_SESSION['cart']['hasSentEmail'] = 1;
}
تزریق جهانی غیر ضروری ❌
مشکلاتی که تزریق ایجاد می کند:
-
قابلیت نگهداری:
در این مثال می بینیم که یک وجود دارد تزریق غیر ضروری متغیر جهانی $_SESSION[‘cart’] عملکرد داخلی این تابع در این نقطه است وابسته روی متغیر $_SESSION برای عملکرد. حتی اگر بعداً تصمیم بگیریم که راه بهتری برای ذخیره و بازیابی اطلاعات سبد خرید پیدا کردهایم، باید این کار را انجام دهیم هر نقطه که $_SESSION را شناسایی کنید استفاده می شود و استفاده را تغییر می دهد. -
خوانایی:
یکی دیگر از مشکلاتی که از تزریق این متغیرهای سراسری ناشی میشود این است که هر کسی که تابع را میخواند، از ابتدا نمیداند که این متغیرها وجود دارند. واضح نیست زیرا آنها به عنوان پارامتر بیان نمی شوند. این خوانایی کد را کاهش می دهد.
این یک مستعد خطا رویکرد. اگر پروژه شما مجموعه آزمایشی نداشته باشد، باید به آرامی آن را اشکال زدایی کنید و بسیاری از اشتباهات در نهایت در مرحله تولید قرار می گیرند.
تغییر کنترل نشده دولت جهانی
در اینجا ما مقدار hasSentEmail سبد خرید را به 1 تغییر می دهیم تا به برنامه اطلاع دهیم که قبلاً یک ایمیل به این سبد ارسال کرده ایم و دیگر این کار را انجام ندهیم.
کجای دیگر این مقدار تغییر می کند؟ ما مطلقاً هیچ سرنخی نداریم اگر روش کنترل شده ای برای استفاده از این جلسه نداشته باشیم، مقدار hasSentEmail از متغیر $_SESSION می تواند در هر نقطه از برنامه ما از هر تابعی تغییر کند. اگر ما یک session_start() انجام می دهیم و در هر فایلی Session gate را باز می کنیم، ممکن است یک جهش جلسه در هر فایلی وجود داشته باشد. این غیرقابل پیش بینی ایجاد می کند و برنامه ما را بی ثبات می کند.
راه حل ها! 🤔
جهانی بودن $_SESSION را محدود کنید
function sendNotificationEmailBasedOnCartLength(int $cartSize, int $hasEmailBeenSentForCart = 0) {
if ($cartSize > 4 && $hasEmailBeenSentForCart == 0) {
sendSomeEmail();
}
}
ابتدا باید تابع و جلسه را جدا کنید. هر اطلاعاتی را که در مورد جلسه نیاز دارید در داخل پارامترهای تابع ارسال کنید. این متغیر جهانی را به یک متغیر محلی محدود می کند.
با محدود کردن استفاده از آن، $_SESSION را کنترل کنید
دوم، شما نباید به $_SESSION دسترسی داشته باشید[‘cart’] متغیر مستقیما در هر فایلی یک فایل را انتخاب کنید و یک کلاس ایجاد کنید که مسئول ایجاد جلسه، بازیابی و تغییر آن است. با داشتن یک کلاس واحد که مسئول این اقدامات است، میتوانید مطمئن باشید که متغیر سراسری وضعیت غیرمنتظرهای نخواهد داشت.
session_start();
class Cart {
private $products;
public function __constructor() {
if (!$_SESSION['cart']) {
$_SESSION['cart'] = ['products' => [], "emailIsSent" => 0];
}
}
public function initializeCart() {
$_SESSION['cart'] = ['products' => [], "emailIsSent" => 0];
}
public function addProduct(Product $product) {
$_SESSION['cart']['products'][] = $product;
}
public function setEmailIsSent() {
$_SESSION['cart']['emailIsSent'] = 1;
}
public function getCart() {
return $_SESSION['cart'];
}
}
در اینجا می توانید یک مثال ساده از ایجاد کلاسی را ببینید که در آن قرار دارد تنها جهش دهنده و بازیابی $_SESSION[‘cart’]. اگر تصمیم دارید در آینده اطلاعاتی را برای سبد خرید بازیابی کنید یا یک سبد خرید جدید ایجاد کنید به $_SESSION قابل اعتماد نیست[‘cart’] متغیر زیرا می توانید عملکرد این توابع را به هر نحوی که دوست دارید تعویض کنید و برنامه شما به همان صورت کار می کند.
علاوه بر این ما فقط می توانیم تصمیم بگیریم اینها کلاس ها توانایی تعامل با session ها و حذف تمام نمونه های session_start() را از هر جای دیگری خواهند داشت و مطمئن شوید که این متغیر جهانی فقط در این محیط کنترل شده حالت خود را تغییر می دهد.
جلسه[‘cart’] متغیر فقط می تواند مقادیر مشخص شده توسط این کلاس را نگه دارد.
در نتیجه
ما نشان دادیم که چرا جهش غیرقابل کنترل یک متغیر جهانی در برنامه ما بد است زیرا ایجاد می کند:
- غیر قابل پیش بینی بودن
- مسائل مربوط به قابلیت نگهداری
- غیرقابل خواندن
و ما با استفاده از کلاسهایی که جهشها و بازیابی این متغیرها را کنترل میکنند نشان دادیم که چگونه میتوانیم برنامه خود را پاکتر و راحتتر با تغییرات سازگار کنیم.
منابع: