Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

A Simple and Clean .NET Design and Implementation Method - Part 1

3.45/5 (5 votes)
24 Apr 2008CPOL6 min read 1   166  
A fast and simple way in using application design patterns - Part 1.

Introduction

There are many methodologies surrounding Design Patterns and standards available in reference to the software development life cycle. Each needs to address the following issues: standardization, reusability, and scalability. The standardization aspect consists of coding standards, naming conventions, comments, use of interfaces, etc. Reusability looks at the extendibility, and flexibility to run as a component model, or wrap-able in an n-tiered approach. Scalability encapsulates the emphases on robust coding, performance, data usage and transfers, and finally security.

For sure, there are many decisions involved in designing and developing an application, even the simplest applications should require ample amount of design work before implementation takes place.

In this article, I will take an easy and simple business requirement and go through the process of design and implementation where I will try to emphasize on standardization, reusability, and scalability.

Background

  • Software Architecture
  • Object Oriented Programming
  • Design Methodologies (RUP)
  • UML

Name Value Storage Project

User Requirements

In this example, the business user requires a program be built to store Name Value pairs such as FirstName = Yang where FirstName = Name and Yang = Value.

The Name value can only be alphanumeric values, and spaces around the equal sign should be ignored.

The storage needs to be XML based, and the GUI must be simple and user friendly.

Design

Use Case

The User Requirement in this case is simple and straightforward. Without meeting with the clients to gather more information, we can now deduce a useful List of Actions that can be performed. We can also draw up the high level interactions between Users and the Software. At this point, we can also create a list of processes, the application's must-haves and should-haves that would increase the reusability and extendibility.

A Use Case diagram can be put together to illustrate this:

Use_Case.png

Even though we only have one user and some very simple Use Cases, the process can quickly grow and become more complex. By analyzing the Use Cases, we can minimize the risks involve in undertaking feature changes as well as development time.

Process Diagram

The next step is to introduce some process diagrams into the design. A good starting point is to take each Use Case and extrapolate a Business Process out of it. Again, a good design is dictated by the robustness on validations, extendibility, and error handling.

A good way to extend a business process is to Expose Events through the objects. This can also provide ways of intercepting specific processes, thus scaling the application.

Error handling and validations tie hand to hand. The result of specific business rule validations should generate specific exceptions or results that are controlled within the application.

Let's take a look at a very simple process of Creating a Name Value Pair:

Image 2

This process is a simple, and involves particular layers of business operation. The segregation of the business layers will give clues to the implementation phase, and reduces the amount of effort in the actual project design. It is important to focus on the way entities in the process connect since this ultimately reflects the performance and will be utilized for security on calculating attack surfaces.

Class Diagram

Name_Value_Libarary.png

The key to a robust and scalable application lies in its core design model. Since most applications deal with information, it is critical to develop a model that will capture all the properties of the required information as well as the interactions and relationships between them. The more you understand about what it is you are trying to capture, the better the model will be, and the more robust and scalable the application will be.

Many times during this phase, you will be faced to challenge the business users on why a particular decision about the types of information are captured. A robust object oriented model sometimes does not follow a particular business model, since the business requirements usually apply to a very scope centric and project centric collection of data. Due to this face, our model may lack growth potentials and key elements that allow future advancements and scalability. It is crucial to challenge the business users whenever possible to increase the scope or alter it to enable the project to reach its potentials. By following this methodology, we can deliver more with less time for the first phase, and for future phases as well.

Usage of Interfaces

Below is the class diagram for the Name Value Storage project. Instead of simply using a Hashtable or Dictionary as my implementation, I've started off the project by introducing a Business Logic Interface.

C#
using System;
using NameValueLib.BLL;
namespace NameValueLib
{
    /// <summary>
    /// Name value collection is used to manage a list of Name/Value pairs
    /// </summary>
    public interface INameValueCollection : 
        System.Collections.Generic.IList<NameValuePair> 
    {
        /// <summary>
        /// Raised on Adding new NameValuePair to the List
        /// </summary>
        event NameValueHandler InsertNameValuePair;

        /// <summary>
        /// Raised on Deleting NameValuePair from the list
        /// </summary>
        event NameValueHandler RemoveNameValuePair;

        /// <summary>
        /// Add a new Name value pair into the list given a single
        /// patterned input in the format of [Name][delimiter][Value]
        /// </summary>
        /// <param name="NameValueString"></param>
        void Add(string NameValueString);

        /// <summary>
        /// Removes all the name value pairs
        /// </summary>
        void Remove(NameValuePair[] nameValuePairs);

        /// <summary>
        /// Sort the list by Name ascendingly
        /// </summary>
        void SortByName();

        /// <summary>
        /// Sort the list by Value ascendingly
        /// </summary>
        void SortByValue();

        /// <summary>
        /// Sort the Name Value collection by a sort by and order
        /// </summary>
        void Sort(NameValueComparer.SortByType sortBy, bool ascending);
        /// <summary>
        /// Get the XML output of the list
        /// </summary>
        /// <returns></returns>
        string GetXML();

        /// <summary>
        /// Save the List to an XML File
        /// </summary>
        /// <param name="FileName"></param>
        void Save(string FileName);
    }
}

