در قسمت اول این سری، درباره کلیات نامگذاری و قواعد و قراردادهای رایج نوشتم. در ادامه کمی به جزئیات نامگذاری میپردازم.
مواردی که تو این قسمت تحت عنوان جزئیات به اونا پرداخته میشه عبارتنداز:
عبارات مخفف و نحوه استفاده از اونا در نامگذاری
زبانهای برنامه نویسی و نحوه استفاده از کلمات کلیدی این زبانها
نسخه های جدید پیاده سازی ها و نحوه نامگذاریشون
کلمات مرکب و تشخیصشون به همراه استثناهای موجود
و درنهایت خلاصه ای از نامگذاری اجزای مختلف یک کتابخونه
عبارات مخفف
در حالت کلی استفاده از عبارات مخفف در نامگذاری توصیه نمیشه مگر اینکه عبارت موردنظر بسیار رایج باشه و خواننده بلافاصله متوجه مفهومش بشه. برای مثال HTML ، XML ، IO و UI بسیار رایج هستن، اما باید از بکاربردن عبارات مخفف غیررایج در نامگذاری پرهیز کرد.
برای تشخیص اینکه آیا یک عبارت مخفف رایج هست (تا بشه از اون در نامگذاری استفاده کرد) یا نه، میشه از یه روش بسیار ساده استفاده کرد. برای اینکار کافیه تا عبارت موردنظر رو در گوگل جستجو کنیم و اگه اولین نتایج بدست اومده مربوط به مفهوم موردنظر باشه میشه نتیجه گرفت که اون عبارت مخفف به اندازه کافی رایج هست.
براساس تعریف، یک مخفف حداقل باید 2 حرف داشته باشه. نحوه برخورد با مخففهای دارای بیشتر از 2 حرف با مخففهای دارای 2 حرف با هم فرق داره (دلیل اصلی این اختلاف، جلوگیری از بروز اشتباه به دلیل کمی تعداد کاراکترهاست). با مخففهای دارای 2 حرف مانند کلمهای یک حرفی برخورد میشه، درصورتیکه با سایر مخففها مثل یک کلمه کامل چندحرفی برخورد میشه. برای مثال IOStream برای روش PascalCasing و ioStream برای روش camelCasing، همچنین از HtmlBody و htmlBody بهترتیب برای روشهای Pascal و camel استفاده میشه.
موارد زیادی رو میشه پیدا کرد که در ابتدا بهنظر میرسه برای پیادهسازیشون باید قوانین اشاره شده رو نقض کرد. این موارد شامل استفاده از کتابخونههای سایر پلتفرمها (مثل MFC, HTML و غیره)، جلوگیری از مشکلات جغرافیایی (مثلا نام کشورها)، احترام به نام افراد درگذشته، و مواردی از این دست میشه. اما در بیشتر این موارد هم میشه بدون نقض قوانین فوق و با تغییر عبارت اصلی (که موجب تطابق با این قوانین میشه) بدون اینکه لطمهای به مفهومش بزنه، نامگذاری رو انجام داد.
تنها موردی که بهنظر میرسه میتونه قوانین فوق رو نقض کنه «نامهای تجاری» اند. البته استفاده از نامهای تجاری توصیه نمیشه، چون این نامها معمولا سریعتر از محتوای کتابخونهها تغییر میکنن!
برای درک بهتر قانون «عدم استفاده از عبارات مخففی که رایج نیستند» مثالی از زبان توسعه دهندگان داتنتفریمورک آورده میشه. در کلاس Color متد زیر با Overloadهای مختلف وجود داره:
public class Color { … public static Color FromArgb (…) { … } }
در این مورد برای رعایت قوانین بهجای استفاده از ARGB از عبارت Argb استفاده شده. اما بکارگیری این عبارت موجب شده تا این سوال بهظاهر خندهدار اما درست پیش بیاد: «چیجوری میشه در این کلاس، یک رنگ رو از ARGB تبدیل کرد؟ هرچی که من میبینم فقط تبدیل از طریق آرگومان b (یا Argb ) هست.»
خب حالا بهنظر میرسه که در اینجا باید قوانین رو نقض کرد و از عنوان FromARGB که مفهوم درست رو میرسونه استفاده کرد. اما با کمی دقت متوجه میشیم که این قوانین در ابتدا نیز با پیادهسازی نشون داده شده نقض شدن! یعنی چی؟ خب، همه میدونیم که عبارت RGB مخفف معروفی برای عبارت Red Green Blue هست. اما استفاده از ARGB برای افزودن کلمه Alpha به ابتدای عبارت مذکور چندان رایج نیست. پس استفاده از مخفف Argb از همون اول اشتباه بوده. بنابراین راهحل بهتر میتونه استفاده از نام FromAlphaRgb باشه که هم قوانین فوق رو نقض نکرده و هم مفهوم رو بهتر میرسونه.
زبانهای برنامه نویسی
عبارات و کلماتی که مختص یک زبان برنامه نویسی خاص (مثل int یا long در #C) هستند رو نباید به عنوان نام یا بخشی از نام یکی از اجزای برنامه انتخاب کرد. مثلا برای دریافت مقدار عددی یک شی نباید از نامی مثل GetInt استفاده کرد. برای این کار میشه از نامی مناسبتر با مفهومی معنادار مثل GetLength استفاده کرد.
در مواردی که به دلایل مختلف نشه از روش بالا استفاده کرد بهتره به جای استفاده از عبارات مختص یک زبان برنامه نویسی در صورت امکان از معادل کلی تر اون در CLR استفاده کرد. مثلا برای متدی که تبدیلی به نوع Int64 انجام میده، به جای استفاده از نام GetLong یا ToLong بهتره از GetInt64 یا ToInt64 استفاده بشه.
درمواردی که نشه یک عبارت معنادار مناسب یافت، و همچنین نوع پارامتر یا مقدار مربوطه مهم نباشه، بهتره از کلماتی کلی و معمول مثل item یا value استفاده بشه. مثل:
void Write(double value);
void Write(float value);
void Write(short value);
void Write(float value);
void Write(short value);
نکته جالبی که بد نیست در اینجا بهش اشاره بشه اینه که تو VB.NET یه سری کلمه های کلیدی همنام با کلاسهای پیاده شده در کتابخونه های پایه ای دات نت وجود دارن. مثل Delegate یا Module و یا Application. با اینکه ویژوال بیسک هم مثل سی شارپ روشی برای جداسازی کلمه های کلیدی از نام اجزا داره (با استفاده از []) اما استفاده از این نامها در طراحی این زبون برنامه نویسی یک نقطه ضعف به حساب میاد.
یکی دیگه از نقاط ضعف طراحی در دات نت، نامگذاری استثنا بسیار معرف NullReferenceException هست. استفاده از این کلاس در VB.NET با توجه به اینکه این زبون از عبارت Nothing به جای null استفاده میکنه، یک عیب به حساب میاد. یعنی در نامگذاری این استثنا، قاعده اشاره شده در این قسمت رعایت نشده و از کلمه ای مخصوص یک زبان برنامه نویسی (در اینجا عبارت null که مثلا مخصوص #C هست) استفاده شده.
نسخه های جدید
برای نامگذاری قسمتهای بروزشده و جدید یک برنامه بهتره از نامهایی مشابه نسخه قدیمی برای هدایت برنامه نویسان و مشخص شدن آسونتر رابطه بین دو نسخه استفاده بشه. مثال:
public class AppDomain { /// <summary> /// Establishes the specified directory path as the location where assemblies are shadow copied. /// </summary> /// <param name="path">The fully qualified path to the shadow copy location. </param><exception cref="T:System.AppDomainUnloadedException">The operation is attempted on an unloaded application domain. </exception><filterpriority>2</filterpriority><PermissionSet><IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="ControlAppDomain"/></PermissionSet> [Obsolete("AppDomain.SetCachePath has been deprecated. Please investigate the use of AppDomainSetup.CachePath instead. http://go.microsoft.com/fwlink/?linkid=14202")] [SecurityCritical] [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public void SetCachePath(string path) { InternalSetCachePath(path); } }
public class AppDomainSetup { /// <summary> /// Gets or sets the name of an area specific to the application where files are shadow copied. /// </summary> /// /// <returns> /// The fully qualified name of the directory path and file name where files are shadow copied. /// </returns> /// <filterpriority>2</filterpriority><PermissionSet><IPermission class="System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true"/></PermissionSet> public string CachePath { [SecuritySafeCritical] get { return VerifyDir(Value[9], false); } set { Value[9] = NormalizePath(value, false); } } }
- اگه احساس میشه که باید عبارتی به نام قدیمی اضافه بشه بهتره از پسوند به جای پیشوند استفاده کرد. این روش کمک زیادی هنگام مطالعه سندها و یا هنگام استفاده از Intellisense و یا گشتن در لیست اجزای یک برنامه میکنه. مثل ReaderWriterLockSlim به عنوان نسخه جدید کلاس ReaderWriterLock به جای استفاده از SlimReaderWriterLock، با اینکه از لحاظ زبون انگلیسی خوانایی دومی بهتره اما برای رعایت قاعده اشاره شده از همون نسخه اولی استفاده شده.
- سعی کنید تا اونجا که ممکنه از عباراتی جدید و با معنا که به روشنی تغییرات اعمال شده رو برسونه، به جای افزودن پسوند یا پیشوند استفاده کنین.
- اگه نام قدیمی تنها عبارتیه که مفهوم درست رو در بر داره (مثل نام یک استاندارد صنعتی)، و نشه از پسوند و پیشوندی مناسب برای نسخه جدید استفاده کرد، از یک پسوند عددی برای متمایز کردن نسخه جدید استفاده کنین. مثل IDynamicObject2
مثال:
// old API [Obsolete("This type is obsolete. Please use the new version of the same class, X509Certificate2.")] public class X509Certificate { ... } // new API public class X509Certificate2 { ... }
- نباید از پسوندهایی مثل Ex (که در نسخه های قدیمی کتابخونه های زبان ++C زیاد استفاده میشه) برای مشخص کردن نسخه های جدید استفاده کرد.
مثال:
[Obsolete("This type is obsolete. ...")] public class Car { ... } // new API public class CarEx { ... } // اشتباه public class CarNew { ... } // اشتباه
public class Car2 { ... } // درست public class Automobile { ... } // درست
- درصورت نیاز برای نامگذاری نسخه جدیدی از برنامه که مثلا بر روی محدوده وسیعتری از اعداد کار میکنه، میشه از پسوند عددی 64 استفاده کرد. اینکار تنها در صورتیکه یک نسخه قدیمی برای کار با اعداد با محدوده کوچکتر (مثلا اعداد 32 بیتی) وجود داشته باشه، درسته.
مثال:
public class Process { // old API public int PeakWorkingSet { get; set; } public int PagedMemorySize { get; set; } // ... // new API public long PeakWorkingSet64 { get; set; } public long PagedMemorySize64 { get; set; } }
کلمات مرکب
کلمات مرکب به کلماتی گفته میشه که بیش از یک کلمه با مفهوم مستقل در ساختش استفاده شده باشه. مثل Callback یا FileName. با تمام کلمات موجود در یک کلمه مرکب مثل یک کلمه مستقل رفتار نمیشه (یعنی حرف اولشون بزرگ نوشته بشه). میپرسید یعنی چی؟
کلمات مرکبی وجود دارند که به اونا closed-form گفته میشه. این نوع کلمات مرکب با اینکه از 2 یا چند کلمه دارای مفهوم مستقل تشکیل شدن، اما به خودی خود دارای مفهوم جداگانه و مستقلی هستند. برای تشخیص این کلمات میشه به فرهنگ لغت مراجعه کرد (و یا از نرمافزار Microsoft Word استفاده کرد) و دریافت که آیا کلمه مرکب موردنظر آیا مفهوم مستقلی برای خودش داره یا نه.
در جدول زیر مثالهایی از عبارات رایج و نحوه درست و نادرست استفاده از هریک نشان داده شده است:
همونطور که در جدول بالا آورده شده، در استفاده از قوانین عبارات مخفف دو مورد استثنا وجود داره: Id و Ok. این دو مورد به دلیل رواج و کاربرد عامیانه زیادشون به این شکل نوشته میشن. این دو کلمه باید همینجوری که در اینجا نشون داده شده استفاده بشن.
در جدول زیر خلاصه ای از قواعد نامگذاری اجزای مختلف یک برنامه آورده شده:
Pascal Casing | Camel Casing | Wrong |
---|---|---|
Callback | callback | CallBack |
BitFlag | bitFlag | Bitflag / bitflag |
Canceled | canceled | Cancelled |
DoNot | doNot | Donot / Don’t |
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. این دو مورد به دلیل رواج و کاربرد عامیانه زیادشون به این شکل نوشته میشن. این دو کلمه باید همینجوری که در اینجا نشون داده شده استفاده بشن.
نامگذاری اجزا
در جدول زیر خلاصه ای از قواعد نامگذاری اجزای مختلف یک برنامه آورده شده:
جزء | روش نامگذاری | مثال |
---|---|---|
Assembly | Pascal | Kara.Pos.App.exe |
Namespace | Pascal | namespace System.Security { ... } |
Type | Pascal | public class StreamReader { ... } |
Interface | Pascal | public interface IEnumerable { ... } |
Method | Pascal | public virtual string ToString(); |
Property | Pascal | public int Length { get; } |
Event | Pascal | public event EventHandler Exited; |
Field | Pascal |
public static readonly TimeSpan InfiniteTimeout;
public const Min = 0;
|
Enum value | Pascal |
public enum FileMode {
Append,
...
}
|
Parameter | Camel | public static int ToInt32(string value); |
.: در قسمتهای بعد نامگذاری درست اجزای مختلف یک برنامه شرح داده میشه.
قسمت اول: کلیات
قسمت دوم: جزئیات
قسمت سوم: نامگذاری اسمبلی
قسمت چهارم: نامگذاری فضای نام
قسمت پنجم: نامگذاری نوع
قسمت ششم: نامگذاری اعضای نوع
:.