07-Mar-22
Coding Guidelines for .Net Microservices
1.0
Coding standard to be followed.
Class Names
Do use PascalCasing for class names and method names.
1.public class ClientActivity
2.{
3. public void ClearStatistics()
4. {
5. //...
6. }
7. public void CalculateStatistics()
8. {
9. //...
10. }
11. }
Variable Names
Do use camelCasing for local variables and method arguments.
1.public class UserLog
2.{
3. public void Add(LogEvent logEvent)
4. {
5. int itemCount = logEvent.Items.Count;
6. // ...
7. }
8.}
Identifiers
Do not use Hungarian notation or any other type identification in identifiers
1.// Correct
2.int counter;
3.string name;
4.
5.// Avoid
6.int iCounter;
7.string strName;
Why: consistent with the Microsoft's .NET Framework. In addition, the Visual Studio IDE makes it very easy to
determine the type of a variable (via tooltips). It is best to avoid type indicators in identifiers.
Constants
Do not use Screaming Caps for constants or read only variables
1.// Correct
2.public static const string ShippingType = "DropShip";
3.
4.// Avoid
5.public static const string SHIPPINGTYPE = "DropShip";
Abbreviations
Avoid Abbreviations.
Exceptions: abbreviations commonly used as names, such as Id, Xml, Ftp, Uri
1.// Correct
2.UserGroup userGroup;
3.Assignment employeeAssignment;
4.
5.// Avoid
6.UserGroup usrGrp;
7.Assignment empAssignment;
8.
9.// Exceptions
10. CustomerId customerId;
11. XmlDocument xmlDocument;
12. FtpHelper ftpHelper;
13. UriPart uriPart;
Why: consistent with the Microsoft's .NET Framework. It prevents inconsistent abbreviations by
different developers.
Abbreviation Casing
#
Do not use PascalCasing for abbreviations 3 characters or more (2 chars are both uppercase)
1.HtmlHelper htmlHelper;
2.FtpTransfer ftpTransfer;
3.UIControl uiControl;
Why: consistent with the Microsoft's .NET Framework. Caps would grap visually too much
attention.
No Underscores
Do not use Underscores in identifiers.
Exception: you can prefix private static variables with an underscore.
1.// Correct
2.public DateTime clientAppointment;
3.public TimeSpan timeLeft;
4.
5.// Avoid
6.public DateTime client_Appointment;
7.public TimeSpan time_Left;
8.
9.// Exception
10. private DateTime _registrationDate;
Why: consistent with the Microsoft's .NET Framework. It makes code more natural to read
(without 'slur'). Also avoids underline stress, i.e. inability to see underline
Type Names
Do use predefined type names instead of system type names like Int16, Single, UInt64, etc
1.// Correct
2.string firstName;
3.int lastIndex;
4.bool isSaved;
5.
6.// Avoid
7.String firstName;
8.Int32 lastIndex;
9.Boolean isSaved;
Why: consistent with the Microsoft's .NET Framework. It makes code more natural to read.
Implicit Types
douse implicit type var for local variable declarations.
Exception: primitive types (int, string, double, etc) use predefined names.
1.var stream = File.Create(path);
2.var customers = new Dictionary();
3.
4.// Exceptions
5.int index = 100;
6.string timeSheet;
7.bool isCompleted;
Why: removes clutter, particularly with complex generic types. Type is easily detected with
Visual Studio tooltips.
Noun Class Names
Do use noun or noun phrases to name a class.
1.public class Employee
2.{
3.}
4.public class BusinessLocation
5.{
6.}
7.public class DocumentCollection
8.{
9.}
Why: consistent with the Microsoft's .NET Framework. Makes classes easy to remember.
Interfaces
Do prefix interfaces with the letter I. Interface names are noun (phrases) or adjectives.
1.public interface IShape
2.{
3.}
4.public interface IShapeCollection
5.{
6.}
7.public interface IGroupable
8.{
9.}
Why: consistent with the Microsoft's .NET Framework
File Names
Do name source files according to their main classes. Exception: file names with partial classes
reflect their source or purpose, e.g. designer, generated, etc.
1.// Located in Task.cs
2.public partial class Task
3.{
4. //...
5.}
1.// Located in Task.generated.cs
2.public partial class Task
3.{
4. //...
5.}
Why: consistent with the Microsoft practices. Files are alphabetically sorted and partial classes
remain adjacent.
Namespaces
Do organize namespaces with a clearly defined structure
1.// Examples
2.namespace Company.Product.Module.SubModule
3.namespace Product.Module.Component
4.namespace Product.Layer.Module.Group
Why: consistent with the Microsoft's .NET Framework. Maintains good organization of your
code base.
Curly Brackets
Do vertically align curly brackets.
1.// Correct
2.class Program
3.{
4. static void Main(string[] args)
5. {
6. }
7.}
Member Variables
Declare all member variables at the top of a class, with static variables at the very top.
1.// Correct
2.public class Account
3.{
4. public static string BankName;
5. public static decimal Reserves;
6.
7. public string Number {get; set;}
8. public DateTime DateOpened {get; set;}
9. public DateTime DateClosed {get; set;}
10. public decimal Balance {get; set;}
11.
12. // Constructor
13. public Account()
14. {
15. // ...
16. }
17. }
Enums
Use singular names for enums. Exception: bit field enums.
1.// Correct
2.public enum Color
3.{
4. Red,
5. Green,
6. Blue,
7. Yellow,
8. Magenta,
9. Cyan
10. }
11.
12. // Exception
13. [Flags]
14. public enum Dockings
15. {
16. None = 0,
17. Top = 1,
18. Right = 2,
19. Bottom = 4,
20. Left = 8
21. }
Why: consistent with the Microsoft's .NET Framework and makes the code more natural to
read. Plural flags because enum can hold multiple values (using bitwise 'OR')
Enum Types
DO not explicitly specify a type of an enum or values of enums (except bit fields)
1.// Don't
2.public enum Direction : long
3.{
4. North = 1,
5. East = 2,
6. South = 3,
7. West = 4
8.}
9.
Enum Suffix
Do not suffix enum names with Enum
1.// Don't
2.public enum CoinEnum
3.{
4. Penny,
5. Nickel,
6. Dime,
7. Quarter,
8. Dollar
9.}
10.
11. // Correct
12. public enum Coin
13. {
14. Penny,
15. Nickel,
16. Dime,
17. Quarter,
18. Dollar
19. }
Naming Conventions and Standards
Use Pascal casing for Class names.
Example
1. public class BusinessCase
2. {
3. //.........
4. }
Use Pascal casing for Method names.
Example
1. void AutoComplete(string name)
2. {
3. // ......
4. }
Use Camel casing for variables and method parameters.
Example
1. int totalCount = 0;
2. void AutoComplete(string name)
3. {
4. string fullMessage = "Hello " + name;
5. }
Use Meaningful, descriptive words to name variables. Do not use abbreviations.
Example
Good:
1. string address;
2. int salary;
Bad:
3. string nam;
4. string addr;
5. int sal;
Do not use single character variable names like i, n, s etc. Use names like index, temp
One exception, in this case, would be variables used for iterations in loops.
Example
1. for (int i = 0; i < count; i++)
2. {
3. //...........
4. }
Do not use underscores (_) for local variable names.
Prefix boolean variables, properties, and methods with "is" or similar prefixes.
1. Ex: private bool _isFinished
Use Pascal Case for file names.
Indentation and Spacing
Use TAB for indentation. Do not use SPACES. Define the Tab size as 4.
Comments should be in the same level as the code (use the same level of indentation).
Example
Good
1. // Format a message and display
2. string fullMessage = "Hello my name is " + name;
3. DateTime currentTime = DateTime.Now;
4. string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
5. MessageBox.Show( message );
Bad
1. // Format a message and display
2. string fullMessage = " Hello my name is " + name;
3. DateTime currentTime = DateTime.Now;
4. string message = fullMessage + ", the time is : " + currentTime.ToShortTimeString();
5. MessageBox.Show ( message );
Curly braces ( {} ) should be in the same level as the code outside the braces.
Use one blank line to separate logical groups of code.
Example
Good
1. bool ShowMessage(string name) {
2. string fullName = "Hello " + name;
3. DateTime currentTime = DateTime.Now;
4. string message = fullName + ", the time is : " + currentTime.ToShortTimeString();
5. MessageBox.Show(message);
6. if (...) {
7. // Write your code here
8. // ...
9. return false;
10. }
11. return true;
12. }
Bad
1. bool ShowMessage(string name) {
2. string fullName = "Hello " + name;
3. DateTime currentTime = DateTime.Now;
4. string message = fullName + ", the time is : " + currentTime.ToShortTimeString();
5. MessageBox.Show(message);
6. if (...) {
7. // Write your code here
8. // ...
9. return false;
10. }
11. return true;
There should be one and only one single blank line between each method inside the class.
The curly braces should be on a separate line and not in the same line as if, for, etc.
Example
Good
1. if ( ... )
2. {
3. // write your code here
4. }
Bad
1. if ( ... ) {
2. // Write your code here }
Use a single space before and after each operator and brackets.
Example
Good
1. if(showResult)
2. {
3. for ( int i = 0; i < 10; i++ )
4. {
5. //
6. }
7. }
Bad
1. if(showResult==true)
2. {
3. for(int i= 0;i<10;i++)
4. {
5. //
6. }
7. }
Method name should clarify the meaning. Do not use misleading names. If the method name is clear
then there is no need of documentation.
Example
Good
1. void SaveStudentDetails (string studentDetails )
2. {
3. // Save the student details.
4. }
Bad
1. // This method will save the student details.
2. void SaveDetails (string student )
3. {
4. // Save the student details.
5. }
A method should do only one job at a time. Do not use it for more than one job.
Example
Good
1. //Save student details
2. SaveStudentDetails();
3. //Send email to user that student details is added successfully.
4. SendEmail();
Bad
1. //Save student details
2. Public void SaveStudentDetails()
3. {
4. // First task
5. //Save student details
6. //Second task
7. // Send emails
8. }
Make sure string comparisons convert string to uppercase or lowercase for comparison.
Example
Good
1. If(UserName.ToLower()=="tom")
2. {
3. // write yor logic here
4. }
Bad
1. If(UseName=="TOm")
2. {
3. //
4. }
Comments
Do not write comments for every line of code and every variable declared.
Use // or /// for comments. Avoid using /* … */
Write comments where is it required. But they should be good readable and limited. If all variables and
method names are perfectly meaningful, then there is no need of many comments.
If you initialize a numeric variable to a special number other than 0, -1 etc, document the reason for
choosing that value.
Make sure to perform spelling check on comments and make sure proper grammar and punctuation is
used.
Enum
Always use a singular noun for defining enum.
Example
1. Enum Mailtype
2. {
3. Subject,
4. Body,
5. PlaneText
6. }
Interface
Always use the letter "I" as a prefix with the name of an interface. After letter I, use PascalCase.
Example
1. public interface IMultiply
2. {
3. int Multiplication();
4. }
High-level standard
1. The Single Responsibility Principle
Just like with code, where a class should have only a single reason to change, microservices should be
modeled in a similar fashion. Building bloated services which are subject to change for more than one
business context is a bad practice.
2. Have a separate data store(s) for your microservice
It defeats the purpose of having microservices if you are using a monolithic database that all your
microservices share. Any change or downtime to that database would then impact all the microservices
that use the database. Choose the right database for your microservice needs, customize the
infrastructure and storage to the data that it maintains, and let it be exclusive to your microservice.
Ideally, any other microservice that needs access to that data would only access it through the APIs that
the microservice with write access has exposed.
3. Use asynchronous communication to achieve loose coupling
To avoid building a mesh of tightly coupled components, consider using asynchronous communication
between microservices.
a. Make calls to your dependencies asynchronously, example below.
b. An even better option is to use events for communicating between microservices. Your microservice
would publish an event to a message bus either indicating a state change or a failure and whichever
microservice is interested in that event, would pick it up and process it.
4. Proxy your microservice requests through an API Gateway
Instead of every microservice in the system performing the functions of API authentication, request /
response logging, and throttling, having an API gateway doing these for you upfront will add a lot of
value. Clients calling your microservices will connect to the API Gateway instead of directly calling your
service. This way you will avoid making all those additional calls from your microservice and the internal
URLs of your service would be hidden, giving you the flexibility to redirect the traffic from the API
Gateway to a newer version of your service. This is even more necessary when a third party is accessing
your service, as you can throttle the incoming traffic and reject unauthorized requests from the API
gateway before they reach your microservice. You can also choose to have a separate API gateway that
accepts traffic from external networks.
5. Ensure your API changes are backwards compatible
You can safely introduce changes to your API and release them fast as long as they don’t break existing
callers. One possible option is to notify your callers , have them provide a sign off for your changes by
doing integration testing. However, this is expensive, as all the dependencies need to line up in an
environment and it will slow you down with a lot of coordination . A better option is to adopt contract
testing for your APIs. The consumers of your APIs provide contracts on their expected response from
your API. You as a provider would integrate those contract tests as part of your builds and these will
safeguard against breaking changes. The consumer can test against the stubs that you publish as part of
the consumer builds. This way you can go to production faster with independently testing your contract
changes.
6. Version your microservices for breaking changes
It's not always possible to make backwards compatible changes. When you are making a breaking
change, expose a new version of your endpoint while continuing to support older versions. Consumers
can choose to use the new version at their convenience. However, having too many versions of your API
can create a nightmare for those maintaining the code. Hence, have a disciplined approach to deprecate
older versions by working with your clients or internally rerouting the traffic to the newer versions.
7. Have dedicated infrastructure hosting your microservice
You can have the best designed microservice meeting all the checks, but with a bad design of the
hosting platform it would still behave poorly. Isolate your microservice infrastructure from other
components to get fault isolation and best performance. It is also important to isolate the infrastructure
of the components that your microservice depends on.
8. Create Organizational Efficiencies
While microservices give you the freedom to develop and release independently, certain standards need
to be followed for cross cutting concerns so that every team doesn’t spend time creating unique
solutions for these. This is very important in a distributed architecture such as microservices, where you
need to be able to connect all the pieces of the puzzle to see a holistic picture. Hence, enterprise
solutions are necessary for API security, log aggregation, monitoring, API documentation, secrets
management, config management, distributed tracing, etc.
Review Code
This is the major point of code review. Inside it, review the code to make sure that the code follows the
coding standard.
Naming Conventions
1. Pascal Case
2. Camel Case
Pascal Case
The first characters of all words are Upper Case and other characters are lower case.
Example
CaseHistory
Camel Case
The first letter is in lowercase and the first letter of every subsequent concatenated word is in caps.
OR
The first character of all words, except the first word, is Upper Case and other characters are lower case.
Example
businessCase