Class Convention Definition:
A collection of conventions for Class file naming and Class location along with the use of Abstract, Static and Instantiated Class types with Static and Instance Constructors
Class Convention Justification:
Class standards are the most important of all the code standards. The highest cost of maintenance of an Enterprise application is in Class maintenance over the life cycle of an assembly.
Good Class management, through enforced Class standards, will reduce the cost of Change Requests and lower the cost of the ramp up time for the understanding of the intent of a C# Type by newly assigned developers.
Class Convention Standards:
Classes can manage STATE , as with Data Transfer Object (DTO) Classes, or the can manage BEHAVIOR as with action Class Methods.
There is Only One Public Class per File…
…The Class and the File Names are the Same
A Class must comply with the Single Responsibility Principle. This is the most important principle for Classes. Compliance with this principle will support compliance with other principles such as Open / Closed Principle.
“A Class Should have One and Only One Reason to Change”
2- One Static Constructor
3- Many Instance Constructors – Default Parameterless and Parametized
4- Public and Private Methods
5- Many Nested Private Classes
All of these Software Entities must exist for a Single Responsibility for servicing the calling module.
All internal elements must be related to that “Single Purpose”. Any dependency that does not have a “One and Only One” relationship with the Class purpose should be an external Software Dependency Entity.
Classes that are holding State – A Data Properties Class acting as a Data Transfer Object, a DTO:
A Class that is managing State cannot have any action Methods other than Property Methods used for validation and default instantiation of initial Property values. All Property setup actions must be in a Constructor.
No External action Methods are allowed in a State Class object. A DTO is a “Thing”, a Noun, not an action behavior object. It manages Data Elements only.
Class Types and Use Standards:
Use this Class type when more than one instances of this type may be required.
This class can be managed as instances within an Inversion of Control (IOC) container such as Microsoft’s Unity.
If you need common behaviour and Properties for all child inherited Classes use an Abstract Class as a Base Class. If you only have contract signatures and no implementation methods this Class acts like an Interface but is actually faster at runtime than a standard Interface.
If you can afford to use your only inheritance in C# and the derived Class has an “Is A” relationship to the Contract signatures use an Abstract Class as your interface.
If the implementation of a class needs to be protected from external changes and will never require an “Is A” relationship type, mark it closed for inheritance with the sealed key word.
A Singleton is a type that can only be created once. Static Classes are used for Public Helper Method containers and any Type that will only have one possible implementation.
Static Classes cannot be mocked in Unit or Integration testing as mocking frameworks use Class Types as Base Classes for override inheritance to create the mocked object.
Use this Class to prevent a violation of the DRY Principle, “Do Not Repeat Yourself”. Generic Classes can define the required Types through inheritance at design time..
If you need to restrict the types available to be used at run-time declare the Base Class of the inheritance hierarchy at design time in the Class signature.
This type of Class is generally used by auto-generated code processes within the .NET environment and by 3rd party applications.
The General Rule is not to Extend Classes with the Partial Keyword.
Class Structure Standards:
Unused declarations lead to misunderstanding of the dependencies being consumed by the Class Type. Remove all unused Using Statements to help better define the intent of the underlying Class.
Use “Aliases” to eliminate possible type ambiguity between like named namespaces.
The namespace name follows the naming convention for Namespace defined in the Namespace Coding Standard.
The Class file will always be in a folder with the same name as the last element in the Namespace designation. This will guarantee that the Class Namespace and Project assembly structure are synchronized for better understanding of the intent of the assembly
It will always define an Access Modifier as the first item in the signature.
The Default Class Access Modifier of Internal will Never be Implicit but always Explicit
The default Access Modifiers for all Class members is Private and that can be implicit except for Class Constructors, Methods and Properties which will always be always explicit.
The use of the Auto-property feature of C# will be used when default implementations of “get: set:” is consumed. All Public Properties, in Pascal notation, will be listed first then followed by Private properties using a modified Camel notation with an underscore as a prefix character.
Data members, declarations as Class fields is strongly discourage as it removes the Power of a Property Method from the declaration and is not considered a Best Practice
No Property declaration will be allowed below the Constructors as all Class level Properties dependencies should be easily identified at the top of a Class code block.
You can use a Static Constructor to initiate base class properties based on runtime conditionals. You can use a Static Constructor to initiate Class level Property requirements for instantiated Constructors based on run-time conditionals as well.
Static Constructors cannot have any parameters and will run before any base class Constructors or Class level instantiated Constructors. It is a good choice for Property management for changing runtime conditions.
Use the C# 4.0 default parameter feature whenever possible to reduce Constructor overloading. This will help to manage “Code Noise” which adds to code clutter and reduces overall understanding of the intent of the single responsibility of the underlying Class.
If the parameterless default Constructor is not required, or will never be called, do not place one above the parametered Constructor.
#Region directives for Public Methods usually indicate more than one responsibility that the Class is trying to support.
There can be exceptions but as a general rule Public Method use of #Regions is discouraged
This means that the Private Method had no reuse value outside of the consuming Class. It can be used many times in this Class but has no possible use outside of the underlying Class type.
If the Method has use outside of the consuming Class it should be refactored into a Helper Class Method.
Private Class Methods should be encapsulated using a #Region directive to reduce “Code Noise” and aid to a better understanding of the underlying Class intent to use Class level methods.
A Nested Private Class acts as a Class-centric Software Entity. It is a Type that solely exists for the consumption of the Parent Class.
If a nested Private Class is required by any other Type, it is Refactored to another files and made Public
An example of a Nested type would be a DTO created to remove a long list of Method parameters and replace them with a parameter DTO. This would abstract away the details of the parameter and aid to managing “Code Noise” and parameter clutter.
Classes have a single responsibility and will usually consume many dependencies to perform the requirements for the assigned responsibility.
The Only Requirement of the Class is to Service the Calling Software Entity’s Request
The Class cannot and should not manage any aspect of the dependencies that it requires. All these dependencies should all be refactored into other Class Types that have the responsibility for that management.
Helper Methods and Nested Class Types are the abstraction of internal Class unique dependencies. These become Private dependencies.
The structure of a Class should clearly define the single responsibility and the multiple dependencies, private and public.
The Class Structure should Aid in an Ease of Understanding of the Intent of the Underlying Software Entities