مطالب
معرفی برنامه jQueryPad

jQueryPad برنامه‌ای است قابل حمل و کم حجم برای تمرین و همچنین آزمایش سریع اسکریپت‌های مبتنی بر jQuery . می‌توان در قسمت سمت چپ آن قطعه‌ کد HTML ‌ایی را نوشت و در TextBox سمت راست آن، قطعه‌ کد جاوا اسکریپتی مبتنی بر jQuery . سپس با فشردن دکمه F5 بلافاصله نتیجه‌ی ترکیب این دو در پایین صفحه نمایش داده می‌شود.



اگر نیاز به استفاده از نگارش خاصی از jQuery را داشتید می‌توان فایل js موجود در پوشه‌ی template آن‌را تغییر داد.
کار انجام شده شبیه به برنامه‌ی LINQ-Pad است؛ البته برنامه‌ی LINQ-Pad در نگارش تجاری آن دارای intellisense هم هست.

مطالب
اصول و قراردادهای نام‌گذاری در دات‌نت
نامگذاری (Naming) اشیا یک برنامه شاید در نگاه اول دارای اهمیت بالایی نباشه، اما تجربه نشون داده که در پروژه‌های بزرگ که با کمک چندین مجموعه به انجام میرسه نامگذاری صحیح و اصولی که از یکسری قواعد کلی و مناسب پیروی میکنه میتونه به پیشبرد اهداف و مدیریت راحتتر برنامه کمک بسیاری بکنه.
بیشتر موارد اشاره شده در این مطلب از کتاب جامع و مفید Framework Design Guidelines اقتباس شده که خوندن این کتاب مفید رو به خوانندگان توصیه میکنم.
برای کمک به نوشتن اصولی و راحتتر سورسهای برنامه‌ها در ویژوال استودیو نرم افزارهای متعددی وجود داره که با توجه به تجربه شخصی خودم نرم افزار Resharper  محصول شرکت Jetbrains یکی از بهترین هاست که در مورد خاص مورد بحث در این مطلب نیز بسیار خوب عمل میکنه.
برخی از موارد موجود در مطلب جاری نیز از قراردادهای پیشفرض موجود در نرم افزار Resharper نسخه 6.0 برگرفته شده است و قسمتی نیز از تجربه شخصی خودم و سایر دوستان و همکاران بوده است.
اصل این مطلب حدود یکسال پیش تهیه شده و اگر نقایصی وجود داره لطفا اشاره کنین.

اصول و قراردادهای نام‌گذاری در دات‌نت
انواع نام‌گذاری
نام‌گذاری اشیا در حالت کلی را می‌توان به سه روش زیر انجام داد:
1. Pascal Casing: در این روش حرف اول هر کلمه در نام شی به صورت بزرگ نوشته می‌شود.
FirstName
2. camel Casing: حرف اول در اولین کلمه نام هر شی به صورت کوچک و حرف اول بقیه کلمات به صورت بزرگ نوشته می‌شود.
firstName
3. Hungarian: در این روش برای هر نوع شی موجود یک پیشوند درنظر گرفته می‌شود تا از روی نام شی بتوان به نوع آن پی برد. در ادامه و پس از این پیشوندها سایر کلمات بر اساس روش Pascal Casing نوشته می‌شوند.
strFirstName
lblFirstName
نکته: استفاده از این روش به جز در نام‌گذاری کنترل‌های UI منسوخ شده است.

قراردادهای کلی
1. نباید نام اشیا تنها در بزرگ یا کوچک بودن حروف با هم فرق داشته باشند. به عنوان مثال نباید دو کلاس با نام‌های MyClass و myClass داشته باشیم. هرچند برخی از زبان‌ها case-sensitive هستند اما برخی دیگر نیز چنین قابلیتی ندارند (مثل VB.NET). بنابراین اگر بخواهیم کلاس‌های تولیدی ما در تمام محیط‌ها و زبان‌های برنامه نویسی قابل اجرا باشند باید از این قرارداد پیروی کنیم.
2. تا آنجا که امکان دارد باید از به‌کار بردن مخفف کلمات در نام‌گذاری اشیا دوری کنیم. مثلا به جای استفاده از GetChr باید از GetCharacter استفاده کرد.
البته در برخی موارد که مخفف واژه موردنظر کاربرد گسترده ای دارد می‌توان از عبارت مخفف نیز استفاده کرد. مثل UI به جای UserInterface و یا IO به جای InputOutput.
 
آ. اصول نام‌گذاری فضای نام (namespace)
1. اساس نام‌گذاری فضای نام باید از قاعده زیر پیروی کند:
<Company>.<Technology|Produt|Project>[.<Feature>][.<SubNamespace>]
( < > : اجباری        [ ] : اختیاری )
2. برای نام‌گذاری فضای نام باید از روش Pascal Casing استفاده شود.
3. در هنگام تعریف فضاهای نام به وابستگی آنها توجه داشته باشید. به عنوان مثال اشیای درون یک فضای نام پدر نباید به اشیای درون فضای نام یکی از فرزندانش وابسته باشد. مثلا در فضای نام System نباید اشیایی وجود داشته باشند که به اشیای درون فضای نام System.UI وابسته باشند.
4. سعی کنید از نام‌ها به صورت جمع برای عناوین فضای نام استفاده کنید. مثلا به جای استفاده از Kara.CSS.HQ.Manager.Entity از Kara.CSS.HQ.Manager.Entities استفاده کنید. البته برای مورادی که از عناوین مخفف و یا برندهای خاص استفاده کرده‌اید از این قرارداد پیروی نکنید. مثلا نباید از عنوانی شبیه به Kara.CSS.Manager.IOs استفاده کنید.
5. از عنوانی پایدار و مستقل از نسخه محصول برای بخش دوم عنوان فضای نام استفاده کنید. بدین معنی که این عناوین با گذر زمان و تغییر و تحولات در محتوای محصول و یا تولیدکننده نباید تغییر کنند. مثال:
Microsoft.Reporting.WebForms
Kara.Support.Manager.Enums
Kara.CSS.HQ.WebUI.Configuration
6. از عناوین یکسان برای فضای نام و اشیای درون آن استفاده نکنید. مثلا نباید کلاسی با عنوان Manager در فضای نام Kara.CSS.Manager وجود داشته باشد.
7. از عناوین یکسان برای اشیای درون فضاهای نام یک برنامه استفاده نکنید. مثلا نباید دو کلاس با نام Package در فضاهای نام Kara.CSS.Manger و Kara.CSS.Manger.Entities داشته باشید.

ب. اصول نام‌گذاری کلاس‌ها و Structها
1. عنوان کلاس باید اسم یا موصوف باشد.
2. در نام‌گذاری کلاس‌ها باید از روش Pascal Casing استفاده شود.
3. نباید از عناوین مخففی که رایج نیستند استفاده کرد.
4. از پیشوندهای زائد مثل C یا Cls نباید استفاده شود.
5. نباید از کاراکترهایی به غیر از حروف (و یا در برخی موارد خیلی خاص، شماره نسخه) در نام‌گذاری کلاس‌ها استفاده شود.
مثال:
درست:
PackageManager , PacakgeConfigGenerator
Circle , Utility , Package
نادرست:
CreateConfig , classdata
CManager , ClsPackage , Config_Creator , Config1389
6. در نام‌گذاری اشیای Generic از استفاده از عناوینی چون Element, Node, Log و یا Message پرهیز کنید. این کار موجب به‌وجودآمدن کانفلیکت در عناوین اشیا می‌شود. در این موارد بهتر است از عناوینی چون FormElement, XmlNode, EventLog و SoapMessage استفاده شود. درواقع بهتر است نام اشیای جنریک، برای موارد موردنیاز، کاملا اختصاصی و درعین حال مشخص‌کننده محتوا و کاربرد باشند.
7. از عناوینی مشابه عناوین کتابخانه‌های پایه دات‌نت برای اشیای خود استفاده نکنید. مثلا نباید کلاسی با عنوان Console, Parameter, Action و یا Data را توسعه دهید. هم‌چنین از کابرد عناوینی مشابه اشیای موجود در فضاهای نام غیرپایه دات‌نت و یا غیردات‌نتی اما مورداستفاده در پروژه خود که محتوا و کاربردی مختص همان فضای نام دارند پرهیز کنید. مثلا نباید کلاسی با عنوان Page در صورت استفاده از فضای نام System.Web.UI تولید کنید.
8. سعی کنید در مواردی که مناسب به‌نظر می‌رسد از عنوان کلاس پایه در انتهای نام کلاس‌های مشتق‌شده استفاده کنید. مثل FileStream که از کلاس Stream مشتق شده است. البته این قاعده در تمام موارد نتیجه مطلوب ندارد. مثلا کلاس Button که از کلاس Control مشتق شده است. بنابراین در به‌کاربردن این مورد بهتر است تمام جوانب و قواعد را درنظر بگیرید.

پ. اصول نام‌گذاری مجموعه‌ها (Collections)
یک مجموعه در واقع یک نوع کلاس خاص است که حاوی مجموعه‌ای از داده‌هاست و از همان قوانین کلاس‌ها برای نام‌گذاری آن‌ها استفاده می‌شود.
1. بهتر است در انتهای عنوان مجموعه از کلمه Collection استفاده شود. مثال:
CenterCollection , PackageCollection
2. البته درصورتی‌که کلاس مورد نظر ما رابط IDictionary را پیاده‌سازی کرده باشد بهتر است از پسوند Dictionary استفاده شود.

