Code style makes things easier to read. It is about using clear names as well as white space.
Specific language construct preferences are also part of the deal.
This article lists code style preferences, that might be followed in some of the JJ
projects.
They mostly conform to Microsoft
standards described in these articles:
A tool like ReSharper
may help. Its settings can be fine-tuned to closely match the preferences. It then checks the code style and can auto-format for you.
Suggestion | Examples |
---|---|
Pascal case for properties, methods, class names and events |
MyProperty MyMethod |
Camel case for local variables and parameters | myLocalVariable myParameter |
Fields in camel case starting with underscore | _myField |
Constants in capitals with underscores between words | MY_CONSTANT |
Type arguments just the letter T or start with the letter T |
T TEntity TViewModel |
Interfaces start with I . |
IMyInterface |
Abbreviations not preferred | Ā |
Abbreviations of 2 letters with capitals. | ID |
Abbreviations of 3 letters or more in pascal case. | Mvc |
MVC partial View names in pascal case, starting with underscore |
_MyPartialView |
For long identifiers, underscores to separate āthe piecesā | Sine_OperatorCalculator_VarFrequency |
Reasons for naming conventions might be, just knowing what kind of system elements they are.
Method names commonly start with verbs, e.g. CreateOrder
.
For clarity generally donāt use verbs, for things other than methods.
Suggestions for verbs:
Verb | Description |
---|---|
Add |
List.Add(item) ListManager.Add(list, item) ( List can be the this argument or the first argument.) |
Assert |
Throws an Exception if input is invalid. |
Calculate |
Ā |
Clear |
Clears a list. |
Convert |
Ā |
ConvertTo |
Ā |
Create |
Returns a new object. |
Delete |
Ā |
Ensure |
Setting up a state, if not set up yet. If Ensure means to throw an Exception ,consider using the Assert verb instead. |
Execute |
Ā |
Generate |
Ā |
Get |
Ā |
Invoke |
Ā |
Parse |
Ā |
Process |
Ā |
Remove |
Ā |
Save |
Ā |
Set |
Ā |
Try |
Ā |
TryGet |
Returns null if an object does not exist. |
Validate |
Generating validation messages for user-input errors. |
In this architecture, class
names may end with a pattern name or a verb converted to a noun, e.g.:
Converter
Validator
Calculator
And they may start with a term out of the functional domain (like Order
, Product
or Price
):
OrderConverter
ProductValidator
PriceCalculator
More specialized classes
might get a prefix or suffix (like Optimized
or WithPriorityShipping
):
OptimizedPriceCalculator
OrderValidatorWithPriorityShipping
Abstract classes
might prefer a Base
suffix:
ProductValidatorBase
It might be quite important to see in code, whether something is a base
class. But exceptions may be made. For instance, entity classes
might leave out the Base
suffix for readability reasons.
You might keep variables names similar to the class
names and include the prefixes and suffixes, so it stays clear what they are.
Apart form pattern names, here are some other suggested ālast namesā for classes
:
Ā | Ā |
---|---|
Resolver |
A class that does lookups requiring complex keys or different ways of looking up depending on the situation, fuzzy lookups, etc. |
Dispatcher |
A class calls different methods or sends messages to different endpoints based on the input it receives. |
Invoker |
Something that invokes a method, possibly based on input or specific conditions. |
Provider |
A class that provides something. It can be useful to have a separate class that provides something if there are many conditions or contextual dependencies involved in retrieving something. A Provider might also be used when something is retrieved conditionally or if retrieval is postponed until later. |
Asserter |
A class meant to throw Exceptions under certain conditions. |
Ā | Any verb might become a class name, by turning it into a verby noun, e.g. Convert => Converter . |
When naming boolean variables, consider using prefixes and suffixes:
Prefix / Suffix | Example | Comment |
---|---|---|
Is... |
IsDeleted |
Might be the most common prefix. |
Must... |
MustDelete |
Ā |
Can... |
CanDelete |
Might indicate what user can do. |
Has... |
HasRecords |
Ā |
Are... |
AreEqual |
For plural things. |
Not... |
NotNull |
A nice prefix, but perhaps be careful with negative names. See Double Negatives. |
Include... |
IncludeHidden |
Verb are usually for methods, but these may make sense for booleans. |
Exclude... |
ExcludeSpecialChars |
ā |
...Exists |
FileExists |
Ā |
Always... |
Ā | Ā |
Never... |
Ā | Ā |
Only... |
Ā | Ā |
A prefix might not always be put at the beginning. If it looks better, you might put it somewhere else:
LinesAreCopied
instead of:
AreLinesCopied
Some boolean names are so common, that they might not need a prefix:
Visible
Enabled
Plural words are preferred for collections:
Products
Orders
Variable names for amounts of elements might be named:
Count
So perhaps avoid plural words to denote a count or describe things other than collections.
This architecture tends to end enum
types with the Enum
suffix e.g. OrderStatusEnum
.
Another alternative might be the suffix Mode
, e.g. ConnectionMode
. But Enum
expresses it more explicitly and that might be quite important.
A DateTime
property might be suffixed with Utc
or Local
:
StartDateLocal OrderDateTimeUtc
An alternative suffix for DateTimes
could be When
:
ModifiedWhen OrderedWhen
But that might not look so nice, when you add the Local
and Utc
suffixes again:
ModifiedWhenUtc OrderedWhenLocal
For number sequences the following names might be used:
ListIndex
IndexNumber
SortOrder
Rank
Perhaps donāt use the word Index
on its own, because thatās an SQL
keyword.
Variable names that describe parts of file paths might easily become ambiguous. Here are some suggestions to make them clearer:
Name | Value |
---|---|
FileName |
"MyFile.txt" |
FilePath |
"C:\MyFolder\MyFile.txt" |
FolderPath |
"C:\MyFolder" |
SubFolder |
"MyFolder" |
RelativeFolderPath /SubFolder /SubFolderPath |
"MyFolder\MyFolder2" |
RelativeFilePath |
"MyFolder\MyFile.txt" |
FileNameWithoutExtension |
"MyFile" |
FileExtension |
".txt" |
AbsoluteFilePath |
"C:\MyFolder\MyFile.txt" |
AbsoluteFolderPath |
"C:\MyFolder" |
AbsoluteFileName |
DOES NOT EXIST |
FileNamePattern /FilePathPattern / etc.wildcards like * and ? |
*.xml C:\temp\BLA_???.csv |
FileNameFormat /FilePathFormat / etc.placeholders like {0} and {0:dd-MM-yyyy} |
order-{0}.txt orders-{0:dd-MM-yyyy}\*.* |
Example | Description |
---|---|
source... dest... |
In code that converts one structure to the other, it might be clear to use the prefixes source and dest . You might use them consistently in the variable names, to keep track of where data comes from and where it goes. |
existing... |
Denoting that something already existed (in the database). |
new... |
Denoting that the object was just newly created. |
original... |
May denote that this is an original value that was (temporarily) replaced. |
...WithRelatedEntities ...WithRelatedObjects |
Indicating that it does more than handling a single object. Related objects linked to it are also included. |
Versatile... |
Versatile in that it might handle a multitude of types or situations. |
...With... |
When making a specialized class that works well for a specific situation, you might use the word With in the class name e.g.:CostCalculator CostWithTaxCalculator |
...Polymorphic |
Handling a variety of (derived) types , which may need different ways of processing. |
...IfNeeded |
A suffix alternative for Conditional that might be easier to read. |
...Unsafe |
When it lacks e.g. thread-safety, executes unmanaged code, or lacks some other checks. |
...Recursive |
When the process is recursive. Meaning: A method might call itself directly or indirectly. Or when processing a tree, the same type of data might be there deeper down the tree. |
To... |
For conversion from one thing to another. Sometimes the this is the source of the conversion, for example:array.ToHashSet() Sometimes a parameter is the source, for instance: MyConverter.ToHashSet(object[] array) But Convert or ConvertTo might be used as an alternative in that case:MyConverter.ConvertToHashSet(object[] array) |
From... |
For conversion from one thing to another. A lot like To... but executed on the dest object:dest.FromSource(source) The To... prefix might be more common, and possibly more readable. |
Event
names and delegate
names representing what just happened might be written in the past tense. For example:
Deleted
TransactionCompleted
Event
names and delegate
names representing what is about to happen might be written in the following form:
Deleting
TransactionCompleting
User-initiated events
might not follow that pattern:
Click
DoubleClick
KeyPress
MouseUp
Delegate
names might also have the suffix Callback
or Delegate
:
ProgressInfoCallback
AddItemDelegate
Sometimes the word On
may be used:
OnSelectedIndexChanged
OnClick
Or the prefix Handle
:
HandleMouseDown
Or the suffix Requested
, if your event
looks like a method name.
RemoveRequested
The names mentioned above can be used for events
, but also for methods that raise or handle the event. Some prefixes for these methods include: On
, Handle
, Fire
, and Do
.
Perhaps avoid using event
names with two event
-indicating words, like OnDragging
or OnMouseUp
. Instead, you can use shorter names like Dragging
or MouseUp
.
Test class
names end with the word Tests
.
Recommended | Less Preferred |
---|---|
|
|
Reason: Just convention.
Prefer to start test
method names with Test_
and use underscores freely.
Recommended | Less Preferred |
---|---|
|
|
Reason:
When test names mean to be descriptive, they might become long. Underscores can separate the āpiecesā and make it more readable.
Avoid prefixes such as strName
.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Otherwise it might be easily overlooked, that there is another property.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Just a preference. Itās up to you. But when youāre not familiar with it, variables might be missed while searching the code. This syntax would have to be taken into account.
Recommended | Less Preferred |
---|---|
|
|
Reason: Just a bit more tidy.
Putting enters inside methods between the āpieces that do somethingā.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Visible separation between steps inside methods.
Recommended | Less Preferred |
---|---|
|
|
Reason: May look odd if youāre not used to it.
Recommended | Less Preferred |
---|---|
|
|
Reason: A bit tidier and the bits better separated.
Recommended | Less Preferred |
---|---|
|
|
Reason: More tidy.
Recommended | Less Preferred |
---|---|
|
|
Reason: So they stand out.
Recommended | Less Preferred |
---|---|
|
|
Reason:
It might have been on a single line for readability, so perhaps we want to keep it like that.
Perhaps start out with Visual Studio's
auto-formatting enabled and set to its defaults.
Reason: Less surprising to the next developer.
Apply indentation properly.
Recommended | Less Preferred |
---|---|
|
|
Reason: More readable.
Recommended | Less Preferred |
---|---|
|
|
Reason: Less clutter.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Without braces, only the next line is looped or executed conditionally. The line after that would not be part of the loop or if
, which might not be very obvious and might lead to error.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Tabular form might be undone by auto-formatting. It may look nice, but maybe get your eyes used to non-tabular form instead.
Aligning the elements:
Recommended | Less Preferred |
---|---|
|
|
Reason: readability.
Keeping members private is preferred.
private void Bla()
{
...
}
Reason:
Other code might become dependent on publicly accessible things. Managing dependencies like that is quite a thing in software development.
Keep types internal
is preferred.
internal class MyClass
{
...
}
Reason:
Managing dependency between parts is quite a concern in software development. We might protect things from forming too many connections, by using access modifying keywords, like private
and internal
.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Avoiding confusion about the defaults.
Exception:
Interface
members have no access modifiers.
Prefer not to use public
fields. Use either private
fields or use properties.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Some may say using public
fields makes the interface
less stable. Fields may look similar to properties
from the outside. However, frameworks may expect properties
, not fields. This makes it harder to use fields in reusable functions and may cause compatibility issues.
The use of internal
members is not recommended within internal
classes.
Recommended | Less Preferred |
---|---|
|
|
Reason:
If the class
is internal
, the members are automatically internal
too. When making the class
public
, more access modifiers may need to change, creating an opportunity for error.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Interface types
may give you less to refactor when changing a type
. Less dependency on specific implementation, allowing for an easier switch to another class
.
Putting nested classes
at the top of the parent class'
code.
Recommended | Less Preferred |
---|---|
|
|
Reason:
It may not be obvious there are nested classes
, unless they are put at the top.
Give each class
(or interface
or enum
) its own file.
Reason:
One might be surprised to find types
hidden away behind a single file name. It may harm the overview of the different pieces of the code.
Exceptions:
This guideline does not apply to nested classes
. Also, a single class
can be split across multiple files if they are partial classes
. This guideline may also be ignored if there are a large number of smaller classes
.
It may not be very handy to have many folders that only contain one or few classes
. Consider moving those classes
to other folders or putting them together in a single Helpers
folder.
You might put comment for members in <summary>
tags.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Your comment might be valuable from the outside for others to see. Your summary
would show up when hovering over a member.
Recommended | Less Preferred |
---|---|
|
|
Reason:
English is basically the main language in IT. A broader reach of people might be able to read your comments.
Avoid comments that do not add information.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Less visual clutter. Reading it might not be worth the time.
Avoid leaving around unused or outcommented code. If necessary, you can move it to an Archive
folder.
Reason:
Unused code might clutter your vision. It may also give the impression, that it was outcommented in error.
Recommended | Less Preferred |
---|---|
|
|
Reason: More readable.
Recommended | Less Preferred |
---|---|
|
|
Reason:
The default switch
case is often the ālast resortā case, so it may make sense to put it last.
Avoid long code lines for readability.
The use of var
is not preferred here.
Recommended | Less Preferred |
---|---|
|
|
Reason:
A variable type
might be relevant to see.
Exceptions:
But in some cases, var
may be preferred after all. For example, when the type
is obvious, or it makes the code more readable.
Recommended | Not Preferred |
---|---|
|
|
Recommended | Less Preferred |
---|---|
|
|
Recommended | Less Preferred |
---|---|
|
|
Recommended | Less Preferred |
---|---|
|
|
Recommended | Less Preferred |
---|---|
|
|
Prefer not to use type
arguments that can be inferred.
Recommended | Less Preferred |
---|---|
|
|
Reason: Less visual clutter.
When a FileStream
is opened it is appreciated to specify the aspects FileMode
, FileAccess
and FileShare
explicitly. Try to use the most logical and most limiting values tailored to the situation.
Reason:
Otherwise these aspects may have surprising defaults.
When expressing a range in an if
statement, showing the actual limits of the range may look better. Also, mentioning the start of the range first and the end of the range second might make it more readable.
Recommended | Less Preferred |
---|---|
|
|
Reason: Readability. More obvious what the range limits are.
Passing infrastructure-related parameters to constructors or methods, the parameters might be listed in a certain order:
For instance:
class MyPresenter
{
public MyPresenter(
MyEntity entity,
IMyRepository repository,
IAuthenticator authenticator,
string cultureName,
int pageSize)
{
...
}
}
Reason:
Just to have some kind of standard for consistency.
Full namespaces
in code might not be preferred:
Less Preferred |
---|
|
Reason:
Long and wordy code can make it harder to read.
Half a namespace
might not be preferred either:
Less Preferred |
---|
|
Reason:
If youād want to rename the namespace
, it might create more manual work. The shortened namespace
could be overlooked when searching through the code.
To prevent using a namespace
in the code line, you might give a class
a more unique name:
|
To disambiguate a type
name, you might use a type
alias instead. This can prevent long namespaces
in the code lines:
Recommended |
---|
|
Reason:
Long, visually cluttered code lines might be harder to read.
To improve readability, try giving the members in your code a logical order, instead of putting them all in an arbitrary order. Suggestions for organizing the members in your code:
Ā | Ā |
---|---|
Chronological | When one method delegates to another in a particular order, you might order the methods chronologically. |
By functional aspect | When your code has distinct functionalities, you might keep members with similar functions together and add a comment line above the group. |
By technical aspect | You may choose to keep your fields together, your properties together, your methods together. Another option might be to group them by access modifier (e.g. public or private ). |
By layer | When you can identify layers in your class , you might first list the members of layer 1, then the members of layer 2, etc. |
You might prefer to make it chronological if possible. Otherwise, order it by functional aspect. But there are no rights and wrongs here. Whatever seems most appropriate for your code.
Prefer handling both null
and ""
the same way.
Reason: No surprises when using either null
or ""
.
Prefer string.IsNullOrEmpty
to check if a string
is filled in.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Reference equality (==
) may fail in exceptional cases even when strings
are equal.
Prefer string.Equals
to check the equality of string
.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Reference equality (==
) may fail in exceptional cases even if string
values are equal.
For Nullable
types:
Recommended | Less Preferred |
---|---|
|
|
Reason:
The less preferred one may look nice, but the behavior of the code would change considerably, if the variable type is changed to object
.
Prefer ToArray
over ToList
.
Recommended | Less Preferred |
---|---|
|
|
Reason: More performance.
Downside: The Add
method may throw an Exception
for an Array
.
Prefer using CLR
- compliant data types. Some arenāt CLR
- compliant.
Recommended | Less Preferred |
---|---|
|
|
Reason:
For compatibility with more variations of .NET
.
Avoid getting information by catching an Exception
. Prefer getting your information without using Exception
handling.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Exception
handling is more performance intensive than might be expected. When no Exception
goes off, Exception
handling might perform well, but when an Exception
does go off, quite a few things happen, like gathering StackTrace
information.
Entity equality checks might be better done by ID
than by reference.
Recommended | Less Preferred |
---|---|
|
|
Reason:
Code that compares identities may be less likely to break, because persistence frameworks donāt always ensure instance integrity.
(Also consider doing null checks on the entities if needed.)
Prefer not to use compiler directives, unless the code cannot run on a platform without excluding that piece of code. Otherwise a boolean variable might be preferred, a configuration setting or different concrete implementations of classes
.
Recommended | Less Preferred |
---|---|
|
|
Reason:
When using these compiling directives, a compilation might succeed, without all the code being actually compilable.
Prefer using the new
keyword instead of Activator.CreateInstance
. Using genericsā new
constraint might avoid some of the Activator.CreateInstance
calls.
Recommended | Less Preferred |
---|---|
|
|
A call to Activator.CreateInstance
might be the last choice for instantiating an object
.
Reason:
New
statements are strongly typed, less likely to break and possibly faster.