Coding Standard Best Practices In C#

Datetime:2016-08-22 22:14:49          Topic: C#           Share

Now-a-days, performance and security are very crucial aspects of business prospective. If your product is not good in performance and not secure as well, then it is for sure that you are going to lose your reputation. Performance and security gives the positive impact towards,

  • Customer trust
  • High volume of business
  • Reputation etc.

Because, these two aspects are the keys to any software product. We can achieve these both in many ways. In this article, I am going to discuss the best practices of coding standards.

Let's say, we have a business requirement where every developer can write code in their own way to meet the business requirement. But, what makes the difference between you and them. As per my understanding, in the most cases, the developer thinks only from one angle which is the functional requirement to meet the business requirement, but remember, that's not enough. The real developer should think of multiple aspects before jumping into the implementation including both, functional and non-functional aspects. Here, I mentioned one aspect, the non-functional requirement. This aspect plays a vital role along with the functional requirement. Non-functional requirement includes the following:

  • Security
  • Performance
  • Scalability
  • Extendability
  • User friendliness etc

As a developer, we have to consider the above points along with functional requirement. Going forward, I will show you few of the best coding practices.

Coding standards help writing the easily understandable code and maintaining the consistency. I highly recommend to every software programmer or developer to follow the coding guidelines to help improving the readability of your source code and making software maintenance easier. I have listed few best coding practices which provide:

  • Great performance
  • Minimized complexity
  • Easier maintainability etc.

