Analyzing Requirements and Defining Microsoft.NET Solution Architectures, Part XI...
Creating Standards and Processes (Part A)
The aim of this series of articles is to provide an overview of issues surrounding the architecture of .NET Solutions. In doing so it is following Microsoft’s recommended approach and, in particular, looking at the requirements of the related Microsoft certification exam (70-300), which itself is one of the requirements for the MCSD .NET qualification. The main reference for this series of articles is the Que publication: 'Exam Cram2 .NET Solution Architectures'.
We’ve looked at the following thus far:
Article I: phase 1 of the process, the envisioning phase.
Article II: started on phase 2 (gathering and analysing requirements) focussing on business requirements.
Article III: continued with phase 2, focussing on user requirements and issues surrounding globalisation and localisation of your application.
Article IV: finished off phase 2, focussing on operational and infrastructure requirements
Article V: phase 3, developing specifications.
Article VI: phase 4, creating the conceptual design.
Article VII: phase 5, creating the logical design (application architecture).
Article VIII: phase 5, creating the logical design (logical data model)
Article IX: phase 6, creating the physical design.
Article X: phase 6, creating the physical design (deployment and maintenance).
In the last two articles in the series we consider a subject that applies to all phases of the project development lifecycle, looking at the key area of standards and processes.
Establishing standards for the team we've left until the final topic but it is not the last chronologically; in fact it should be one of the first. Standards define the 'minimally acceptable' practices that the team has agreed on. Processes define how you are to get from the project inception to project completion with the least risk and the highest quality.
A key issue is that the whole team must follow the agreed standards or processes or the project will be compromised. These standards should be best practice standards ... just because they are agreed standards doesn't automatically make them any good or more likely to lead to a quality solution! The standards themselves must be good.
In these last two articles we'll consider some of the key areas where standards are important.
Standard formats for headers and footers, revision tracking, styles etc. should be used and a standard medium employed, e.g. Word documents. Key documents should be subject to peer review and you should document why, not just what, you did. Justifying decisions early on means they are more likely to be the correct decisions.
The Microsoft Design Guidelines have plenty to say in the subject of coding standards, key points from which follow:
Naming
Two main naming guidelines are recommended:
Basically, MS recommends you use Pascal case for everything bar parameters, fields and variables, where Camel case should be used.
You should not use abbreviations unless they are widely accepted. You should avoid using class or method names that conflict with language keywords.
Try to name classes by using a noun (or noun phrase) for the class name. Underscores and Hungarian notation (strName) are out as far as Microsoft is concerned! When naming methods use the VerbNoun format, e.g. ClearGrid rather than GridClear.
Further guidance:
Class member usage
Be sure you know when to use a method instead of a property. Use read only properties if the user cannot change the data behind. Avoid write only properties.
For methods consider overloading where you would have used optional parameters or default parameters in the past. When overloading keep the order of the parameters consistent.
Avoid constructors that do a lot of work. Use parameters in constructors as shortcuts for setting parameters.
Dimension variables when you first use them, not at the top of the section of code as used to be common practice.
Microsoft recommends defensive programming – checking each parameter value for validity, throwing exceptions where necessary.
Type usage
Classes are recommended over interfaces. Classes can contain implementation code, and this implementation can be inherited and extended. Interfaces require all implementation to be created. Interfaces do not support implementation inheritance.
Use structures for types that are primarily containers for primitive data types. Enums are recommended where applicable, particularly as a way to strongly type parameters.
Exposing functionality to COM
For classes that will be consumed by COM the ComVisible attribute should be used. Be aware of when you want your object to be marshalled by value (serialised) or marshalled by reference (via proxies).
Error raising and handling
Use the predefined exception types where possible. When creating new exception types inherit from ApplicationException. Do not use exceptions to catch normal or expected exceptions or to influence program flow. Exceptions should be focussed on unexpected errors. Consider performance – exceptions will bubble up the call stack ... they should never reach the root of this stack.
Array/ Collection usage
Use a collection rather than an array when Add or Remove are supported, and vice versa. Never return Null from a Collection or Array property – return an empty collection (or array) instead.
Use collections when it will prevent the calling code from having to scan the entire structure looking for a value.
Security in class libraries
Two dimensions:
Threading
Static state must be thread safe. Design away from the need for thread synchronisation if at all possible. Use the lock statement with care and as seldomly as possible.
Asynchronous ProgrammingOften a good way to improve scalability.
Because of the difference between COM's instance count and .NET's garbage collection, releasing object or resource references in a more predictable way might be necessary. You can use the Finalize method for implicit, albeit indeterminate, cleanup, or you can use the IDisposable interface and the accompanying Dispose method so that your object's client code can force a cleanup of resources. Just make sure to call the SupressFinalize property of your Dispose method. In general, code in the Finalize method is considered suboptimal from a performance standpoint.
Equals
The equals method is used to see if two objects are the same. Sometimes this may mean the same value, sometimes pointing to the same memory address. If you don't want this default behaviour you would override in your own code.
Callback
Use events instead of callbacks if the calling code signs up for notification in advance. Or use Delegates.
Timeout
Allow the calling code to specify the maximum time it will wait for a response (for either synchronous or asynchronous calls) with a property setting or an extra parameter.
In the next and final article in the series will complete our look at issues surrounding standards and processes
Exam Cram 2 .NET Solution Architectures
Cornish et al.
Que
http://msdn.microsoft.com/architecture/