آنتروپی (Software Entropy) : هر چه پروژه رو به جلو پیش بره، پیچیدگی اون هم بیشتر میشه. در نتیجه تعداد خطاهای از پیش تعین نشده و استثناء ها هم بیشتر میشه. بنابراین نیاز به مدیریت خطاها (Error Handling) و استثناها (Exception) به نسبت بیشتر احساس میشه. این یعنی ما باید راه حل هایی رو دریابیم تا از خطاهای احتمالی جلوگیری کنیم، یا اونها رو با روش جایگزین مدیریت کنیم و یا حداقل کاری که میتونیم انجام بدیم، پیامی مناسب به کاربران و همچنین به تیم توسعه نمایش بدیم. که بتوانند با استفاده از پیامها از وجود تناقض در روند اجرای سیستم مطلع بشوند.
بگذارید قبل از شروع مقاله، ما تابعی رو برای خودمون به عنوان یک مثال بنویسیم تا بتونیم اون رو مرحله به مرحله بهبود ببخشیم و باهم بازنویسی کنیم.
اینجا تابعی رو داریم که قرار هست، رایانامه (از طریق پارامتر email)، نام (از طریق پارامتر name) و سن کاربرانمون (از طریق پارامتر age) دریافت کنیم و پس از انجام فرآیند لازم، اون رو به خبرخوان خودمون مشترک کنیم. پس مینویسیم:
تا اینجای ماجرا همه چی به نظر خوب میرسه اما اینکه ما مطمئن نیستیم که تابع ما دقیقا همون چیزهایی رو دریافت میکنند که باید باشند. تایپاسکریپت با ارائه قابلیت تایپ ها به ما کمک زیادی کردند اما آیا کافی هستند. پس ما نیاز داریم تا داده هامون رو بیشتر بررسی کنیم تا از درست بودن مقادیر اونها مطمئنتر بشیم. مثلا این سوال رو باید از خودمون بپرسیم که «آیا پارامتر email دقیقا شامل یک ایمیل میشه یا صرفا یه داده با نوع string هست؟» یا به عنوان مثال، «مقدار age آیا شامل اعداد منفی هم میشه یا نه؟».
برای پاسخ دادن به این پرسش ها ما در تابع تغییراتی رو اعمال میکنیم تا از دادههایی که از پارامترها میگیریم مطمئن بشیم. در اولین سطر از تابع، دادهها و مقادیر اونها رو بررسی میکنیم و تابع رو به شکل زیر بازنویسی میکنیم:
بهتر شد، حالا مطمئن هستیم که همه چی درست کار میکنه. و این یعنی عملکرد برنامه نسبتا تحت کنترل ما است.
باید بگم، ابتدا ما مقدار email رو بررسی میکنیم تا مطمئن بشیم مقدار وارد شده دقیقا همون چیزی هست که ما میخواهیم و در صورت نادرست بودن مقدار، با استفاده از کلیدواژه `throw`، تابع در همان خطی که این کلیدواژه صدا زده شده متوقف میشه و هر چیزی که در جلوی کلیدواژه throw باشه رو به توابع بالاتر که تابع ما رو صدا زدهاند اطلاع میدیم که یک خطایی رخ داده و داخل خطا هم پیام خطا رو مینویسیم و در بالاترین(یا جایی که نیاز هست) با استفاده از بلاک try/catch خطا ها رو دریافت میکنیم و واکنش خودمون رو نسبت به این پیام نشون میدیم. با این کار، ما حتی یک قدم هم به راحتتر و سریعتر دیباگ کردن نزدیک میشیم و هم میتونیم به تجربه کاربری بهتری دست پیدا کنیم. یعنی، میتونیم در صورت اشتباه بودن مقادیر، اون ها رو لاگ بگیریم. و برای کاربر هم پیام مناسب رو نمایش بدیم که «رایانامه وارد شده نادرست است». اینجوری حتی کاربر نهایی ما هم متوجه میشه که رایانامه وارد شده رو تصحیح کنه.
به نظر میرسه خوانایی و توسعهپذیری رو قربانی عملکرد کرده باشیم، اینطور نیست؟
از خودمون باید بپرسیم «نمیشه این تکه کد از این تابع با همون عملکرد و حتی خوانایی بهتر نوشت؟» در واقع، «نمیشه بهتر از این باشه که بعدا اگر کسی خواست بعد از شما یا حتی خود شما این تابع رو توسعه بده توانایی این کار رو فقط در چند ثانیه داشته باشه؟»
البته که شدنی هست، فقط کافیه به جای استفاده از if-else های تودرتو اون ها رو خطی کنیم:
به نظر، خواناتر شد. و البته که در عملکرد هم تغییری ایجاد نشد و تابع همچنان همان تابع با همان عملکرد هست. اما بیاییم کمی دوباره بهش نگاه بندازیم و از خودمون بپرسیم بهتر از این هم میشد نوشت؟ همچنین درباره تجربه کاربری بهتر برای کاربر چطور؟ آیا پیام خشک و خالی «رایانامه وارد شده صحیح نمی باشد» کافی به نظر میاد؟ آیا اگه دوباره بنویسیم در رفتار تابع تغییر ایجاد میشه؟ امکان نداره بهتر از این باشه.
اینجا باید به شما بگم. بهتر از این هم میتونه باشه. پس ما تابعمون رو دوباره بازنویسی میکنیم. و برای هر شرط بررسی، یک تابع مجزا برای خودش ایجاد میکنیم.
برای تشخیص email مینویسیم:
برای بررسی پارامتر age مینویسیم:
برای اعتبارسنجی پارامتر name هم مینویسیم:
داره جالبتر میشه. مثل اینکه ما داریم اصول SOLID رو هم رعایت میکنیم به طوری که تابع subscribe که هم وظیفه اعتبارسنجی و هم وظیفه نامنویسی خبرخوان رو داشت، به بخشهای کوچکتری تقسیم میشه و حالا هر بخش که یک تابع مجزای برای وظیفه خودش هست، داره به درستی وظیفه خودش رو انجام میده، به طوری که ما Single Responsibility Principle رو رعایت کردهایم.
حالا وقت اون رسیده خود تابع subscribe رو بازنویسی کنیم:
هووم، رفتار تابع تغییر نکرد. خوانایی تابع افزایش پیدا کرد و به دنبال اون، توسعهپذیری رو هم افزایش دادیم.
اما هنوز نتونیستیم تجربه کاربری رو بهبود ببخشیم. روشی هست که بشه؟ بله قطعا. وقتی ما توابع اعتبارسنجی رو جدا کردیم، دستمون برای توسعه و تغییر به مراتب بازتر میشه. پس بیاییم تغییرات لازم رو اعمال کنیم.
در نتیجه شروط لازم و پیامهای لازم برای پارامتر email رو بیشتر میکنیم و تابع validateEmail به شکل زیر بازنویسی میشه:
و برای پارامتر age هم میشه:
برای پارامتر نام هم داریم:
با این روش، هم دقیقتر به کاربر برای تجربه کاربری کمک کردیم. هم به خودمون برای توسعهپذیر تر کردن توابعهایی که مینویسیم.
البته میشه این توابع رو با استفاده از کتابخونههای اعتبارسنجی بهبود بخشید. کتابخونههایی مثل Zod و...
حتی میشه این توابع رو با تکنیک تایپاسکریپتی Type Narrowing ترکیب کرد تا بشه حتی تایپ سیستم قویتری ایجاد کرد.
این روش دلچسب برای «اعتبارسنجی دادهها» یا به انگلیسی «Data Validation» رو روش «Guard Clause» یا «بندهای محافظتی» نامگذاری کردند که یکی از روش های تئوری «سریعترین شکست» یا «Fail-Fast» هست یه جورهایی برگرفته شده از همون ضربالمثل «جنگ اول به از صلح آخر» خودمون هست. البته که میتونه از هر زاویه باعث بهبود کیفیت برنامههایی باشه که توسعه میدیم.
گارد کلاز چه مزیت هایی داره:
وقتی از این تکنیک در پروژههاتون استفاده کردید. خوشحال میشم من رو هم در جریان تغییراتون بگذارید.
میتونید من رو در همه شبکه های اجتماعی و پیامرسانها (به جز اینستاگرام) به آدرس «mikoloism» پیدا کنید.
«رایانامه» | «تلگرام» | «گیت هاب» | «کدپن»
بنویسیم و لذت ببریم :)