ت. اصول نام‌گذاری Delegateها
1. عنوان یک delegate باید اسم یا موصوف باشد.
2. در نام‌گذاری delegateها باید از روش Pascal Casing استفاده شود.
3. نباید از عناوین مخففی که رایج نیستند استفاده کرد.
4. از پیشوندهای زائد مثل D یا del نباید استفاده شود.
5. نباید از کاراکترهایی به غیر از حروف در نام‌گذاری delegateها استفاده شود.
6. نباید در انتهای نام یک delegate از عبارت Delegate استفاده شود.
7. بهتر است که درصورت امکان در انتهای نام یک delegate که برای Event Handler استفاده نمی‌شود از عبارت Callback استفاده شود. البته تنها درصورتی‌که معنی و مفهوم مناسب را داشته باشد.
مثال:
نحوه تعریف یک delegate
public delegate void Logger (string log);
public delegate void LoggingCallback (object sender, string reason);

ث. اصول نام‌گذاری رویدادها (Events)
1. عنوان یک رویداد باید فعل یا مصدر باشد.
2. در نام‌گذاری کلاس‌ها باید از روش Pascal Casing استفاده شود.
3. نباید از عناوین مخففی که رایج نیستند استفاده کرد.
4. از پیشوندهای زائد نباید استفاده شود.
5. نباید از کاراکترهایی به غیر از حروف در نام‌گذاری رویدادها استفاده شود.
6. بهتر است از پسوند EventHandler در عنوان هندلر رویداد استفاده شود.
7. از به کاربردن عباراتی چون AfterXXX و یا BeforeXXX برای نمایش رویدادهای قبل و یا بعد از رخداد خاصی خودداری شود. به جای آن باید از اسم مصدر (شکل ingدار فعل) برای نام‌گذاری رویداد قبل از رخداد و هم‌چنین شکل گذشته فعل برای نام‌گذاری رویداد بعد از رخداد خاص استفاده کرد.
مثلا اگر کلاسی دارای رویداد Open باشد باید از عنوان Openning برای رویداد قبل از Open و از عنوان Opened برای رویداد بعد از Open استفاده کرد.
8. نباید از پیشوند On برای نام‌گذاری رویداد استفاده شود.
9. همیشه پارامتر e و sender را برای آرگومانهای رویداد پیاده سازی کنید. sender که از نوع object است نمایش دهنده شیی است که رویداد مربوطه را به وجود آورده است و e درواقع آرگومانهای رویداد مربوطه است.
10. عنوان کلاس‌آرگومان‌های رویداد باید دارای پسوند EventArgs باشد.
مثال:
عنوان کلاس‌آرگومان:
AddEventArgs , EditEventArgs , DeleteEventArgs
عنوان رویداد:
Adding , Add , Added
تعریف یک EventHandler:
public delegate void <EventName>EventHandler  (object sender, <EventName>EventArgs e);
نکته: نیاز به تولید یک EventHandler مختص توسعه یک برنامه به‌ندرت ایجاد می‌شود. در اکثر موارد می‌توان با استفاده از کلاس جنریک <EventHandler<TEventArgs تمام احتیاجات خود را برطرف کرد.
تعریف یک رویداد:
public event EventHandler <AddEventArgs> Adding;

ج. اصول نام‌گذاری Attributeها
1. عنوان یک attribute باید اسم یا موصوف باشد.
2. در نام‌گذاری attributeها باید از روش Pascal Casing استفاده شود.
3. نباید از عناوین مخففی که رایج نیستند استفاده کرد.
4. از پیشوندهای زائد مثل A یا atr نباید استفاده شود.
5. نباید از کاراکترهایی به غیر از حروف در نام‌گذاری attributeها استفاده شود.
6. بهتر است در انتهای نام یک attribute از عبارت Attribute استفاده شود.
مثال:
DisplayNameAttribute , MessageTypeAttribute

چ. اصول نام‌گذاری Interfaceها
1. در ابتدای عنوان interface باید از حرف I استفاده شود.
2. نام باید اسم، موصوف یا صفتی باشد که interface را توصیف می‌کند.
به عنوان مثال:
IComponent  (اسم)
IConnectionProvider (موصوف)
ICloneable (صفت)
3. از روش Pascal Casing استفاده شود.
4. خودداری از بکاربردن عبارات مخفف غیررایج.
5. باید تنها از کاراکترهای حرفی در نام interface استفاده شود.
 
ح. اصول نام‌گذاری Enumerationها
1. استفاده از روش Pascal Casing
2. خودداری از کاربرد عبارات مخفف غیررایج
3. تنها از کاراکترهای حرفی در نام Enumretionها استفاده شود.
4. نباید از پسوند یا پیشوند Enum یا Flag استفاده شود.
5. اعضای یک Enum نیز باید با روش Pascal Casing نام‌گذاری شوند.
مثال:
public enum FileMode {
    Append,
    Read, …
}
6. درصورتی‌که enum موردنظر از نوع flag نیست باید عنوان آن مفرد باشد. 
7. درصورتی‌که enum موردنظر برای کاربرد flag طراحی شده باشد نام آن باید جمع باشد. مثال:
[Flag]
public enum KeyModifiers {
    Alt = 1, 
    Control = 2,
    Shift = 4
}
8. از به‌کاربردن پسوند و یا پیشوندهای اضافه در نام‌گذاری اعضای یک enum نیز پرهیز کنید. مثلا نام‌گذاری زیر نادرست است:
public enum OperationState {
    DoneState, 
    FaultState,
    RollbackState
}

خ. اصول نام‌گذاری متدها
1. نام متد باید فعل یا ترکیبی از فعل و اسم یا موصوف باشد.
2. باید از روش Pascal Casing استفاده شود.
3. خودداری از بکاربردن عبارات مخفف غیررایج و یا استفاده زیاد از اختصار
4. تنها از کاراکترهای حرفی برای نام متد استفاده شود.
مثال:
AddDays , Save , DeleteRow , BindData , Close , Open

د. اصول نام‌گذاری Propertyها
1. نام باید اسم، صفت یا موصوف باشد.
2. باید از روش Pascal Casing استفاده شود.
3. خودداری از بکاربردن عبارات مخفف غیررایج.
4. تنها از کاراکترهای حرفی برای نام‌گذاری پراپرتی استفاده شود.
مثال:
Radius , ReportType , DataSource , Mode , CurrentCenterId
5. از عبارت Get در ابتدای هیچ Propertyای استفاده نکنید.
6. نام خاصیت‌هایی که یک مجموعه برمی‌گرداند باید به صورت جمع باشد. عنوان این Propertyها نباید به‌صورت مفرد به همراه پسوند Collection یا List باشد. مثال:
public CenterCollection Centers { get; set; }
7. خواص Boolean را با عناوینی مثبت پیاده‌سازی کنید. مثلا به‌جای استفاده از CantRead از CanRead استفاده کنید. بهتر است این Propertyها پیشوندهایی چون Is, Can یا Has داشته باشند، البته تنها درصورتی‌که استفاده از چنین پیشوندهایی ارزش افزوده داشته و مفهوم آن را بهتر برساند. مثلا عنوان CanSeek مفهوم روشن‌تری نسبت به Seekable دارد. اما استفاده از Created خیلی بهتر از IsCreated است یا Enabled کاربرد به مراتب راحت‌تری از IsEnabled دارد.
برای تشخیص بهتر این موارد بهتر است از روش ifسنجی استفاده شود. به عنوان مثال
if (list.Contains(item))
if (regularExpression.Matches(text))
if (stream.CanSeek)
if (context.Created)
if (form.Enabled)
مفهوم درست‌تری نسبت به موارد زیر دارند:
if (list.IsContains(item))
if (regularExpression.Match(text))
if (stream.Seekable)
if (context.IsCreated)
if (form.IsEnabled)
8. بهتر است در موارد مناسب عنوان Property با نام نوعش برابر باشد. مثلا
public Color Color { get; set; }

ذ. اصول نام‌گذاری پارامترها
پارامتر درحالت کلی به آرگومان وروی تعریف شده برای یک متد گفته می‌شود.
1. حتما از یک نام توصیفی استفاده شود. از نام‌گذاری پارامترها براساس نوعشان به‌شدت پرهیز کنید.
2. از روش camel Casing استفاده شود.
3. تنها از کاراکترهای حرفی برای نام‌گذاری پارامترها استفاده شود.
مثال:
firstName , e , id , packageId , centerName , name
4. نکاتی برای نام‌گذاری پارامترهای Operator Oveloading:
- برای operatorهای دو پارامتری (binary operators) از عناوین left و right برای پارامترهای آن استفاده کنید:
public static MyType operator +(MyType left, MyType right)
public static bool operator ==(MyType left, MyType right)
- برای operatorهای تک‌پارامتری (unary operators) اگر برای پارامتر مورد استفاده هیچ عنوان توصیفی مناسبی پیدا نکردید حتما از عبارت value استفاده کنید:
public static MyType operator ++(MyType value)
- درصورتی‌که استفاده از عناوین توصیفی دارای ارزش افزوده بوده و خوانایی کد را بهتر می‌کند حتما از این نوع عناوین استفاده کنید:
public static MyType operator /(MyType dividend, MyType divisor)
- نباید از عبارات مخفف یا عناوینی با اندیس‌های عددی استفاده کنید:
public static MyType operator -(MyType d1, MyType d2) // incorrect!

ر. اصول نام‌گذاری متغیر (Variable)ها
- نام متغیر باید اسم، صفت یا موصوف باشد.
نام‌گذاری متغیرها باید با توجه به نوع آن انجام شود.
1. متغیرهای عمومی (public) و protected و Constantها
- استفاده از روش Pascal Casing
- تنها از کاراکترهای حرفی برای نام متغیر عمومی استفاده شود.
مثال:
Area , DataBinder , PublicCacheName
2. متغیرهای private (در سطح کلاس یا همان field)
- نام این نوع متغیر باید با یک "_" شروع شود.
- از روش camel Casing استفاده شود.
مثال:
_centersList
_firstName
_currentCenter
3. متغیرهای محلی در سطح متد
- باید از روش camel Casing استفاده شود.
- تنها از کاراکترهای حرفی استفاده شود.
مثال:
parameterType , packageOperationTypeId