If you look at the Use Case, you will notice that there are a lot of similarities. By segregating the implementation and the abstract prototype, having this interface allows room for extendibility and to create standardization. Depending on the size and user desires, I can wish to implement this interface in a number of ways either with a List<> or Dictionary<> or even a custom data structure.

N-Tier Architecture

By adapting an N-Tiered approach, we allow the application to be cross domain, be reused and pluggable into any type of application whether it's a web or Windows or even Service application. We allow it to be registered in the GAC, and even for COM+. We also open a new door for more secure abilities while not increasing the attack surface of the core functionalities. N-Tiered architecture renders many benefits that outweigh the disadvantages. It is now an industry standard and is the bridge to the next generation applications such as SAAS.

The project is split up into two tiers, the Business Logic Layer and the Presentation Layer done in Windows Forms. I can easily implement a web version or even a console version for the presentation layer.

A point to make about standardization. Standardization enables a project to be understood by peers even by yourself in the future if you need to make changes. Coding standards and naming conventions can be critical in minimizing the amount of find needed in searching and filtering. It is a good idea to develop a standard project layout (using folders) as well as a class layout (using namespaces). This not only helps us developers, it can sometimes help CLR to more efficiently execute grouped code.

Project_View.JPG

Validation

A robust business layer should contain solid validation of input variables. You should never trust the client no mater how secure the presentation layer is. The pattern I used in the project uses the .NET Exceptions framework. To efficiently utilize the .NET Exceptions framework, NameValueException is used to handle application level business logic validation exceptions.

C#
..
public void Add(string NameValueString, string Delimiter)
{
    string Errors;
    // pre: validate
    if (!NameValueValidator.DefaultValidator.ValidateNameValueInput(
                            NameValueString, Delimiter, out Errors))
        throw new NameValueException(Errors);

    try
    {
        // find delimiter position
        int delPos = NameValueString.IndexOf(Delimiter);
        // create new Name Value Pair
        this.Add(new NameValuePair(NameValueString.Substring(0, delPos).Trim(),
            NameValueString.Substring(delPos+Delimiter.Length).Trim(), Delimiter));
    }
    catch (NameValueException nex)
    {
        throw nex;
    }
    catch (Exception ex)
    {
        throw new NameValueException("Error Parsing Name Value Input.", ex);
    }
} 
..

Events and Delegates

The usage of events and delegates provides a way to intercept application triggers, as well as a way to efficiently extend business logic.

In this project, I've created a delegate to handle generic Events such as <code>Add() or Removed() for standard data collections.

C#
public delegate void NameValueHandler(object sender, NameValuePair NameValuePair);

Sorting

There are a number of ways to implement sorting in .NET. One efficient method is to implement a comparer and utilize the default .NET Quick Sort for the List<> object.

C#
/// <summary>
/// Comparer used to compare Name Value Pairs and for Sorting the NameValueCollection
/// </summary>
public class NameValueComparer
    :IComparer<NameValuePair>
{
    public enum SortByType: byte 
    {
        name = 1,
        value = 2
    };

    #region public propperties
    private bool _ascending;
    public bool Ascending
    {
        get
        {
            return this._ascending;
        }
        set
        {
            this._ascending = value;
        }
    }

    private SortByType _sortBy;
    public SortByType SortBy
    {
        get{
            return this._sortBy;
        }
        set{
            this._sortBy = value;
        }
    }
    #endregion

    #region constructors
    public NameValueComparer():this(SortByType.name, true){}
    /// <summary>
    /// Create comparer
    /// </summary>
    /// <param name="sortBy"></param>
    /// <param name="ascending"></param>
    public NameValueComparer(SortByType sortBy, bool ascending)
    {
        this._sortBy = sortBy;
        this._ascending = ascending;
    }
    #endregion

    #region IComparer<NameValuePair> Members

    /// <summary>
    /// Compares x to y according to the sort and ordering
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    public int Compare(NameValuePair x, NameValuePair y)
    {
        // pre:
        if (x == null || y == null)
            throw new NameValueException("Error Sorting Collection.");
        if (this.SortBy == SortByType.name)
            return this._ascending ? x.Name.CompareTo(y.Name) : y.Name.CompareTo(x.Name);
        else if (this.SortBy == SortByType.value)
            return this._ascending ? x.Value.CompareTo(y.Value) : y.Value.CompareTo(x.Value);
        else
            throw new NameValueException("Sort Type not found.");
    }

    #endregion
}

Serialization

One of the major improvements in the .NET framework is its ability for easy serialization and deserialization. The adaptations are used for object persistence, communication protocols such as SOAP, and remoting.

XML Serialization

Coming Soon...

Presentation Layer

Main Form

MainScreen.JPG

Custom Validation Handling...

Invalid.JPG

Using the GetXML() Method

Get_XML.JPG

Conclusion

Coming soon...

Points of Interest

You may improve this project in anyway possible and send it to me. I've left an empty dictionary implementation of an interface, which if you are interested, feel free to go ahead at it.

History

  • April 24, 2008 - First draft of article created.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)