Given below are few of the best coding standard practices:

  • Assignments should not be made from within sub-expressions
  • Files should not have too many lines of code (maximum 1000 lines in a namespace)
  • Methods should not be too complex (Default value is 10).
  • Lines should not be too long (maximum length is 200)
  • Methods should not have too many parameters (Default value is 7 )
  • switch statements should not have too many case clauses (Default value is 30)
  • Control flow statements do, while, switch, if, foreach, for and try should not be nested too deeply (Default value is 3)
  • Expressions should not be too complex
  • Generic exceptions should not be ignored
  • Types should be named in Pascal case
  • switch case clauses should not have too many lines
  • Classes should not have only private constructors
  • async and await should not be used as identifiers
  • Boolean checks should not be inverted
  • Use break statements only with switch cases, don't use except switch cases.
  • TODO tags should be handled and add summary to every method in the file and Methods should not be empty
  • Enumerations Flags with zero-value members should be named None
  • Fields that are only assigned in the constructor must be readonly.
  • For Parameters with [DefaultParameterValue] attributes should also be marked with [Optional]
  • Empty default clauses in a switch should be removed
  1. Assignments should not be made from within sub-expressions

    Assignments within sub-expressions are hard to identify and make the code less readable. From the below table, we can observe that the preferable column contains == operator. It is also a common mistake to write "=" when "==" was meant to be written. Ideally, the expressions should not have side-effects.

    Example


    Reason: Assignments within sub-expressions are hard to identify and make the code less readable.
    Complexity: Major
  2. Files should not have too many lines

    Problem

    A source file containing too many lines of code with too many responsibilities causes difficulty to understand it and makes it harder to maintain.

    Solution

    It's advised to break down the responsibilities into smaller piece as methods which focus on well-defined tasks. Then, merge them at last in calling the method. Those smaller files will not only be easier to understand but easier to test also.
    Default value: 1000
    Complexity: Major
  3. Methods should not be too complex

    Problem
    Cyclomatic complexity of a function should not exceed a defined threshold. If that exceeds the limit, it causes:
    • Poor performance
    • Takes lot of time to execute the code which results performance impact
    • Difficult to maintain the code
    • Difficult to understand
    Solution
    We can use Task Parallel Library (TPL) to overcome such complex code execution.
    Default value: 10
    Complexity: Major
  4. Lines should not be too long

    Problem
    Having too long line of code that it scrolls horizontally, that makes it difficult to understand the complete code.
    Solution
    It's advised to split the lengthy line of code into some pieces which makes you easy to understand.
    Maximum length: 200
    Complexity: Minor
  5. Methods should not have too many parameters


    Problem
    A long parameters list creates a new structure to contain so many parameters.
    Solution
    Encapsulate multiple parameters into a single object.
    Ex: Instead of String fname, String lname, String address, String contact-number etc. into a object type, let's define them in a Person object containing all these fields and pass this object type as a method's input parameter.
    Default value: 7
    Complexity: Major
  6. SWITCH statements should not have too many CASE clauses

    Problem
    Usually, it is an attempt to map two sets of data. The real map structure will be more readable and maintainable and it should be used instead.
    Solution
    CASE clause content should be minimized by dividing into methods
    Maximum: 30
    Minimum: 3
    Mandatory: default case
    Complexity: Major
  7. Control flow statements IF, FOR, FOREACH, DO, WHILE SWITCH and TRY should not be nested too deeply
    Problem
    Nested flow statements or multiple conditions cause the complex code which is hard to understand. Also, multiple nested flow statements or multiple conditional statements cause the performance issues.
    Solution
    Replace control flow statement conditions into multiple methods (splitting condition based code into multiple methods), and call them in the targeted area.
    Maximum: 3
    Complexity: Major
  8. Expressions should not be too complex

    Problem
    The complexity of an expression is decided by the number of ||, && and condition? if True: if false operators it contains.
    Solution
    Breakdown multiple conditions into methods and call them in the targeted area. Sample code is, as shown below:
    Complexity: Major
  9. Generic exceptions should not be ignored


    If exception occurs in your code, then it's bad practice to simply ignore it. Instead, it is good to handle it properly and if you need, you log them.
    Solution:
    Complexity: Major
  10. Types should be named in Pascal case

    As per coding standards types (structure, class), name should be in Pascal case.
    Complexity: Minor
  11. SWITCH case clauses should not have too many lines

    Problem
    CASE clause contains too many statements causes difficult in readability.
    Solution
    The content of CASE clause should be moved in a dedicated method, as shown below:
    Complexity: Major
    Default threshold: 5
  12. Classes should not have only PRIVATE constructors

    Problem
    A class having only a private constructor cannot be instantiated and it seems to be worthless code.
    Solution
    Class should contain public constructors as well. Sample code is, as the following:
    Complexity: Major
  13. ASYNC and AWAIT should not be used as identifiers


    async and await are reserved keywords. So, we should not use them for variable names in order to avoid the confusion. It is advisable not to use these keywords.
    Complexity: major
  14. Boolean checks should not be inverted

    Problem
    Using inverted Boolean checks is costly and complex.
    Solution
    Instead, we should use the opposite Boolean comparison. Sample code is written below:
    Complexity: Minor
  15. Break statements should not be used except for switch cases
    Break statement makes it difficult to read the code. Most preferable, every loop should have a single termination point. And, it's advised to use close braces for every condition and also, use else part for every if condition.
    Complexity: Minor
  16. TODO tags should be handled and add summary to every method in the file and methods should not be empty
    If any method is empty or something you want to implement at later point of time, then in such cases, use TODO tags within the method; which states that something needs to be implemented in TODO tags area. Outside of the methods, write some summary by stating the actual use of the method. So that, at the later point when you forgot, if you filter with TODO keyword, it will give you the filtered result and there it will remind you to write something. And by seeing the summary part, everyone can easily understand the purpose of the method.
    Complexity: info

  17. Flags enumerations zero-value members should be named NONE
    We should use None flag for 0 value while defining ENUM and we should make a standard practice to maintain the consistency. Sample code is, as below:
    Complexity: Minor
  18. Fields that are only assigned in the constructor should be read-only


    By the name itself, we can say that only read-only members should be assigned in a class constructor. If member variables are not declared as read-only whereas we are assigning their values in a class constructor, then unnecessarily we are creating confusion. So, to avoid such confusion, if you want to assign field's value in a class constructor, then mark those fields as read-only, otherwise don't use fields inside class constructor which are not marked as read-only.
    Complexity: Minor

  19. Parameters with [DefaultParameterValue] attributes should also be marked with [Optional]
    If the caller provides the value for a parameter at any cost, then it's useless to set the default value for a parameter. The DefaultParameterValue must be used in combination with Optional because DefaultParameterValue is non-usable without optional.
    Complexity: Minor
  20. Empty DEFAULT clauses in a SWITCH should be removed


    If you use default clause in switch case, then it should contain an appropriate action. If not, then there is no meaning of using default clause.
    Complexity: Minor
    Fiends, if you use the above coding standards, then really you will get lot of benefits, as listed below:
    • Application performance will be improved.
    • Code maintainability will be easier.
    • Code re-usability can be acheived.
    • Easy to identify bugs.
    • Code complexity can be reduced, and many more...




About List