ز. اصول نام‌گذاری کنترل‌های UI
1. نام باید اسم یا موصوف باشد.
2. استفاده از روش Hungarian !
3. عبارت مخفف معرفی‌کننده کنترل، باید به اندازه کافی برای تشخیص نوع آن مناسب باشد.
مثال:
lblName (Label)
txtHeader (TextBox)
btnSave (Button)

ژ. اصول نام‌گذاری Exceptionها
تمام موارد مربوط به نام‌گذاری کلاس‌ها باید در این مورد رعایت شود. 
1. باید از پسوند Exception در انتهای عنوان استفاده شود.
مثال:
ArgumentNullException , InvalidOperaionException

س. نام‌گذاری اسمبلی‌ها و DLLها
1. عناوینی که برای نام‌گذاری اسمبلی‌ها استفاده می‌شوند، باید نمایش‌دهنده محتوای کلی آن باشند. مثل:
System.Data
2. از روش زیر برای نام‌گذاری اسمبلی‌ها استفاده شود:
<Company>.<Component>.dll
<Company>.<Project|Product|Technology>.<Component>.dll
مثل:
Microsoft.CSharp.dll , Kara.CSS.Manager.dll

ش. نام‌گذاری پارامترهای نوع (Generic (type parameter
1. از حرف T برای پارامترهای تک‌حرفی استفاده کنید. مثل:
public int IComparer<T> {…}
public delegate bool Predicate<T> (T item)
2. تمامی پارامترهای جنریک را با عناوینی توصیفی و مناسب که مفهوم و کاربرد آنرا برساند نام‌گذاری کنید، مگر آنکه یافتن چنین عباراتی ارزش افزوده‌ای در روشن‌تر کردن کد نداشته باشد. مثال:
public int ISessionChannel<TSession> {…}
public delegate TOutput Converter<TInput, TOutput> (TInput from)
public class Nullable<T> {…}
public class List<T> {…}
3. در ابتدای عناوین توصیفی حتما از حرف T استفاده کنید.
4. بهتر است تا به‌صورتی روشن نوع قید قرار داده شده بر روی پارامتری خاص را در نام آن پارامتر نمایش دهید. مثلا اگر قید ISession را برای پارامتری قرار دادید بهتر است نام آن پارامتر را TSession درنظر بگیرید.
 
ص. نام‌گذاری کلید Resourceها
به دلیل شباهت ساختاری که میان کلیدهای resource و propertyها وجود دارد قواعد نام‌گذاری propertyها در اینجا نیز معتبر هستند.
1. از روش نام‌گذاری Pascal Casing برای کلیدهای resource استفاده کنید.
2. از عناوین توصیفی برای این کلیدها استفاده کنید. سعی کنید تا حد امکان به هیچ وجه از عناوین کوتاه و یا مخففی که مفهوم را به‌صورت ناکامل می‌رساند استفاده نکنید. درواقع سعی کنید که خوانایی بیشتر کد را فدای فضای بیشتر نکنید.
3. از کلیدواژه‌های CLR و یا زبان مورداستفاده برای برنامه‌نویسی در نام‌گذاری این کلیدها استفاده نکنید.
4. تنها از حروف و اعداد و _ در نام‌گذاری این کلیدها استفاده کنید.
5. سعی کنید از عناوین توصیفی همانند زیر برای پیام‌های مناسب خطاها جهت نمایش به کاربر برای کلیدهای مربوطه استفاده کنید. درواقع نام کلید باید ترکیبی از نام نوع خطا و یک آی‌دی مشخص‌کننده پیغام مربوطه باشد:
ArgumentExceptionIllegalCharacters
ArgumentExceptionInvalidName
ArgumentExceptionFileNotFound
 
نکاتی درمورد کلمات مرکب
کلمات مرکب به کلماتی گفته می‌شود که در آن از بیش از یک کلمه با مفهوم مستقل استفاده شده باشد. مثل Callback یا FileName. 
باید توجه داشت که با تمام کلمات موجود در یک کلمه مرکب نباید همانند یک کلمه مستقل رفتار کرد و حرف اول آن را در روش‌های نام‌گذاری موجود به‌صورت بزرگ نوشت. کلمات مرکبی وجود دارند که به آن‌ها closed-form گفته می‌شود. این کلمات مرکب با اینکه از 2 یا چند کلمه دارای مفهوم مستقل تشکیل شده‌اند اما به‌خودی‌خود دارای مفهوم جداگانه و مستقلی هستند. برای تشخیص این کلمات می‌توان به فرهنگ لغت مراجعه کرد (و یا به‌سادگی از نرم‌افزار Microsoft Word استفاده کرد) و دریافت که آیا کلمه مرکب موردنظر آیا مفهوم مستقلی برای خود دارد، یعنی درواقع آیا عبارتی closed-form است. با کلمات مرکب از نوع closed-form همانند یک کلمه ساده برخورد می‌شود! 
در جدول زیر مثال‌هایی از عبارات رایج و نحوه درست و نادرست استفاده از هریک نشان داده شده است.

Pascal Casing

camel Casing

Wrong

Callback

callback

CallBack

BitFlag

bitFlag

Bitflag / bitflag

Canceled

canceled

Cancelled

DoNot

doNot

Donot / Don’t

Email

email

EMail

Endpoint

endpoint

EndPoint / endPoint

FileName

fileName

Filename / filename

Gridline

gridline

GridLine / gridLine

Hashtable

hashtable

HashTable / hashTable

Id

id

ID

Indexes

indexes

Indices

LogOff

logOff

Logoff / LogOut !

LogOn

logOn

Logon / LogIn !

SignOut

signOut

Signout / SignOff

SignIn

signIn

Signin / SignOn

Metadata

metadata

MetaData / metaData

Multipanel

multipanel

MultiPanel / multiPanel

Multiview

multiview

MultiView / multiView

Namespace

namespace

NameSpace / nameSpace

Ok

ok

OK

Pi

pi

PI

Placeholder

placeholder

PlaceHolder / placeHolder

UserName

username

Username / username

WhiteSpace

whiteSpace

Whitespace / whitespace

Writable

writable

Writeable / writeable

همان‌طور که در جدول بالا مشاهد می‌شود در استفاده از قوانین عبارات مخفف دو مورد استثنا وجود دارد که عبارتند از Id و Ok. این کلمات باید همان‌طور که در اینجا نشان داده شده‌اند استفاده شوند.
 
نکاتی درباره عبارات مخفف
1. عبارات مخفف (Acronym) با خلاصه‌سازی کلمات (Abbreviation) فرق دارند. یک عبارت مخفف شامل حروف اول یک عبارت طولانی یا معروف است، درصورتی‌که خلاصه‌سازی یک عبارت یا کلمه از حذف بخشی از آن به‌دست می‌آید. تا آنجاکه امکان دارد از خلاصه‌سازی عبارات نباید استفاده شود. هم‌چنین استفاده از عبارات مخفف غیررایج توصیه نمی‌شود.
مثال: IO و UI
2. براساس تعریف، یک مخفف حداقل باید 2 حرف داشته باشد. نحوه برخورد با مخفف‌های دارای بیشتر از 2 حرف با مخفف‌های دارای 2 حرف باهم متفاوت است. با مخفف‌های دارای 2 حرف همانند کلمه‌ای یک حرفی! برخورد می‌شود، درصورتی‌که با سایر مخفف‌ها همانند یک کلمه کامل چندحرفی برخورد می‌شود. به‌عنوان مثال IOStream برای روش PascalCasing و ioStream برای روش camelCasing استفاده می‌شود. هم‌چنین از HtmlBody و htmlBody به‌ترتیب برای روش‌های Pascal و camel استفاده می‌شود.
3. هیچ‌کدام از حروف یک عبارت مخفف در ابتدای یک واژه نام‌گذاری‌شده به روش camelCasing به‌صورت بزرگ نوشته نمی‌شود!
نکته: موارد زیادی را می‌توان یافت که در ابتدا به‌نظر می‌رسد برای پیاده‌سازی آنها باید قوانین فوق را نقض کرد. این موارد شامل استفاده از کتابخانه‌های سایر پلتفرم‌ها (مثل MFC, HTML و غیره)، جلوگیری از مشکلات جغرافیایی! (مثلا در مورد نام کشورها یا سایر موقعیت‌های جغرافیایی)، احترام به نام افراد درگذشته، و مواردی از این دست می‌شود. اما در بیشتر قریب به اتفاق این موارد هم می‌توان بدون تقض قوانین فوق اقدام به نام‌گذاری اشیا کرد، بدون اینکه با تغییر عبارت اصلی (که موجب تطابق با این قوانین می‌شود) لطمه‌ای به مفهوم آن بزند. البته تنها موردی که به‌نظر می‌رسد می‌تواند قوانین فوق را نقض کند نام‌های تجاری هستند. البته استفاده از نام‌های تجاری توصیه نمی‌شود، چون این نام‌ها سریع‌تر از محتوای کتابخانه‌های برنامه‌نویسان تغییر می‌کنند!
نکته: برای درک بهتر قانون "عدم استفاده از عبارات مخففی که رایج نیستند" مثالی از زبان توسعه دهندگان دات‌نت‌فریمورک ذکر می‌شود. در کلاس Color متد زیر با Overloadهای مختلف در دسترس است:
public class Color {
    …
    public static Color FromArgb(…)
    { … }
}
همان‌طور که مشاهده می‌شود برای رعایت قوانین فوق به‌جای استفاده از ARGB از عبارت Argb استفاده شده است. اما این نحوه استفاده موجب شده تا این سوال به‌ظاهر خنده‌دار اما درست پیش‌آید:
"چطور می‌شود در این کلاس رنگی را از ARGB تبدل کرد؟ هرچه که من میبینم فقط تبدیل از طریق (Argb) آرگومان b است!"
حال در این نقطه به‌نظر می‌رسد که در اینجا باید قوانین فوق را نقض کرد و از عنوان FromARGB که مفهوم درست را می‌رساند استفاده کرد. اما با کمی دقت متوجه می‌شویم که این قوانین در ابتدا نیز با پیاده‌سازی نشان داده شده در قطعه کد بالا نقض شده‌اند! همه می‌دانیم که عبارت RGB مخفف معروفی برای عبارت Red Green Blue است. اما استفاده از ARGB برای افزودن کلمه Alpha به ابتدای عبارت مذکور چندان رایج نیست. پس استفاده از مخفف Argb از همان ابتدا اشتباه به‌نظر می‌رسد. بنابراین راه‌حل بهتر می‌تواند استفاده از عنوان FromAlphaRgb باشد که هم قوانین فوق را نقض نکرده و هم مفهوم را بهتر می‌رساند.
 
دیگر نکات
1. قراردادهای اشاره شده در این سند حاصل کار شبانه روزی تعداد بسیاری از برنامه نویسان در سرتاسر جهان در پروژه‌های بزرگ بوده است. این اصول کلی تنها برای توسعه آسان‌تر و سریع‌تر پروژه‌های بزرگ تعیین شده‌اند و همان‌طور که روشن است تنها ازطریق تجربه دست‌یافتنی هستند. بنابراین چه بهتر است که در این راه از تجارب بزرگان این عرصه بیشترین بهره برده شود.
2. هم‌چنین توجه داشته باشید که بیشتر قراردادهای اشاره شده در این سند از راهنمای نام‌گذاری تیم توسعه BCL دات‌نت‌فریمورک گرفته شده است. این تیم طبق اعتراف خودشان زمان بسیار زیادی را برای نام‌گذاری اشیا صرف کرده‌اند و توصیه کرده‌اند که دیگران نیز برای نام‌گذاری، زمان مناسب و کافی را در توسعه پروژه‌ها درنظر بگیرند.
 
اشتراک‌ها
امکانات جدید در فایرفاکس کوانتم

Firefox Quantum is over twice as fast as Firefox from 6 months ago, built on a completely overhauled core engine with brand new technology stolen from our advanced research group, and graced with a beautiful new look designed to get out of the way and let you do what you do best: surf a ton of pages, open a zillion tabs, all guilt free because Firefox Quantum uses less memory than the competition 

امکانات جدید در فایرفاکس کوانتم
مطالب
اجزاء معماری سیستم عامل اندروید (قسمت دوم معماری امنیتی اندروید) :: بخش چهارم
ایمن کردن برنامه تولید شده در برابر حملات:

هنگام دریافت اطلاعات از کاربر، باید داده‌ها در جایی ذخیره شوند. اینکه داده‌ها در کجا ذخیره و نگه داری شوند و از نفوذ به آنها جلوگیری شود، نهایت امن بودن برنامه شما را نشان میدهد. باید فرض کنید که برنامه شما به طور مستقیم یا غیرمستقیم در برخی موارد مورد حمله قرار میگیرد و تنها چیزی که بین حفاظت از اطلاعات کاربر نهایی، شما و حفاظت از داده‌ها مطرح می‌شود برعهده شما خواهد بود. چند نمونه از حملات را توضیح خواهم داد:
حملات غیر مستقیم (Indirect Attacks)
قبل از اینکه این بحث را باز کنم اجازه دهید ببینیم ترس از یک حمله تا چه حد استرس بوجود می‌آورد؟ در نیمه دوم 2010 و اوایل 2011 ، دو آسیب‌پذیری خطرناک در نسخه‌های Android به ترتیب 2.2 و 2.3 کشف شدند. آسیب‌پذیری در اصل همان خطری است که در آن یک مهاجم می‌تواند هر پرونده‌ای را که بر روی SD دستگاه ذخیره شده‌است کپی کند و به سرقت ببرد! حمله بدون اجازه از حافظه اتفاق افتاده است و آسیب پذیری، این راه را برای آن فراهم کرده است. به تصویر دقت کنید! ( این آسیب پذیری مربوط به سرقت اطلاعات است)

نکات زیر، جالب‌ترین نکات در خصوص شیوه حمله بوده که قابل توجه است:

  1. یک کاربر از یک وب سایت حاوی کدهای مخرب و آلوده که یک فایل را میزبانی می‌کند، مانند evil.html بازدید می‌کند.
  2. با توجه به یک بخش از آسیب پذیری، فایل evil.html دانلود می‌شود و کارت SD آن را بدون هشدار به کاربر، ذخیره می‌کند!
  3. با توجه به بخش دیگری از آسیب پذیری، به محض اینکه فایل ذخیره شد، می‌توان کدهای جاوا اسکریپت مخرب را روی آن اجرا کرد!
  4. بدلیل بخش پایانی حمله روی این آسیب پذیری، کدهای جاوااسکریپت تحت شرایطی خاص روی سیستم محلی (local) اجرا می‌شوند! ابزار آلوده و برنامه نویسی شده، براحتی روی کارت SD ذخیره و مستقر شده و به وب سایت مهاجم برای ارسال اطلاعات قربانی دسترسی کامل دارد.
فرض کنید که برنامه شما تمام اطلاعات ذخیره‌شده در کارت SD را برای ذخیره‌سازی، زیر نظر دسترسی‌های خودش ذخیره کرده است و مطابق با الگوی دایرکتوری‌ها جلو می‌رود. با اینحال داده‌های شما در معرض خطر سرقت قرار گرفته‌اند! این مثالی از حمله غیرمستقیم به برنامه شما است. اینکه اپلیکیشن شما تا چه میزان در برابر حملات غیرمستقیم مقاوم خواهد بود، بستگی به تلاش شما در برنامه نویسی و تحلیل موارد امنیتی دارد و لازمه آن این است که قبل از تولید نرم افزار حتما تحلیل امنیتی بعمل آید و اپلیکیشن را از آنها منع کنید.
ممکن است بپرسید، "من فقط یک توسعه دهنده اندرویدی کوچکی هستم که قصد دارم برنامه خودم را در یک مارکت اندرویدی بفروشم و قیمت این برنامه خیلی پایین است. بنابراین آیا واقعا باید زمانی را برای انجام این کار امنیتی از قبل هدر دهم؟

و من با صدای رسا جواب می‌دهم : "بله! باید این کار را انجام دهید." این کار باعث می‌شود تا در حین گسترش اپلیکیشن کوچک خود، دیگر نگران مشکلات حملات مستقیم یا غیرمستقیم نباشید.

حملات مستقیم (Direct Attacks) 

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

Proxim و ذخیره داده 

بیایید با یک مثال ساده با نام Proxim شروع کنیم: برای نوشتن یک برنامه که می‌تواند یک SMS را به افراد خاص و معین ارسال کند، قرار دادی بسته‌ایم؛ با توجه به نزدیکی به مجموعه‌ای از مختصات مکانی آنها روی GPS. برای مثال: کاربر در این برنامه می‌تواند شماره تماس همسر خود را ذخیره کرده و هر زمان که به فاصله 3 مایلی به خانه یا محل کار برسد، با او تماس میگیرد. بدین صورت همسر فرد مطلع می‌شود که او نزدیک به محل کار یا خانه است و با یک تماس تلفنی او را آگاه می‌سازد.

کدهای زیر بخشی از فایل (Save Routine, SaveController. java) هستند:

package net.zenconsult.android.controller;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import net.zenconsult.android.model.Contact;
import net.zenconsult.android.model.Location;
import android.content.Context;
import android.os.Environment;
import android.util.Log;
public class SaveController {
 private static final String TAG = "SaveController";
 public static void saveContact(Context context, Contact contact) {
  if (isReadWrite()) {
   try {
    File outputFile = new File(context.getExternalFilesDir(null), contact.getFirstName());
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    outputStream.write(contact.getBytes());
    outputStream.close();
   } catch (FileNotFoundException e) {
    Log.e(TAG, "File not found");
   } catch (IOException e) {
    Log.e(TAG, "IO Exception");
   }
  } else {
   Log.e(TAG, "Error opening media card in read/write mode!");
  }
 }
 public static void saveLocation(Context context, Location location) {
  if (isReadWrite()) {
   try {
    File outputFile = new File(context.getExternalFilesDir(null), location.getIdentifier());
    FileOutputStream outputStream = new FileOutputStream(outputFile);
    outputStream.write(location.getBytes());
    outputStream.close();
   } catch (FileNotFoundException e) {
    Log.e(TAG, "File not found");
   } catch (IOException e) {
    Log.e(TAG, "IO Exception");
   }
  } else {
   Log.e(TAG, "Error opening media card in read/write mode!");
  }
 }
 private static boolean isReadOnly() {
  Log.e(TAG, Environment
   .getExternalStorageState());
  return Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment
   .getExternalStorageState());
 }
 private static boolean isReadWrite() {
  Log.e(TAG, Environment
   .getExternalStorageState());
  return Environment.MEDIA_MOUNTED.equals(Environment
   .getExternalStorageState());
 }
}
هر بار که کاربر دکمه ذخیره مکان یا دکمه ذخیره تماس را انتخاب می‌کند، عملیات صورت میگیرد. حال بیایید به کدهای مکان و تماس نگاهی بیندازیم:

  کدهای فایل ( Location .java)

package net.zenconsult.android.model;
publicclass Location {
 private String identifier;
 privatedouble latitude;
 privatedouble longitude;
 public Location() {}
 publicdouble getLatitude() {
  return latitude;
 }
 publicvoid setLatitude(double latitude) {
  this.latitude = latitude;
 }
 publicdouble getLongitude() {
  return longitude;
 }
 publicvoid setLongitude(double longitude) {
  this.longitude = longitude;
 }
 publicvoid setIdentifier(String identifier) {
  this.identifier = identifier;
 }
 public String getIdentifier() {
  return identifier;
 }
 public String toString() {
  StringBuilder ret = new StringBuilder();
  ret.append(getIdentifier());
  ret.append(String.valueOf(getLatitude()));
  ret.append(String.valueOf(getLongitude()));
  return ret.toString();
 }
 publicbyte[] getBytes() {
  return toString().getBytes();
 }
}

کدهای فایل (Contact.java)

package net.zenconsult.android.model;
publicclass Contact {
 private String firstName;
 private String lastName;
 private String address1;
 private String address2;
 private String email;
 private String phone;
 public Contact() {}
 public String getFirstName() {
  return firstName;
 }
 publicvoid setFirstName(String firstName) {
  this.firstName = firstName;
 }
 public String getLastName() {
  return lastName;
 }
 publicvoid setLastName(String lastName) {
  this.lastName = lastName;
 }
 public String getAddress1() {
  return address1;
 }
 publicvoid setAddress1(String address1) {
  this.address1 = address1;
 }
 public String getAddress2() {
  return address2;
 }
 publicvoid setAddress2(String address2) {
  this.address2 = address2;
 }
 public String getEmail() {
  return email;
 }
 publicvoid setEmail(String email) {
  this.email = email;
 }
 public String getPhone() {
  return phone;
 }
 publicvoid setPhone(String phone) {
  this.phone = phone;
 }
 public String toString() {
  StringBuilder ret = new StringBuilder();
  ret.append(getFirstName() + "|");
  ret.append(getLastName() + "|");
  ret.append(getAddress1() + "|");
  ret.append(getAddress2() + "|");
  ret.append(getEmail() + "|");
  ret.append(getPhone() + "|");
  return ret.toString();
 }
 publicbyte[] getBytes() {
  return toString().getBytes();
 }
}
کلاس‌های مکان و تماس با استاندارد یکسانی طراحی شده‌اند و داده‌ها در محلی امن، نگه‌داری می‌شوند. هر کدام از آنها شامل ()toString و ()getBytes است که کل محتوای کلاس را به عنوان یک رشته یا مجموعه‌ای از بایت‌ها برمیگرداند.
اگر بنا بود تا به صورت دستی یک شئ تماس را اضافه کنیم، احتمالا باید به صورت زیر عمل میکردیم:
final Contact contact = new Contact();
contact.setFirstName("User 1");
contact.setLastName("L1");
contact.setAddress1("");
contact.setAddress2("");
contact.setEmail("name@site.net");
contact.setPhone("12120031337");

اشتراک‌ها
پروژه ASP.net MVC Awesome

jQuery based helpers (controls) for ASP.net MVC designed to build highly responsive and interactive Ajax-enabled Web applications  

پروژه ASP.net MVC Awesome
مطالب
مدیریت محل اعمال Google analytics در ASP.NET MVC
ذخیره سازی اطلاعات بازدیدهای کاربران، در طول زمان حجم بالایی از بانک اطلاعاتی را به خود اختصاص خواهد داد؛ به علاوه کند شدن کوئری‌های مرتبط با آن، به همراه مصرف بالای منابع سیستم. به همین جهت اکثر سایت‌ها از Google analytics برای مدیریت جمع آوری بازدیدهای کاربران خود استفاده می‌کنند و این ابزار واقعا عالی و حرفه‌ای طراحی شده و پیاده سازی همانند آن شاید در حد یک پروژه‌ی‌ چندساله باشد.
اضافه کردن Google analytics به یک سایت، بسیار ساده است. در آن ثبت نام می‌کنید؛ سپس آدرس دومین خود را وارد کرده و یک قطعه کد جاوا اسکریپتی را دریافت خواهید کرد که باید به انتهای تمام صفحات سایت خود اضافه نمائید و ... همین.
اضافه کردن این کد در ASP.NET MVC می‌تواند در فایل layout یا همان master page سایت انجام شود تا به صورت خودکار به تمام صفحات اعمال گردد.

مشکل!
من نمی‌خواهم که صفحات غیرعمومی سایت نیز دارای کدهای Google analytics باشند و بی‌جهت Google به این‌جاها نیز سرکشی زاید کند! چکار باید کرد؟
احتمالا عنوان می‌کنید که باید یک if و else به همراه آرایه‌ای از نام‌ها و آدرس‌های صفحات غیرعمومی سایت تهیه کرد و بر این اساس کدهای Google analytics را در master page درج کرد یا خیر.
بله. این روش کار می‌کنه ولی بهینه نیست و همچنین نگهداری آن در طول زمان مشکل است. سایت توسعه خواهد یافت، صفحات غیرعمومی بیشتر خواهند شد و ممکن است در این بین فراموش شود که کدهای مرتبط به روز شوند.

روش بهتر:
آیا می‌توان در یک View مشخص کرد که فیلتر Authorize در اکشن متد متناظری که آن‌را رندر کرده است بکار گرفته شده است یا خیر؟
صفحات غیرعمومی سایت در ASP.NET MVC با فیلتر Authorize محافظت می‌شوند. این فیلتر را می‌توان به کل یک کنترلر اعمال کرد تا به تمام اکشن متدهای آن اعمال شود؛ یا فقط به یک اکشن متد خاص که Viewایی خاص را رندر می‌کند.

نحوه پیاده سازی تشخیص وجود فیلتر Authorize را در یک View رندر شده، در متد کمکی زیر می‌توان مشاهده کرد:
@helper IncludeGoogleAnalytics(WebViewPage page)
    {
        var controller = page.ViewContext.Controller;
        var controllerHasAuthorizeAttribute = controller.GetType().GetCustomAttributes(typeof(AuthorizeAttribute), true).Any();
        var currentActionName = page.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
        var actionHasAuthorizeAttribute = controller.GetType().GetMethods()
                                                    .Where(x => x.Name == currentActionName &&
                                                                x.GetCustomAttributes(typeof(AuthorizeAttribute), true).Any())                                                    
                                                    .Any();
        if (!controllerHasAuthorizeAttribute && !actionHasAuthorizeAttribute)
        {
            string trackingId = ConfigurationManager.AppSettings["GoogleAnalyticsID"];
    <script type="text/javascript">
        var _gaq = _gaq || [];
        _gaq.push(['_setAccount', '@trackingId']);
        _gaq.push(['_trackPageview']);
        (function () {
            var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
            ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
            var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
        })();    
    </script>
        }

  توضیحات:
این متد در فایلی به نام HtmlUtils قرار گرفته در پوشه app_code تعریف شده است و بکارگیری آن در یک فایل master page به نحو زیر خواهد بود:
@HtmlUtils.IncludeGoogleAnalytics(this)

در این متد به کمک خاصیت page.ViewContext.Controller می‌توان به کنترلری که در حال رندر کردن View جاری است دسترسی یافت. اکنون که به کنترلر دسترسی داریم، به کمک Reflection، ویژگی‌ها یا Attributes آن‌را یافته و بررسی می‌کنیم که آیا دارای AuthorizeAttribute است یا خیر. بر این اساس می‌توان تصمیم گرفت که آیا View در حال نمایش عمومی است یا خصوصی. اگر عمومی بود، کدهای اسکریپتی Google analytics به صورت خودکار به صفحه تزریق می‌شوند.
همچنین در اینجا فرض بر این است که Id منتسب به دومین جاری در کلیدی به نام GoogleAnalyticsID در فایل کانفیگ برنامه در قسمت app settings آن تعریف شده است.
 
مطالب
مدیریت پیشرفته‌ی حالت در React با Redux و Mobx - قسمت اول - Redux چیست؟
Redux و Mobx، کتابخانه‌های کمکی هستند برای مدیریت حالت برنامه‌های پیچیده‌ی React. هرچند React به صورت توکار به همراه امکانات مدیریت حالت است، اما این کتابخانه‌ها مزایای ویژه‌ای را به آن اضافه می‌کنند. در این سری ابتدا کتابخانه‌ی Redux را به صورت خالص و مجزای از React بررسی می‌کنیم. از این کتابخانه در برنامه‌های Angular و Ember هم می‌توان استفاده کرد و به صورت اختصاصی برای React طراحی نشده‌است. سپس آن‌را به برنامه‌های React متصل می‌کنیم. در آخر کتابخانه‌ی محبوب دیگری را به نام Mobx بررسی می‌کنیم که برای مدیریت حالت، اصول برنامه نویسی شیءگرا و همچنین Reactive را با هم ترکیب می‌کند و این روزها در برنامه‌های React، بیشتر از Redux مورد استفاده قرار می‌گیرد.


چرا به ابزارهای مدیریت حالت نیاز داریم؟

به محض رد شدن از مرز پیاده سازی امکانات اولیه‌ی یک برنامه، نیاز به ابزارهای مدیریت حالت نمایان می‌شوند؛ خصوصا زمانیکه نیاز است با اطلاعات قابل توجهی سر و کار داشت. مهم‌ترین دلیل استفاده‌ی از یک ابزار مدیریت حالت، مدیریت منطق تجاری برنامه است. منطق نمایشی برنامه مرتبط است به نحوه‌ی نمایش اجزای آن در صفحه؛ مانند نمایش یک صفحه‌ی مودال، تغییر رنگ عناصر با عبور کرسر ماوس از روی آن‌ها و در کل منطقی که مرتبط و یا وابسته‌ی به هدف اصلی برنامه نیست. از سوی دیگر منطق تجاری برنامه مرتبط است با مدیریت، تغییر و ذخیره سازی اشیاء تجاری مورد نیاز آن؛ مانند اطلاعات حساب کاربری شخص و دریافت اطلاعات برنامه از یک API که مختص به برنامه‌ی خاص ما است و به همین دلیل نیاز به ابزاری برای مدیریت بهینه‌ی آن وجود دارد. برای مثال اینکه در کجا باید منطق تجاری و نمایشی را به هم متصل کرد، می‌تواند چالش بر انگیر باشد. چگونه باید اطلاعات کاربر را ذخیره کرد؟ چگونه React باید متوجه شود که اطلاعات ما تغییر کرده‌است و در نتیجه‌ی آن کامپوننتی را مجددا رندر کند؟ یک ابزار مدیریت حالت، تمام این مسایل را به نحو یک‌دستی در سراسر برنامه، مدیریت می‌کند.
اگر از یک ابزار مدیریت حالت استفاده نکنیم، مجبور خواهیم شد تمام اطلاعات منطق تجاری را در داخل state کامپوننت‌ها ذخیره کنیم که توصیه نمی‌شود؛ چون مقیاس پذیر نیست. برای مثال فرض کنید قرار است تمام اطلاعات state را داخل یک کامپوننت ذخیره کنیم. هر زمانیکه بخواهیم این state را از طریق یک کامپوننت فرزند تغییر دهیم، نیاز خواهد بود این اطلاعات را به والد آن کامپوننت ارسال کنیم که اگر از تعداد زیادی کامپوننت تو در تو تشکیل شده باشد، زمانبر و به همراه کدهای تکراری زیادی خواهد بود. همچنین اینکار سبب رندر مجدد کل برنامه با هر تغییری در state آن می‌شود که غیرضروری بوده و کارآیی برنامه را کاهش می‌دهد. به علاوه در این بین مشخص نیست هر قسمت از state، از کدام کامپوننت تامین شده‌است. به همین جهت نیاز به روشی برای مدیریت حالت در بین کامپوننت‌های برنامه وجود دارد.


داشتن تنها یک محل برای ذخیره سازی state در برنامه

همانطور که در قسمت 8 ترکیب کامپوننت‌ها در سری React 16x بررسی کردیم، هر کامپوننت در React، دارای state خاص خودش است و این state از سایر کامپوننت‌ها کاملا مستقل و ایزوله‌است. این مورد با بزرگ‌تر شدن برنامه و برقراری ارتباط بین کامپوننت‌ها، مشکل ایجاد می‌کند. برای مثال اگر بخواهیم دکمه‌ای را در صفحه قرار داده و توسط این دکمه درخواست صفر شدن مقدار هر کدام از شمارشگرها را صادر کنیم، با صفر کردن value هر کدام از این کامپوننت‌ها، اتفاقی رخ نمی‌دهد. چون state محلی این کامپوننت‌ها، با سایر اجزای صفحه به اشتراک گذاشته نمی‌شود و باید آن‌را تبدیل به یک controlled component کرد، بطوریکه دارای local state خاص خودش نیست و تمام داده‌های دریافتی را از طریق this.props دریافت می‌کند و هر زمانیکه قرار است داده‌ای تغییر کند، رخ‌دادی را به والد خود صادر می‌کند. بنابراین این کامپوننت به طور کامل توسط والد آن کنترل می‌شود. تازه این روش در مورد کامپوننت‌هایی صدق می‌کند که رابطه‌ی والد و فرزندی بین آن‌ها وجود دارد. اگر چنین رابطه‌ای وجود نداشت، باید state را به یک سطح بالاتر انتقال داد. برای مثال باید state کامپوننت Counters را به والد آن که کامپوننت App است، منتقل کرد. پس از آن چون کامپوننت‌های ما، از کامپوننت App مشتق می‌شوند، اکنون می‌توان این state را به تمام فرزندان App توسط props منتقل کرد و به اشتراک گذاشت. این مورد هم مانند مثال انتقال اطلاعات کاربر لاگین شده‌ی به سیستم، به تمام زیر قسمت‌های برنامه، نیاز به ارسال اطلاعات از طریق props یک کامپوننت، به کامپوننت بعدی را دارد و به همین ترتیب برای مابقی که به props drilling مشهور است و روش پسندیده‌ای نیست.


Redux چیست؟ ذخیره سازی کل درخت state یک برنامه، در یک محل. به این ترتیب به یک شیء جاوا اسکریپتی بزرگ خواهیم رسید که در برگیرنده‌ی تمام state برنامه‌است. یکی از مزایای آن امکان serialize و deserialize کل این شیء، به سادگی است. برای مثال توسط متد JSON.stringify می‌توان آن‌را در جائی ذخیره کرد و سپس آن‌را به صورت یک شیء جاو اسکریپتی در زمانی دیگر بازیابی کرد. یکی از مزایای آن، امکان بازیابی دقیق شرایط کاربری است که دچار مشکل شده‌است و سپس دیباگ و رفع مشکل او، در زمانی دیگر.


تاریخچه‌ای از سیستم‌های مدیریت حالت

همه چیز با AngularJS 1x شروع شد که از data binding دو طرفه پشتیبانی می‌کرد. هرچند این روش برای همگام نگه داشتن View و مدل برنامه، مفید است، اما در Viewهای پیچیده، برنامه را کند می‌کند. در همین زمان فیس‌بوک، روش مدیریت حالتی را به نام Flux ارائه داد که از data binding یک طرفه پشتیبانی می‌کرد. به این معنا که در این روش، همواره اطلاعات از View به مدل، جریان پیدا می‌کند. کار کردن با آن ساده‌است؛ چون نیازی نیست حدس زده شود که اکنون جریان اطلاعات از کدام سمت است. اما مشکل آن عدم هماهنگی model و view، در بعضی از حالات است. Flux از این جهت به وجود آمد که مدیریت حالت در برنامه‌های React آن زمان، پیچیده بود و مقیاس پذیری کمی داشت (پیش از ارائه‌ی Context و Hooks). در کل Flux صرفا یکسری الگوی مدیریت حالت را بیان می‌کند و یک کتابخانه‌ی مجزا نیست. بر مبنای این الگوها و قراردادها، می‌توان کتابخانه‌های مختلفی را ایجاد کرد. از این رو در سال 2015، کتابخانه‌های زیادی مانند Reflux, Flummox, MartyJS, Alt, Redux و غیره برای پیاده سازی آن پدید آمدند. در این بین، کتابخانه‌ی Redux ماندگار شد و پیروز این نبرد بود!


توابع خالص و ناخالص (Pure & Impure Functions)

پیش از شروع بحث، نیاز است با یک‌سری از واژه‌ها مانند توابع خالص و ناخالص آشنا شد. این نکات از این جهت مهم هستند که Redux فقط با توابع خالص کار می‌کند.
توابع خالص: تعدادی آرگومان را دریافت کرده و بر اساس آن‌ها، مقداری را باز می‌گردانند.
// Pure
const add = (a, b) => {
  return a + b;
}
در اینجا یک تابع خالص را مشاهده می‌کنید که a و b را دریافت کرده و بر این اساس، یک خروجی کاملا مشخص را بازگشت می‌دهد.

توابع ناخالص: این نوع توابع سبب تغییراتی در متغیرهایی خارج از میدان دید خود می‌شوند و یا به همراه یک سری اثرات جانبی (side effects) مانند تعامل با دنیای خارج (وجود یک console.log در آن تابع و یا دریافت اطلاعاتی از یک API خارجی) هستند.
// Impure
const b;

const add = (a) => {
  return a + b;
}
تابع تعریف شده‌ی در اینجا ناخالص است؛ چون با اطلاعاتی خارج از میدان دید خود مانند متغیر b، تعامل دارد. این تعامل با دنیای خارج، حتی در حد نوشتن یک console.log:
// Impure
const add = (a, b) => {
  console.log('lolololol');
  return a + b;
}
یک تابع خالص را تبدیل به یک تابع ناخالص می‌کند و یا نمونه‌ی دیگر این تعاملات، فراخوانی سرویس‌های backend در برنامه هستند که یک تابع را ناخالص می‌کنند:
// Impure
const add = (a, b) => {
   Api.post('/add', { a, b }, (response) => {
    // Do something.
   });
};


روش‌هایی برای جلوگیری از تغییرات در اشیاء در جاوا اسکریپت

ایجاد تغییرات در آرایه‌ها و اشیاء (Mutating arrays and objects) نیز ناخالصی ایجاد می‌کند؛ از این جهت که سبب تغییراتی در دنیای خارج (خارج از میدان دید تابع) می‌شویم. به همین جهت نیاز به روش‌هایی وجود دارد که از این نوع تغییرات جلوگیری کرد:
// Copy object
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original);
برای تغییری در یک شیء، تنها کافی است خاصیتی را به آن اضافه کنیم و یا با استفاده از واژه‌ی کلیدی delete، خاصیتی را از آن حذف کنیم. به همین جهت برای اینکه تغییرات ما بر روی شیء اصلی اثری را باقی نگذارند، یکی از روش‌ها، استفاده از متد Object.assign است. کار آن، یکی کردن اشیایی است که به آن ارسال می‌شوند. به همین جهت در اینجا با یک شیء خالی، از صفر شروع می‌کنیم. سپس دومین آرگومان آن را به همان شیء مدنظر، تنظیم می‌کنیم. به این ترتیب به یک کپی از شیء اصلی می‌رسیم که دیگر به آن، اتصالی را ندارد. به همین جهت اگر بر روی این شیء کپی تغییراتی را ایجاد کنیم، به شیء اصلی کپی نمی‌شود و سبب تغییرات در آن (mutation) نخواهد شد.
برای مثال در React، برای انجام رندر نهایی، در پشت صحنه کار مقایسه‌ی اشیاء صورت می‌گیرد. به همین جهت اگر همان شیءای را که ردیابی می‌کند تغییر دهیم، دیگر نمی‌تواند به صورت مؤثری فقط قسمت‌های تغییر کرده‌ی آن‌را تشخیص داده و کار رندر را فقط بر اساس آن‌ها انجام دهد و مجبور خواهد شد کل یک شیء را بارها و بارها رندر کند که اصلا بهینه نیست. به همین جهت، ایجاد تغییرات مستقیم در شیءای که به state آن انتساب داده می‌شود، مجاز نیست.

متد Object.assign، چندین شیء را نیز می‌تواند با هم یکی کند و شیء جدیدی را تشکیل دهد:
// Extend object
const original = { a: 1, b: 2 };
const extension = { c: 3 };
const extended = Object.assign({}, original, extension);
روش دیگر ایجاد یک کپی و یا clone از یک شیء را که پیشتر در سری «React 16x» بررسی کردیم، به کمک امکانات ES-6، به صورت زیر است:
// Copy object
const original = { a: 1, b: 2 };
const copy = { ...original };
در اینجا نیز ابتدا یک شیء خالی را ایجاد می‌کنیم و سپس توسط spread operator، خواص شیء قبلی را درون آن باز کرده و قرار می‌دهیم. به این ترتیب به یک clone از شیء اصلی می‌رسیم. این حالت نیز از ترکیب چندین شیء با هم، پشتیبانی می‌کند:
// Extend object
const original = { a: 1, b: 2 };
const extension = { c: 3 };
const extended = { ...original, ...extension };


روش‌هایی برای جلوگیری از تغییرات در آرایه‌ها در جاوا اسکریپت

متد slice آرایه‌ها نیز بدون ذکر آرگومانی، یک کپی از آرایه‌ی اصلی را ایجاد می‌کند:
// Copy array
const original = [1, 2, 3];
const copy = [1, 2, 3].slice();
همچنین معادل همین قطعه کد در ES-6 به همراه spread operator به صورت زیر است:
// Copy array
const original = [1, 2, 3];
const copy = [ ...original ];
و یا اگر بخواهیم یک کپی از چندین آرایه را ایجاد کنیم می‌توان از متد concat استفاده کرد:
// Extend array
const original = [1, 2, 3];
const extended = original.concat(4);
const moreExtended = original.concat([4, 5]);
متد Array.push، هرچند سبب افزوده شدن عنصری به یک آرایه می‌شود، اما یک mutation را نیز ایجاد می‌کند؛ یعنی تغییرات آن به دنیای خارج اعمال می‌گردد. اما Array.concat یک آرایه‌ی کاملا جدید را ایجاد می‌کند و همچنین امکان ترکیب آرایه‌ها را نیز به همراه دارد.
معادل قطعه کد فوق در ES-6 و به همراه spread operator آن به صورت زیر است:
// Extend array
const original = [1, 2, 3];
const extended = [ ...original, 4 ];
const moreExtended = [ ...original, ...extended, 5 ];


مفاهیم ابتدایی Redux


در Redux برای ایجاد تغییرات در شیء کلی state، از مفهومی به نام dispatch actions استفاده می‌شود. action در اینجا به معنای رخ‌دادن چیزی است؛ مانند کلیک بر روی یک دکمه و یا دریافت اطلاعاتی از یک API. در این حالت مقایسه‌ای بین وضعیت قبلی state و وضعیت فعلی آن صورت می‌گیرد و تغییرات مورد نیاز جهت اعمال به UI، محاسبه خواهند شد.
اصلی‌ترین جزء Redux، تابعی است به نام Reducer. این تابع، یک تابع خالص است و دو آرگومان را دریافت می‌کند:


تابع Reducer، بر اساس action و یا رخ‌دادی، ابتدا کل state برنامه را دریافت می‌کند و سپس خروجی آن بر اساس منطق این تابع، یک state جدید خواهد بود. اکنون که این state جدید را داریم، برنامه‌ی React ما می‌تواند به تغییرات آن گوش فرا داده و بر اساس آن، UI را به روز رسانی کند. به این ترتیب کار اصلی مدیریت state، به خارج از برنامه‌ی React منتقل می‌شود.

در این تصویر، تابع action creator را هم ملاحظه می‌کند که کاملا اختیاری است. یک action می‌تواند یک رشته و یا یک عدد باشد. با پیچیده شدن برنامه، نیاز به ارسال یک‌سری متادیتا و یا اطلاعات بیشتری از اکشن رسیده‌است. کار action creator، ایجاد شیء action، به صورت یک دست و یکنواخت است تا دیگر نیازی به ایجاد دستی آن نباشد.


مزایای کار با Redux

- داشتن یک مکان مرکزی برای ذخیره سازی کلی حالت برنامه (به آن «source of truth» و یا store هم گفته می‌شود): به این ترتیب مشکل ارسال خواص در بین کامپوننت‌های عمیق و چند سطحی، برطرف شده و هر زمانیکه نیاز بود، از آن اطلاعاتی را دریافت و یا با قالب خاصی، آن‌را به روز رسانی می‌کنند.
- رسیدن به به‌روز رسانی‌های قابل پیش بینی state: هرچند در حالت کار با Redux، یک شیء بزرگ جاوا اسکریپتی، کل state برنامه را تشکیل می‌دهد، اما امکان کار مستقیم با آن و تغییرش وجود ندارد. به همین جهت است که برای کار با آن، باید رویدادی را از طریق actionها به تابع Reducer آن تحویل داد. چون Reducer یک تابع خالص است، با دریافت یک سری ورودی مشخص، همواره یک خروجی مشخص را نیز تولید می‌کند. به همین جهت قابلیت ضبط و تکرار را پیدا می‌کند؛ همان بحث serialize و deseriliaze، توسط ابزاری مانند: logrocket. به علاوه قابلیت undo و redo را نیز می‌توان به این ترتیب پیاده سازی کرد (state جدید محاسبه شده، مشخص است، کل state قبلی را نیز داریم یا می‌توان ذخیره کرد و سپس برای undo، آن‌را جایگزین state جدید نمود). افزونه‌ی redux dev tools نیز قابلیت import و export کل state را به همراه دارد.
- چون تابع Reducer، یک تابع خالص است و همواره خروجی‌های مشخصی را به ازای ورودی‌های مشخصی، تولید می‌کند، آزمایش کردن، پیاده سازی و حتی logging آن نیز ساده‌تر است. در این بین حتی یک افزونه‌ی مخصوص نیز برای دیباگ آن تهیه شده‌است: redux-devtools-extension. تابع خالص، تابعی است که به همراه اثرات جانبی نیست (side effects)؛ به همین جهت عملکرد آن کاملا قابل پیش بینی بوده و آزمون پذیری آن به دلیل نداشتن وابستگی‌های خارجی، بسیار بالا است.


Context API خود React چطور؟

در قسمت 33 سری React 16x، مفهوم React Context را بررسی کردیم. پس از معرفی آن با React 16.3، مقالات زیادی منتشر شدند که ... Redux مرده‌است (!) و یا بجای Redux از React context استفاده کنید. اما واقعیت این است که React Redux در پشت صحنه از React context استفاده می‌کند و تابع connect آن دقیقا به همین زیر ساخت متصل می‌شود.
کار با Redux مزایایی مانند کارآیی بالاتر، با کاهش رندر‌های مجدد کامپوننت‌ها، دیباگ ساده‌تر با افزونه‌های اختصاصی و همچنین سفارشی سازی، مانند نوشتن میان‌افزارها را به همراه دارد. اما شاید واقعا نیازی به تمام این امکانات را هم نداشته باشید؛ اگر هدف، صرفا انتقال ساده‌تر اطلاعات بوده و برنامه‌ی مدنظر نیز کوچک است. React Context برخلاف Redux، نگهدارنده‌ی state نیست و بیشتر هدفش محلی برای ذخیره سازی اطلاعات مورد استفاده‌ی در چندین و چند کامپوننت تو در تو است. هرچند شبیه به Redux می‌توان اشاره‌گرهایی از متدها را به استفاده کنندگان از آن ارسال کرد تا سبب بروز رویدادها و اکشن‌هایی در کامپوننت تامین کننده‌ی Contrext شوند (یا یک کتابخانه‌ی ابتدایی شبیه به Redux را توسط آن تهیه کرد). بنابراین برای انتخاب بین React Context و Redux باید به اندازه‌ی برنامه، تعداد نفرات تیم، آشنایی آن‌ها با مفاهیم Redux دقت داشت.
مطالب
آموزش فریم ورک Vuetify قسمت دوم - UI Components بخش دوم
در بخش قبل با تعدادی از UI Component های vutify آشنا شدیم. در ادامه به بررسی و یادگیری تعدادی دیگر از این UI Component‌ها می‌پردازیم.

این کامپوننت یک کامپوننت همه کاره است. card‌ها میتوانند حاوی محتوا و اقداماتی در مورد یک موضوع واحد باشند. card ها ممکن است حاوی یک عکس، متن و یک لینک در مورد یک موضوع باشند. 
هر card دارای این سه جزء یا کامپوننت اساسی است: v-card-title , v-card-text , v-card-action که به ترتیب حاوی عنوان card ، متن card و عملیاتی که انجام میدهد می‌باشد.
عناصر تشکیل دهنده یک card می‌توانند به صورت زیر باشند:

قطعه کد زیر یک نمونه ساده از ایجاد یک card را به ما نشان می‌دهد.
<div id="app">
  <v-app id="inspire">
    <v-layout>
      <v-flex xs12 sm6 offset-sm3>
        <v-card>
          <v-img height="200px" src="https://cdn.vuetifyjs.com/images/cards/docks.jpg">
            <v-container fill-height fluid>
              <v-layout fill-height>
                <v-flex xs12 align-end flexbox>
                  <span>Top 10 Australian beaches</span>
                </v-flex>
              </v-layout>
            </v-container>
          </v-img>
          <v-card-title>
            <div>
              <span>Number 10</span><br>
              <span>Whitehaven Beach</span><br>
              <span>Whitsunday Island, Whitsunday Islands</span>
            </div>
          </v-card-title>
          <v-card-actions>
            <v-btn flat color="orange">Share</v-btn>
            <v-btn flat color="orange">Explore</v-btn>
          </v-card-actions>
        </v-card>
      </v-flex>
    </v-layout>
  </v-app>
</div>

از این کامپوننت جهت ساخت اسلایدر می‌توان استفاده کرد . اسلایدرها معمولا می‌توانند حاوی عکس و یا متن و یا ترکیبی از هر دو باشند. این کامپوننت دقیقا مشابه carousel در bootstrap عمل می‌کند .
<div id="app">
  <v-app id="inspire">
    <v-carousel>
      <v-carousel-item  v-for="(color, i) in colors" :key="color">
        <v-sheet :color="color" height="100%" tile>
          <v-layout align-center fill-height justify-center>
            <div>Slide {{ i + 1 }}</div>
          </v-layout>
        </v-sheet>
      </v-carousel-item>
    </v-carousel>
  </v-app>
</div>


از این کامپوننت برای انتقال اطلاعات به صورت قطعه‌های کوچک استفاده می‌شود. chip‌ها دارای چهار نوع اولیه می‌باشند. منظم، با آیکون، با پرتره و قابل تعویض.
در پایین با یک مثال، این چهار نوع اولیه نمایش داده شده‌اند.
<div id="app">
  <v-app id="inspire">
    <v-container fluid>
      <v-layout row wrap>
        <v-flex md6 sm12>
          <div>
            <v-chip close>Example Chip</v-chip>
          </div>
          <div>
            <v-chip>Example Chip</v-chip>
          </div>
        </v-flex>
        <v-flex md6 sm12 xs12>
          <div>
            <v-chip close>
              <v-avatar>
                <img src="https://randomuser.me/api/portraits/men/35.jpg" alt="trevor">
              </v-avatar>
              Trevor Hansen
            </v-chip>
          </div>
          <div>
            <v-chip>
              <v-avatar>A</v-avatar>
              ANZ Bank
            </v-chip>
          </div>
        </v-flex>
      </v-layout>
    </v-container>
  </v-app>
</div>

این کامپوننت برای نشان دادن اطلاعات مورد استفاده قرار می‌گیرد و به ما این اجازه را میدهد که بتوانیم چگونگی نمایش اطلاعات را سازماندهی کنیم. این امکانات عبارتند از مرتب سازی، جستجو، صفحه بندی و انتخاب اطلاعات. جهت نمایش این اطلاعات می‌توان از card ها و یا جداول استفاده نمود.
در مثال پایین جهت نمایش اطلاعات از card ها استفاده شده‌است:
<div id="app">
  <v-app id="inspire">
    <v-container fluid grid-list-md>
      <v-data-iterator
        :items="items"
        :rows-per-page-items="rowsPerPageItems"
        :pagination.sync="pagination" content-tag="v-layout" row wrap>
        <template v-slot:item="props">
           <v-card>
              <v-card-title><h4>{{ props.item.name }}</h4></v-card-title>
              <v-divider></v-divider>
              <v-list dense>
                <v-list-tile>
                  <v-list-tile-content>Calories:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.calories }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Fat:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.fat }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Carbs:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.carbs }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Protein:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.protein }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Sodium:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.sodium }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Calcium:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.calcium }}</v-list-tile-content>
                </v-list-tile>
                <v-list-tile>
                  <v-list-tile-content>Iron:</v-list-tile-content>
                  <v-list-tile-content>{{ props.item.iron }}</v-list-tile-content>
                </v-list-tile>
              </v-list>
            </v-card>
          </v-flex>
        </template>
      </v-data-iterator>
    </v-container>
  </v-app>
