Defensive Programming در برنامه‌نویسی به چه معنا است؟

Defensive Programming در برنامه‌نویسی به چه معنا است؟

"برنامه نویسی تدافعی" به چه معنا است؟ اگر بخواهیم به طور ساده توضیح دهیم، برنامه نویسی تدافعی یک سبک برنامه نویسی با هدف پیش بینی حفره های امنیتی و نقاط ضعف احتمالی است. هدف نهایی این مدل برنامه نویسی، جلوگیری از بروز مسائل احتمالی قبل از رویداد آن ها است اگرچه که هنوز رخ نداده است. توصیه ای وجود دارد با این مضمون که: "غیر قابل پیش بینی را پیش بینی کن" و زمانی که برنامه نویسی تدافعی یا Defensive Programming آن را تکمیل می کند و به شما می گوید "غیر قابل پیش بینی را پیش بینی کن و تلاش کن که از اتفاق افتادن آن جلوگیری کنی" این پیچیدگی بیش تر می شود. برای آن که این پیچیدگی را کمی ساده تر کنیم نیاز به ذکر چند نمونه داریم. پس با سکان آکادمی همراه باشید.

دستورات شرطی
یکی از بخش های برنامه ها که شما می توانید به راحت ترین شکل برنامه نویسی تدافعی را در آن ها پیاده سازی کنید و از نتایج حاصل از آن رضایتمند باشید، قطعه کدهایی هستند که حاوی دستورات شرطی اند (در این مقاله، زبان برنامه نویسی PHP را مبنا قرار می دهیم.) در بسیاری از موارد، زمانی که به زبان پی اچ پی برنامه می نویسید، به راحتی نیازی به استفاده از دستور "else" نخواهید داشت. اما آیا حقیقتاً باید از قرار دادن بلوک دستورات مربوط به آن چشم پوشی کنید؟

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

if($var == a){ }
elseif($var == b){ }
elseif($var == c){ }

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

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

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

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

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

فرضیات در مورد کدهای شما
هیچ چیز را فرض قرار ندهید. اگر دو موضوع قبلی چیزی به ما یاد داده باشند، این است که ما نباید هیچ فرضی را برقرار سازیم. به عنوان یک برنامه نویس، به ویژه زمانی که برای یک مدت طولانی روی یک پروژه متمرکز می شویم، شروع می کنیم که فرضیات زیادی را در مورد پروژه قرار دهیم. شروع می کنیم به این که فرض کنیم کاربران بعضی چیزهایی را که ما می دانیم می دانند. نه لزوماً جزئیات فنی را، بلکه جزئیات عملکردی و کاربردی برنامه را.  فرض می کنیم که کاربران خواهند دانست که فایل های بزرگ چگونه می توانند باشند، زیرا ما خودمان از آن موضوع آگاهیم . . . اما این طور نیست، آن ها هیچ ایده ای در مورد چنین چیزهایی ندارند. گاهی این می تواند برای کارهای front-end اهمیت بیش تری داشته باشد، اما به وضوح شما هنوز با رفتارها و ورودی های کاربران در back-end هم سر و کار دارید، پس ارزش آن را دارد که در این باره فکر کنید.

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

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

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

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

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

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

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

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

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