Blissful Designer – Blog of Jovan Stanojlovic

.NET Development and Web Design sprinkled with random thoughts on technology and art from a Toronto-based developer.

Archive

Category: .NET

In my last article I discussed how you can improve your application by using the multi-tier architectural design pattern. Now, I will talk about how you can give yourself some sanity by following standards intended to be used when programming in your favourite language. No, really!

Very often in chatrooms dedicated to programming, such as the one provided by GameDev.net (amongst a plethora of others), people will paste their problem as a code snippet. Almost always, the code is a disorganized heap of garbage. It is hard enough having to find the problem, but don’t make things harder on yourself and on those trying to help you by leaving your work looking like a mess. Follow a clean, consistent coding style.

If you are unable to read your own source files, do you think someone else will do it for you?

That question is no joke. Neatly written text is much nicer to look at than something that was written sloppy and without a care for the reader. Remember: programming languages exist for humans to read and understand easier, not for machines. The least you can do for yourself is follow a few basic guidelines, such as the ones I’m about to present:

  1. Be consistent
  2. Use whitespace wisely
  3. Write interfaces as if the person would guess what names methods have
  4. Divide code up into logical modules, using descriptive file, class, and variable names

1. Be consistent

Consistency is one of the best things you can do when it comes to finding a coding style. It lets the reader adapt quickly to the way your code is organized, and removes confusion when the person is reading each method. Without it, they will jump around trying to read the code, not even begin to understand it, because the code does not follow a uniform style.

Best way to be consistent is to find a naming pattern and a spatial pattern for each of the typical concepts found in programming languages: classes, methods, local variables and comments. A spatial pattern may be the number of blank lines between each method, followed by the comments of the next method. Within the comments can be the purpose of the method, the expected input, and the guaranteed output (Aside: Look into Design-By-Contract). Repeating this for each method will put the user in a mindset where they can find information quickly because they know where to look — you’ve been consistent with your code.

Often times when working in a team setting, the coding style will be decided upfront at the beginning of the project. When it isn’t, and you are modifying someone else’s source files, try to find a pattern them and conform to the convention it has to make your modifications seem as if one person wrote everything. This decreases the times a person has to pause and go back to re-read a block of code, as if it stands out unnaturally.

2. Use whitespace wisely

It’s easier for us to pick apart information by logically grouping them. Just like this website, and many forms of media, whitespace is the cruicial component in grouping data that belongs together. Misusing whitespace, or omitting blank lines or spaces at all, can result in the reader having to strain their eyes and read several times carefully to understand something very basic. Take for example this code snippet:

int blah;
cin >> blah;
int tmp = 1, tmp2 = 0, tmp3;
for(int i=1; i < blah; i++ )
{cout << tmp2 << ", ";}

Seeing code like this everywhere can quickly turn into a nightmare for the reader. Omitting the obvious flaws with asking for user input without sanitizing, there is practically zero whitespace, leading the person to read otherwise useless syntax like the parentheses and brackets. One possible solution is as follows:

int tmp = 1, tmp2 = 0, tmp3;

int blah;
cin >> blah;

for(int i = 1; i < blah; i++)
{
    cout << tmp2 << ", ";
}

Following a logical whitespace trend lets the user read less gibberish, and focuses more on the code that matters, because it spatially groups the important parts together.

3. Write interfaces as if the person would guess what names methods have

Every now and then I find myself trapped a discussion regarding how bad the Win32 API is. These kinds of statements could not be further from the truth. One of the things that the Win32 API particularly excels at is it’s naming convention. A lot of the time, it’s possible to not only think of a function that should exist, but to get the name of the function correct, under three tries. This kind of naming convention is a must for any serious developer, because putting in a little thought into symmetric naming of starting/stopping functions such as BeginPaint and EndPaint can go a long way in making it as least difficult as possible for the user of your code.

4. Divide code up into logical modules, using descriptive file, class, and variable names

Again, another seemingly obvious thing to say, that is often overlooked completely or unknown entirely. Grouping together methods that share logic in common makes it a lot easier to get the big picture regarding all those methods by simply reading their names. Sometimes, I find myself figuring out how something is implemented just by reading the name of the class, or method, or a particular comment that gives away subtle hints or flaws with the implementation. This is golden because it brings us one step closer to understanding a lot of code just by taking the time to give the variables some meaning. Using the previous example as a guideline, lets fix it up so it’s a little more descriptive in it’s functionality:

static const int PrintedValue = 0;

int repeatValueCount;
cin >> repeatValueCount;

for(int i = 1; i < repeatValueCount; i++)
{
    cout << PrintedValue << ", ";
}

Through variable naming alone, we can deduct the purpose of the algorithm. This is one of the things a serious programmer should be striving to achieve, a self-describing naming convention.

A coding convention is more than just pretty text

Eventually, if the coding convention is kept consistent throughout the project, we will have little guesswork to do as to where things are located, because it will become apparent through patterns found in the programmer’s choice of placement. As soon as we figure out the programmer’s style, we have an easier time traversing code and figuring out what it does. We can only do this if the programmer in question (that is, you) has taken the time to organize everything in a logical, thorough manner.

Recommendations on available Coding Styles

For users of C#, reading the C# Coding Style Guide is a must. I highly recommend downloading the Philips Medical System Coding Standards (PDF) as they conform to the standards laid down by Microsoft, and are ubiquitous. This same convention can be used for C++.