</div>
new Vue({
  el: '#app',
  data () {
    return {
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name'
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Fat (g)', value: 'fat' },
        { text: 'Carbs (g)', value: 'carbs' },
        { text: 'Protein (g)', value: 'protein' },
        { text: 'Iron (%)', value: 'iron' }
      ],
      desserts: [
        {
          name: 'Ice cream sandwich',
          calories: 237,
          fat: 9.0,
          carbs: 37,
          protein: 4.3,
          iron: '1%'
        }
        
      ]
    }
  }
})

این کامپوننت جهت نمایش اطلاعات، به صورت یک جدول مورد استفاده قرار می‌گیرد. امکاناتی که برای این جداول می‌توان در نظر گرفت عبارتند از مرتب سازی عناصر جدول، جستجوی عناصر جدول، صفحه بندی جدول در صورتیکه اطلاعات موجود، بیش از یک صفحه باشند؛ ویرایش خطی، راهنمایی‌های سربرگ و انتخاب ردیفهای جدول. جداول استاندارد حاوی اطلاعات، بدون هیچ گونه قابلیت اضافی هستند.
برای کار با این کامپوننت میتوان از تنظیمات بسیار زیادی استفاده کرد که سعی شده در مثال پایین تعدادی از این تنظیمات استفاده شود.
<div id="app">
  <v-app id="inspire">
    <v-data-table :headers="headers" :items="desserts">
      <template v-slot:items="props">
        <td>{{ props.item.name }}</td>
        <td>{{ props.item.calories }}</td>
        <td>{{ props.item.fat }}</td>
        <td>{{ props.item.carbs }}</td>
        <td>{{ props.item.protein }}</td>
        <td>{{ props.item.iron }}</td>
      </template>
    </v-data-table>
  </v-app>
