ASP.NET MVC #13
مثلا jquery.validate.unobtrusive با jquery.validate و jquery «باید» هماهنگ باشند و اگر نیستند دستور update-package را فراموش نکنید. ضمنا پس از به روز رسانی، «باید» ارجاعات به فایلهای جدید را در viewهای برنامه درست کنید. مثلا پروژه به نگارش جدید jQuery به روز شده، اما مدخل آن در view شما هنوز به نگارش قدیمی اشاره میکند. اینها یعنی تداخل و نتیجه آن کار نکردن افزونههای جدید است.
به علاوه اگر تعاریف اسکریپتها را دستی در ابتدای فایل تعریف کردید دیگر نباید از Scripts.Render در پایین صفحه استفاده کنید. چون این مورد هم سبب میشود یکبار دیگر اسکریپتها در صفحه پیوست شوند.
ضمنا من مجددا همین مثال بحث فوق را (نه مثال یک سایت ثالث را) در MVC4 بازنویسی کردم و بدون مشکل کار میکند: Sample13Mvc4.zip
آشنایی با NuGet - قسمت دوم
ASP.NET MVC #8
ProductsList.GetProductsList(List<MvcApplication4.Models.Product>)
public static void GetProductsList(List<Product> list) { // ... }
ClassName.GetProductsList(...instance...)
این پروژه یک فایل اسکریپت بیشتر نیست. بنابراین برای کار کردن نیاز به الحاق آن به صفحه هست (مثل تمام پروژههای جاوا اسکریپتی). ضمنا این مطلب رو برای سؤال پرسیدن باید رعایت کنی: آناتومی یک گزارش خطای خوب . کسی نمیدونه این ارور میده یعنی چی؟ چه خطایی میده؟ کسی مونیتورت رو نمیتونه از راه دور ببینه. باید توضیح بدی. تشریحش کنی با کمک این ابزار: نحوه استفاده از افزونه Firebug برای دیباگ برنامههای ASP.NET مبتنی بر jQuery
Defensive Coding به معنی است که شما با انجام یکسری کارها و در نظر گرفتن یکسری زیر ساختها در توسعهی نرم افزار خود، به اهداف ذیل دست پیدا کنید:
1. Quality (کیفیت)
2. Comprehensible (جامعیت)
3. Predictable (قابلیت پیش بینی)
دستیابی به هر کدام از این اهداف و روشهای اعمال آنها بر روی یک پروژهی نرم افزاری، در ادامه بحث خواهند شد.
1. Clean Code
یکی از اهداف Defensive Coding که در ابتدای مقاله بحث شد جامعیت یا Comprehension بود. برای رسید به این هدف از مفهومی به نام Clean Code استفاده میشود. Clean Code علاوه بر این مسئله، در پی ساده کردن ساختار بندی پشتیبانی و کاهش باگهای نرم افزار نیز هست. ویژگیهای Clean Code در بالا با توجه به شکل ذیل تشریح میشوند:
· Easy to read
یک کد Clean قابلیت خوانایی بالایی دارد. بسیاری از برنامه نویسان در سطوح مختلف با اهمیت این مسئله در توسعه نرم افزار آشنایی دارند. ولی بسیاری از همین برنامه نویسان این اصول را رعایت نمیکنند و سعی نمیکنند با اصول پیاده سازی آن در نرم افزارآشنا شوند.
اگر قابلیت خوانایی یک کد بالا باشد:
§ شما میتوانید Pattern های موجود در کد خود را که میتوانید به عنوان نامزدهایی جهت Refactoring هستند، تشخیص دهید.
§ برنامه نویسان دیگر به راحتی قصد و اهداف ( intent ) شما را از نوشتن یک کد خاص درک خواهند کرد و در طول زمان با خطاهای زیادی روبرو نمیشوند.
§ توسعهی راحتتر و در شرایط وجود فشار، ایجاد سریع یک قابلیت جدید در نرم افزار.
· Clear intent
یک کد Clear دارای اهداف روشن و قابل فهمی میباشد.
· Simple
پیچیدگی با کم هزینه بودن توسعهی و پشتیبانی تضاد مستقیم دارد. بنابراین سادگی در کدها باید جزو اهداف اصلی قرار بگیرد.
· Minimal
کد باید به گونهای باشد که تنها یک چیز را انجام داده و آن را به درستی انجام دهد. همچنین وابستگی بین اجزای کد باید در کمترین حد ممکن باشند.
· Thoughtful
یک کد Clean کدی است که ساختار آن متفکرانه طراحی شده باشد. از نحوهی طراحی یک کلاس گرفته تا layering و Tiering پروژه باید کاملا هوشمندانه و با توجه به پارامترهای موجود باشند. همچنین خطاهای خطرناک و استثناءها باید کاملا هندل شوند.
همهی ما با دیدن کد بالا سریعا مفهوم اسپاگتی کد به ذهنمان خطور میکند. تغییر، توسعه و پشتیبانی نرم افزارهایی که کد آنها به این صورت نوشته شده است، بسیار سخت و پر هزینه میباشد. در این حالت تغییر هر یک از اجزاء ممکن است بر سایر قسمتهای دیگر تاثیرات مختلفی داشته باشد. راه کاری که در این حالت ارائه میشود، Refactoring میباشد. در این روش کد را به کلاسها و متدهایی بر حسب عملکرد تقسیم خواهیم کرد. در نهایت کد تولید شده دارای کمترین تاثیر بر سایر قسمتها خواهد بود. توجه داشته باشید که با انجام این کار، قدمی به سوی SOC یا Separation Of Concern برداشتهاید.
1. Testable Code & Unit Test
یکی دیگر از اهداف Defensive Coding افزایش کیفیت یا Quality میباشد که برای رسیدن به این هدف از مفهوم Testable Code & Unit Test استفاده میشود. بسیاری از ویژگیهای Testable Code و Clean Code با هم مشابه میباشند. برای مثال Refactor کردن هر متد به متدهای کوچکتر، تست آن را سادهتر خواهند کرد. در نتیجه نوشتن کدهای Testable ، با نوشتن کدهای clean شروع میشود.
در این قسمت اشارهای به Unit Test شده است؛ اما این مفهوم میتواند به یک مفهوم گستردهتر به نام Automated Code testing، تعمیم داده شود. به این دلیل که تست فقط به Unit Testing محدود نمیشود و میتواند شامل سایر انواع تستها مانند integration test نیز باشد.
برای مثال شکل ذیل را در نظر بگیرید. در انتهای این سناریو یک Page جدید اضافه شده است. خوب؛ برای تست کد اضافه شده، مجبورید برنامه را اجرا کنید، login کنید، دادههای مورد نظر را در فرم وارد کرده و در نهایت شرایط لازم را جهت تست، فراهم کنید تا بتوانید کد جدید را تست کنید. در این بین با خطایی مواجه میشوید. پس برنامه را متوقف میکنید و تغییرات لازم را اعمال میکنید. حال فرض کنید این خطا به این زودیها رفع نشود. در این حالت باید فرآیند بالا را چندین و چند بار انجام دهید. نتیجه اینکه این روش بسیار زمان بر و پر هزینه خواهد بود. البته میزان هزینه و زمان رابطهی نزدیکی با وسعت تغییرات دارند. برای رفع مسائلی از این دست مایکروسافت زیرساختی به نام MS Test ارائه داده است که میتوان با آن سناریوهای تست متفاوتی را پیاده سازی و اجرا نمود. متاسفانه این مسئله در بسیار از جوامع توسعه نرم افزار رعایت نمیشود و در بسیاری از این جوامع، نیروی انسانی، این فرآیند و فرآیندهایی از این دست را انجام میدهند. درحالیکه چنین فرآیندهایی به راحتی توسط ابزارهای ارائه شدهی توسط شرکتهای مختلف قابل مدیریت است.
1. Predictability
یکی دیگر از اهداف Defensive Coding، قابلیت پیش بینی یا Predictability میباشد. فرآیند تشخیص و پیش بینی خطاها را Predictability میگویند. با درنظر گرفتن امکان وقوع خطاهای مختلف و تصمیم گرفتن در مورد اینکه در هنگام رخ دادن این خطا باید چه کاری صورت بگیرد، میتوان در رسیدن به این هدف قدم بزرگی برداشت.
برای رسیدن به این هدف باید اصل Trust but Verify را دنبال کنیم. برای مثال این اصل به ما میگوید که در هنگام تعریف متدهای public باید یکسری موارد را در نظر بگیریم. یک متد باید از یکسری قراردادها پیروی کند. یک متد قرارداد میکند که یکسری پارامترها را با یک data type خاص به عنوان ورودی دریافت کند. قرارداد میکند که یک مقدار خاص با یک data type خاص را به عنوان نوع بازگشتی بازگرداند یا اینکه هیچ مقداری را باز نگرداند و در نهایت یک متد متعهد میشود که یکسری Exception تعریف شده و پیش بینی شده را صادر کند. اما برای اینکه مطمئن شویم یک application واقعا قابل پیش بینی است و این اصل را به درستی پیاده سازی کرده است، اعتماد میکنیم اما Verify را هم انجام میدهیم. برای verify کردن باید پارامترها، دیتاهای متغیر، مقادیر بازگشتی و استثناءها به گونهای بررسی شوند که مطمئن شویم انتظارت ما را برآورده کردهاند.
زیاده روی بیش از حد خوب نیست و آدم باید همیشه حد اعتدال را رعایت کند. این مسئله اینجا هم صادق است؛ به گونهای که زیاده روی بیش از حد در پیاده سازی و اعمال هر کدام یک از این مواردی که در بالا ذکر گردید، ممکن است باعث پیچیدگی ساختار کد و به طبع آن Application شود. بنابراین رعایت حد اعتدال میتواند در رسیدن به این هدف بسیار مهم باشد.
چهار راز برای امنیت وایرلس
زیباتر کد بنویسیم
داشتن آگاهی در مورد ساختارهای دادهها، الگوریتمها و یا عملگرهای بیتی بسیار عالی است و یا تسلط بر نحوهی کارکرد ابزارهایی مانند SharePoint و امثال آن این روزها ضروری است. اما باید در نظر داشت، کدی که امروز تهیه میشود شاید فردا یا ماه دیگر یا چند سال بعد نیاز به تغییر داشته باشد، بنابراین دانش زیبا نوشتن یک قطعه کد که خواندن آنرا سادهتر میکند و در آینده افرادی که از آن نگهداری خواهند کرد زیاد "زجر" نخواهند کشید، نیز ضروری میباشد. (اگر کامنتهای سایت را خوانده باشید یکی از دوستان پیغام گذاشته بود، اگر به من بگویند یک میلیون بگیرید و برنامه فعلی را توسعه دهید یا رفع اشکال کنید، حاضرم 10 هزارتومان بگیرم و آنرا از صفر بنویسم! متاسفانه این یک واقعیت تلخ است که ناشی از عدم خوانا بودن کدهای نوشته شده میباشد.)
در ادامه یک سری از اصول زیبا نویسی کدها را بررسی خواهیم کرد.
1- سعی کنید میزان تو در تو بودن کدهای خود را محدود کنید.
لطفا به مثال زیر دقت نمائید:
void SetA()
{
if(a == b)
{
foreach(C c in cs)
{
if(c == d)
{
a = c;
}
}
}
}
void SetA()
{
if(a != b)
return;
foreach(C c in cs)
a = GetValueOfA(c);
}
TypeOfA GetValueOfA(C c)
{
if(c == d)
return c;
return a;
}
افزونههای CodeRush و refactor pro مجموعهی DevExpress از لحاظ مباحث refactoring در ویژوال استودیو حرف اول را میزنند. فقط کافی است برای مثال قطعه کد if داخلی را انتخاب کنید، بلافاصله سه نقطه زیر آن ظاهر شده و با کلیک بر روی آن امکان استخراج یک تابع از آنرا برای شما به سرعت فراهم خواهد کرد.
مثالی دیگر:
if (foo) {
if (bar) {
// do something
}
}
if (foo && bar) {
// do something
}
و یا یک مثال دیگر:
میزان تو در تو بودن این تابع جاوا اسکریپتی را ملاحظه نمائید:
function findShape(flags, point, attribute, list) {
if(!findShapePoints(flags, point, attribute)) {
if(!doFindShapePoints(flags, point, attribute)) {
if(!findInShape(flags, point, attribute)) {
if(!findFromGuide(flags,point) {
if(list.count() > 0 && flags == 1) {
doSomething();
}
}
}
}
}
}
function findShape(flags, point, attribute, list) {
if(findShapePoints(flags, point, attribute)) {
return;
}
if(doFindShapePoints(flags, point, attribute)) {
return;
}
if(findInShape(flags, point, attribute)) {
return;
}
if(findFromGuide(flags,point) {
return;
}
if (!(list.count() > 0 && flags == 1)) {
return;
}
doSomething();
}
با وجود پیشرفتهای زیادی که در طراحی و پیاده سازی IDE ها صورت گرفته و با بودن ابزارهای تکمیل سازی خودکار متن تایپ شده در آنها، این روزها استفاده از نامهای بلند برای توابع یا متغیرها مشکل ساز نیست و وقت زیادی را تلف نخواهد کرد. برای مثال به نظر شما اگر پس از یک سال به کدهای زیر نگاه کنید کدامیک خود توضیح دهندهتر خواهند بود (بدون مراجعه به مستندات موجود)؟
void UpdateBankAccountTransactionListWithYesterdaysTransactions()
//or?
void UpdateTransactions()
اگر مورد 2 را رعایت کرده باشید، کمتر به نوشتن کامنت نیاز خواهد بود. از توضیح موارد بدیهی خودداری کنید، زیرا آنها بیشتر سبب اتلاف وقت خواهند شد تا کمک به افراد دیگر یا حتی خود شما. همچنین هیچگاه قطعه کدی را که به آن نیاز ندارید به صورت کامنت شده به مخزن کد در یک سیستم کنترل نگارش ارسال نکنید.
//function thisReallyHandyFunction() {
// someMagic();
// someMoreMagic();
// magicNumber = evenMoreMagic();
// return magicNumber;
//}
به صورت خلاصه جهت نگهداری سوابق کدهای قدیمی باید از سورس کنترل استفاده کرد و نه به صورت کامنت قرار دادن آنها.
از کامنتهای نوع زیر پرهیز کنید که بیشتر سبب رژه رفتن روی اعصاب خواننده میشود تا کمک به او! (خواننده را بیسواد فرض نکنید)
// Get the student's id
thisId = student.getId();
// TODO: This is too bad. FIX IT!
4- عدم استفاده از عبارات شرطی بیمورد هنگام بازگشت دادن یک مقدار bool:
مثال زیر را درنظر بگیرید:
if (foo>bar) {
return true;
} else {
return false;
}
return foo>bar;
برای مثال:
Something something = new Something(foo);
return something;
return new Something(foo);
6- در نگارشهای جدید دات نت فریم ورک استفاده از ArrayList منسوخ شده است. بجای آن بهتر است از لیستهای جنریک استفاده شود. کدی که در آن از ArrayList استفاده میشود طعم دات نت فریم ورک 1 را میدهد!
7- لطفا بین خطوط فاصله ایجاد کنید. ایجاد فواصل مجانی است!
دو تابع جاوا اسکریپتی زیر را (که در حقیقت یک تابع هستند) در نظر بگیرید:
function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));
firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);
radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);
baseRadius = distance(point, center);
radius = baseRadius + (lines * y);
p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code
}
function getSomeAngle() {
// Some code here then
radAngle1 = Math.atan(slope(center, point1));
radAngle2 = Math.atan(slope(center, point2));
firstAngle = getStartAngle(radAngle1, point1, center);
secondAngle = getStartAngle(radAngle2, point2, center);
radAngle1 = degreesToRadians(firstAngle);
radAngle2 = degreesToRadians(secondAngle);
baseRadius = distance(point, center);
radius = baseRadius + (lines * y);
p1["x"] = roundValue(radius * Math.cos(radAngle1) + center["x"]);
p1["y"] = roundValue(radius * Math.sin(radAngle1) + center["y"]);
pt2["x"] = roundValue(radius * Math.cos(radAngle2) + center["y"]);
pt2["y"] = roundValue(radius * Math.sin(radAngle2) + center["y");
// Now some more code
}
استفاده از فاصله بین خطوط در تابع دوم باعث بالا رفتن خوانایی آن شده است و این طور به نظر میرسد که سطرهایی با عملکرد مشابه در یک گروه کنار هم قرار گرفتهاند.
8- توابع خود را کوتاه کنید.
یک تابع نباید بیشتر از 50 سطر باشد (البته در این مورد بین علما اختلاف هست!). اگر بیشتر شد بدون شک نیاز به refactoring داشته و باید به چند قسمت تقسیم شود تا خوانایی کد افزایش یابد.
به صورت خلاصه یک تابع فقط باید یک کار را انجام دهد و باید بتوان عملکرد آنرا در طی یک جمله توضیح داد.
9- از اعداد جادویی در کدهای خود استفاده نکنید!
کد زیر هیچ معنایی ندارد!
if(mode == 3){ ... }
else if(mode == 4) { ... }
if(mode == MyEnum.ShowAllUsers) { ... }
else if(mode == MyEnum.ShowOnlyActiveUsers) { ... }
اگر نیاز به تعداد زیادی پارامتر ورودی وجود داشت (بیش از 6 مورد) از struct و یا کلاس جهت معرفی آنها استفاده کنید.