For users of C, the Indian Hill Style and Coding Standards is the most widely known coding standard, and is geared towards readability and removal of confusion.

Last but not least, internal conventions of a language

One last thing that is essential to follow is the conventions of a specific language or framework. By abiding by the standards of the language, you remove the reader’s confusion and make your code easier to scan through. An example would be:

If a C++ object has to manage it’s own memory, the copy constructor, assignment operator, and the destructor should be implemented by the programmer to prevent bugs or memory leaks.

Now, if a typical reader such as me stumbles upon your class header file and sees that you are overloading these, I will take note and look for dynamic memory in the implementation file. If the methods end up being empty, the convention is broken and nothing is gained.

C# has it’s own conventions, a popular one being Overloading Equals() and Operator==.

Conclusion

By following a set standard of rules and conventions given a programming language, framework, or environment, you will reduce confusion of the reader, and in turn they will be able to read your code and get the bigger picture quicker than usual. As an added bonus, returning to old code after months or years will not be as difficult as it would be if no standard at all was followed.

So make it easy for others to help you when you have a problem you can’t solve: don’t make reading simple code difficult!

When we try to find solutions to problems, we often think about things or scenarios similar to the problem at hand. As with everything else, software is no exception. For the majority of developers, the problem will boil down into this:

  1. Obtain user input
  2. Perform calculations
  3. Read or write information to a data source, and
  4. Ask the user for more input.

Although this scenario has been around for decades, and is one of the most common patterns developers face writing any kind of application, they are unaware of an elegant way of writing the application’s architecture.

The answer of course lies in a multi-tier architecture approach, which lets us write each of the three main functions of a program as independent modules:

  • Get user input
  • Perform the calculations of the program’s problem domain
  • Store or retrieve data in some long-term database

The multi-tier architecture can be further defined as a three-tier architecture, that contains the three modules as the main focus of the application’s architecture.

Lets look at the modules individually.

Presentation Layer

To the user, the presentation layer is the application itself. It is what the user sees and interacts with. To a developer, it is the layer where all of the GUI code will need to be written that allows the user to interact with the other layers.

It is important to realize that the presentation layer is just as important as the other two layers — and often times, even more important. Proper user interface design is essential in allowing the user to navigate and use your program with as few hurdles as possible. Unfortunately, a lot of developers do not follow guidelines, and more often, theme their applications without understanding the purpose behind theming. For Windows-based applications, it is essential to read the Windows User Interface Guidelines.

The presentation layer is most well known for it’s event handlers when dealing with user requests.

Business Logic Layer

This layer’s responsibility deals with solving the problem domain. The problem domain is another way to state the task which the application is meant for, the business logic. Does it calculate insurance rates based on some criteria? Does it schedule client appointments? These kinds of questions fit into the problem domain.

At this layer, most of our case scenarios become apparent through our classes and data structures. Often times, a BankAccount, Customer, Manager, or Service class will be present.

Often times, it useful to document the interaction of the components within the business logic layer, especially if they are complex (but it’s even more useful to make them simple in the first place!). Visual algorithm explanations like flow charts and state charts are very useful in getting a good idea of how this layer works.

The business logic layer is most well known for it’s calculation-intensive functions.

Data Access Layer

Often times the most intuitive and simplest layer is the data access layer. The sole responsibility of this layer is to read and write data from and to a source. The source is almost always a database of some kind. For our purpose, lets use MySQL as a popular database choice. The logic of the data access layer is as follows:

  1. Receive a request from the business logic layer asking for some data
  2. Retrieve the data, job done
  3. Receive a request from the business logic layer asking to insert some data
  4. Write new data, job done

Although simplified to a point, it is not unreasonable or uncommon of a data layer to function in this exact way.

It is often times helpful to abstract away the data source, so that the rest of the application is unaware (and rightfully so) of where the data is stored. The side benefit of this is that we can re-write the data access layer to use another source, but the interface between the data access layer and business logic layer will remain untouched.

The data access layer is well known for long-term storage, availability across different mediums and environments, and constant read/writes from and to the storage medium.

Putting It All Together: Application Controller

For most of the desktop-based applications, an Application Controller is needed. Because there are very few ways to intuitively write a three-tier application on the desktop, we need a controller that will take input from the presentation layer, call a business logic layer method, which in turn will read/write data, and finally, present the results to the user once this is finished.

The three-tier architecture is best present on the web, where the presentation, business logic, and data access layers can be completely remote and controlled by a framework designed for this kind of usage, such as ASP.NET.

Example Application in C# with WinForms.

To show the three-tier architecture in practice, I have written an example application that displays a collection of customer information in a table, using WinForms as the GUI framework and Access 2007 as a single-file database. It is thoroughly commented and highly recommended that you go through it to understand the application of the three-tier architecture better.

Download Example Application for Visual Studio 2008 (118 kb, Includes Source and Release Build).

Conclusion

The three-tier architecture is not a new concept. It has been used for decades, but many developers are still not taking advantage of this simple, intuitive architecture-level design pattern.

The most important thing to understand is when and when not to apply this type of design. As already mentioned, if your application is doing

  1. Get user input
  2. Process data
  3. Store and/or retrieve data

you would strongly benefit from this design pattern.