</div>
new Vue({
  el: '#app',
  data () {
    return {
      headers: [
        {
          text: 'Dessert (100g serving)',
          align: 'left',
          sortable: false,
          value: 'name'
        },
        { text: 'Calories', value: 'calories' },
        { text: 'Fat (g)', value: 'fat' },
        { text: 'Carbs (g)', value: 'carbs' },
        { text: 'Protein (g)', value: 'protein' },
        { text: 'Iron (%)', value: 'iron' }
      ],
      desserts: [
        {
          name: 'Frozen Yogurt',
          calories: 159,
          fat: 6.0,
          carbs: 24,
          protein: 4.0,
          iron: '1%'
        },
        {
          name: 'Ice cream sandwich',
          calories: 237,
          fat: 9.0,
          carbs: 37,
          protein: 4.3,
          iron: '1%'
        },
        {
          name: 'Eclair',
          calories: 262,
          fat: 16.0,
          carbs: 23,
          protein: 6.0,
          iron: '7%'
        },
        {
          name: 'Cupcake',
          calories: 305,
          fat: 3.7,
          carbs: 67,
          protein: 4.3,
          iron: '8%'
        },
        {
          name: 'Gingerbread',
          calories: 356,
          fat: 16.0,
          carbs: 49,
          protein: 3.9,
          iron: '16%'
        }
      ]
    }
  }
})  

