|
Coding Style
This coding style is followed
by our programmers. It's mostly an internal document, but others may find it interesting.
Indentation
Use tabs, not spaces. If spaces
are used, it's very inconventient if later editing the code. Be
very precise about all indentations. The
only exception to proper indentation is when using a procedural language like
OpenGL from within C#. In that case, it's ok to indent the logical sections
even though it's not technically correct. Within lines of code, use spaces rather
than tabs.
To set VS to use tabs rather than spaces, go to Tools
| Options. Go
to the Text Editor category, C#, Tabs. Make sure that the Tab
groups has Keep Tabs checked instead of Insert Spaces. If you
are using C# Express Edition, and you don't see the "Tabs" group under
Text Editor, C#, look down a little bit and find the checkbox to show
all groups. The "Tabs" group will then be visible.
Other options to change in VS:
* Windows Forms Designer, General, Refactoring, EnableRefactoringOnRename: false. This is because if you make a copy of a form, and then rename it, it will also rename the original form.
* Text Editor, C#, Formatting, New Lines: Only else,catch, and finally should be on new lines.
* Text Editor, C#, Formatting, Spacing: Uncheck all boxes. At the bottom, select "ignore spaces around binary operators".
You may use this settings file if you would like to quickly set VS to the preferred settings. DefaultODSettings.zip Save it to your computer and extract. Then import the file inside from Tools, Options, Environment, Import and Export settings.
Patterns
See the Patterns page. ALWAYS USE PATTERNS IF AVAILABLE.
Language Enabling
It's absolutely essential that every single bit of displayed text be enabled
for language translation by getting routed through the Lan class before display.
For almost all static text on a form, this is handled by adding this line
Lan.F(this);
in the form constructor, usually right after InitializeComponent(). Lan.F handles
Form.Text (title), labels, buttons, groupboxes, checkboxes, and radiobuttons. But
it does not include textboxes with static text in them, menus, etc. Those
all need to be handled by manually calling Lan for each one. MessageBox's
are handled one of two ways. If the text is static, then you can use MsgBox,
which is a class we built to simplify things.
MsgBox.Show(this,"Hello World.");
But if the message is dynamic in any way, then it needs to be done without MsgBox,
more like this:
MessageBox.Show(Lan.g(this,"Your name is ")+patient.LName);
In the example above, only the first part of the phrase gets sent for translation.
It's very important to understand why it's done like this, and that you would
never send dynamic text to get translated. In the example above, there is also
a space between the translatable portion of the phrase and the dynamic text. This
is commonly handled by sending it off for translation, just like in the example. But
you probably don't want to send off too many spaces to translate, especially
if they are initial spaces. So it's also common to chain text together
without sending the spaces. Like this:
MessageBox.Show(Lan.g(this,"Your name is")+"
"+patient.LName);
Or like this
MessageBox.Show(String.Format(Lan.g(this,"Hi {0}, how are you?"), patient.FName);
Grids of type ODGrid must have their TranslationName property set so
that the grid title can be automatically translated. Each column in
a grid must also be manually enabled for translation. Use the Pattern when creating grids.
If there's text that is guaranteed to only be used by users of a single
language, such as e-claims or forms, then it's not necessary to worry about translation. Also,
the tables and columns in the database all use English naming. So
for some reporting purposes, they will not be able to see the words
in their language. This is currently a problem in letter merge
and the patient report, where the user must select fields in English.
The category of each phrase is either the name of the form (that's
why we pass in 'this'), or a manually assigned string. We try
to keep these categories very consistent and not change them over time. So
for historical reasons, many grids have TranslationNames starting with
Table...
You also have to make space on each form for translations, many of
which will be longer than the English version. All buttons are
special OD buttons. Never use a standard System button anywhere. The
OD buttons automatically expand to the right when the text is too long
to fit. If the button is right anchored, it will expand to the
left instead. You have to anticipate this and leave space for
every button to expand. You also have to make labels about twice
as large as needed so that they can hold longer text. The AutoSize
property of all labels, radiobuttons, and checkboxes must be set to
false. The text alignment must be carefully considered so that
it will still be aligned nicely if the text is longer.
Oracle Compatibility
No longer applies. If you are curious, you can see the old
Oracle compatibility rules. They are so convoluted that we were eventually forced to abandon them.
General
Blank lines: Never leave blank lines
within a method. Always leave one blank line between each method.
Braces: Opening braces should almost
always be on the same line as the method name. Closing braces
are usually on a line all by themselves. It would be very rare to omit
braces, even if there is only one line between the braces.
Get-Set: Within
properties, these can be real space wasters. This
is one situation where it's just fine to put it all on one line, like
this:
///<summary></summary>
public bool Autosize{
get{return autosize;}
set{autosize=value;}
}
Columns: It is sometimes useful
when using a courier font to create virtual columns for better readability
of repetitive code. We made heavy use of this technique in VS2003,
but VS2005 always reformatted when pasting, and eliminated our spaces.
So the use of columns fell into disuse. If columns are intentionally created, you must use spaces instead of tabs (except the leading tabs, of course).
Comments
Make good succinct comments. Most comments will be in the summary above
each method so that
it can be seen when using intellisense.
///<summary>Used when jumping here from another
module. Make sure not to pass in a value of 0.</summary>
In the past, we required it to be all on one line with no wasted whitespace. We now also allow the summary style that is auto-generated summary when typing a triple slash. It looks more like this:
/// <summary>
///
Used when jumping here from another
module. Make sure not to pass in a value of 0.
///
</summary>
If the comment is very
long, it will just wrap around, and that's fine. In table and table.field
comments, do not use any other XML tags other than summary because
they will not be picked up for documentation. It's ok to leave extra XML tags, but preferrable to remove them. Use correct capitalization,
spelling, and punctuation including a period on the end. A summary
is not required, but is sometimes very useful, especially for public
methods. Even
if no summary is needed, an empty summary is frequently included to help
visually identify where the method starts. Ordinary comments that
start with // within a method should be placed to minimize whitespace. A
short comment should go on the same line as the code, while a longer
comment should go on a separate line.
Very Long Methods
Try not to write a method that is too long, more than a few pages
tall. It becomes very difficult to keep track of where you are in
the method, and to quickly navigate to the section you are looking
for. If you end up with a very long method you have three options:
1. Break it down into a series of smaller methods, each performing
a single task of limited scope.
2. Use #region tags to surround sections that are not used very often.
These will start out collapsed, so they are useful for tucking away
rarely used code.
3. If it doesn't make sense to collapse a procedure with #regions,
and it's more orderly and logical to leave it all in one procedure,
then use comment lines to create subsections, like this:
//Paint the horizontal lines------------------------------------------------------------------------------------
Notice the heavy use of dashes. They should extend nearly all the
way to the right margin. There should be approximately 2 of
these subsections for every page of code. Of course, this will
vary.
Width and Wrap
Use as much horizontal width as possible. Most code over the last
few years has been written on a monitor with a width of 1920 pixels
and a toolbar docked on the right. This results in a workspace
of about 150 columns.
As much of this space as possible should be used. Comments
(except ///summaries) extending past this are usually manually broken
down into two lines. Method declarations with a long argument list can extend past 150 and automatically wrap. But anything other than summaries and method declarations should not extend past 150 columns because the resulting wrap
is distracting.
SQL
If an SQL statement within the C# code is more than a couple of lines,
it is common to start it with @" so that you can use multiple lines
without each line having to be surrouned with +"...". Regardless
of where SQL statements are found, there is a common style that needs
to be followed. There should be no blank lines, except
possibly between statements in a batch command (after a semicolon). All
tablenames are always lowercase so that they will function properly
on a default Linux installation. All column names should be mixed
case, just like they are in the documentation. All SQL functions
and keywords should be all caps. AND should be used instead of
&. There should be no indentation except in a CREATE TABLE
statement, where many of the lines get indented by two spaces. Each
clause of the statement (FROM, WHERE, etc) should start on its own
line even though this is not the most efficient use of whitespace.
|