این کامپوننت به کاربران در مورد یک کار یا موضوع خاص اطلاع می‌دهد و ممکن است حاوی اطلاعات بحرانی، تصمیم گیرنده، یا شامل چندین وظیفه باشد. 
این کامپوننت حاوی دو بخش می‌باشد، یکی برای فعال کردن dialog و دیگری جهت نمایش محتوای آن (به طور پیش فرض). معمولا از این کامپوننت جهت نمایش خطاهایی که روند اجرای برنامه را متوقف میکنند و اطلاعاتی که نیاز به یک کار خاص، تصمیم گیری یا تایید کاربر دارند مانند سیاست‌های حفظ حریم خصوصی استفاده می‌شود. 
<div id="app">
  <v-app id="inspire">
    <div>
      <v-dialog v-model="dialog" width="500">
        <template v-slot:activator="{ on }">
          <v-btn color="red lighten-2" dark v-on="on">
            Click Me
          </v-btn>
        </template>
  
        <v-card>
          <v-card-title primary-title>
            Privacy Policy
          </v-card-title>
  
          <v-card-text>
            Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
          </v-card-text>
  
          <v-divider></v-divider>
  
          <v-card-actions>
            <v-spacer></v-spacer>
            <v-btn color="primary" flat @click="dialog = false">
              I accept
            </v-btn>
          </v-card-actions>
        </v-card>
      </v-dialog>
    </div>
  </v-app>
</div>
در این مثال کاربر ابتدا فقط یک صفحه حاوی یک دکمه را مشاهده می‌نماید که پس از کلیک بر روی دکمه، یک dialog box برای او ظاهر می‌شود. همانطور که گفته شد این dialog box می‌تواند حاوی اطلاعات مختلفی باشد.


این کامپوننت برای کاهش فضای عمودی برای زمانیکه مقدار زیادی اطلاعات وجود دارد می‌تواند مفید باشد. 
لازم به ذکر است که به طور پیش فرض در یک زمان تنها یک پنل عمودی می‌تواند باز باشد.
<div id="app">
  <v-app id="inspire">
    <v-expansion-panel>
      <v-expansion-panel-content v-for="(item,i) in 5" :key="i">
        <template v-slot:header>
          <div>Item</div>
        </template>
        <v-card>
          <v-card-text>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</v-card-text>
        </v-card>
      </v-expansion-panel-content>
    </v-expansion-panel>
  </v-app>
</div>

اشتراک‌ها
Mozilla و تعدیل 250 نفر

Sad news from the folks behind Firefox — they've laid off a quarter of their entire workforce, which reportedly includes both the DevTools and MDN teams.  

Mozilla و تعدیل 250 نفر