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

Tag: Coding Standards

There has been a lot of talk in the recent years about the harm that design patterns bring to new and seasoned developers. The message is clear: you should not use them as a first solution to a problem. This article examines some of the reasons behind that, and even why you should consider not using them at all.

For some odd reason, a handful of developers equate using design patterns to designing good code. The two have nothing to do with each other. Do not rot your mind thinking a book full of puzzle solutions will make you a good puzzle solver. It won’t, it will trick you into thinking you know more than you actually do. But before I get to the bottom of things, it would be a good idea to get this out of the way:

Knowing design patterns is very important

Despite the criticism, it is still essential you have some idea of design patterns, or at least a vague approximation of how they would appear in code. There is often an underlying reason for using a specific approach to a problem, such as using Event Listeners, MVC or the Multi-Tier Architecture. Knowing design patterns can help you:

  • Traverse code faster, allowing you to get the “big picture” sooner than you would otherwise
  • Refactor existing modules such that they are decoupled and are less bound to other modules in the application
  • Generalize a problem you already know exists, have encountered before, and can solve it with a clean solution from the first attempt

Hopefully, you’ve caught on to the fact that the three points deal with post-written code — or at least someone with prior knowledge and strong hindsight of the problem at hand.

So why are design patterns so bad?

1. They make programmers think in terms of patterns, not in terms of the problem domain

One of the worst things you can do when designing an application is think in terms of code, and omit the fact that you are trying to solve a specific, very often business-oriented problem. I often see new or simply inexperienced game programmers trying to brute patterns into their code without a single clue as to why they need to think in terms of patterns first, or whether they will benefit from that approach at all. Often times, the programmer has some grand design in mind (getting ahead of themselves, real fast) that the pattern will solve (never finishes enough of the project to get to it), yet does not realize how little of the problem they understand, and even less idea of why that approach is suitable at all. (Aside: If you ever meet one of these ambitious programmers, ask them why they chose that approach. The answers get repetitive.)

Instead, the humble and realistic approach is to ask yourself what is the application trying to solve? This will avoid the pattern situation altogether, and you might get lucky and see the project at a stage where you can finally refactor the application to use some patterns, making the next round of modules easier to integrate with the existing modules.

2. They try to replace experience, hindsight, and purpose of the application with design generalizations

In a lot of situations, and in lots of different professions, it’s hard to use good judgement without knowing the problem, and sometimes the only way to know the problem is to solve it once. Solve it twice or three times, and you’ll most often find a pattern emerge. I use the word knowing here in a peculiar way, because while you can be presented with a problem, it’s difficult to find a clean solution without knowing what makes the problem tick.

As such, the best place to use design patterns is after a few attempts at a problem, after you have better assessed the true nature of what it is you’re trying to solve. As a humble example, I often tell myself: I now know the problem, I know when it will come up, and I know enough about the solution to generalize the module so that it will take the least amount of work to adapt new changes. In my experience, (time and other constraints aside) I have found that this approach works fantastically, because it leaves you open with your mind’s possibilities, instead of tying your thoughts down to a book or two full of UML diagrams.

This is what I refer to as the natural way of solving a problem, and is discussed as the next point.

3. Design patterns should emerge from code written, in a smooth transition

Since this is one of the key points of this article, I will repeat it again: You cannot apply a design pattern to a non-existing problem. It is far easier, and you gain a lot more out of it, if you apply a pattern to code that already exists, is hopefully written by you (and you still have the big picture in your head), and is in need of refactoring. Trying to adapt code to a solution that does not need a solution is backwards and a waste of time. Focus your thoughts on what needs to be finished instead of looking for problems to solve without any benefits. You won’t gain anything out of it.

After you’ve written a lot of code, and you’ve told yourself it’s time to fix it up and make it work nicely with other modules, it is a wise idea to see how you can refactor the code. This is where the real patterns come into play. These are not the ones talked about in books (but may and do very often end up that way), but the ones that are spoken in the way you’ve written your code, designed your application and thought out the architecture of your application. This is where three main things come into play which will help you: Your brain, algorithms and data structures. Using just these three, you can come up with all sorts of clean solutions to a problem. You will walk away knowing far more this way than you would blindly reading a book whose intent is to somehow turn you into a master architect. It won’t, you’re fooling yourself. No one ever became a good programmer relying on books alone.

Conclusion

For all their seeming benefits, patterns are very often misused. In recent years, a number of programmers have stepped out and proclaimed that patterns are misused, harmful to programmers and projects, and should be avoided unless derived to from experience. I think that last part can be said to apply to a lot of things. Nevertheless, knowing patterns vital and beneficial to you as a programmer, because you will have some gain out of it if you need to adapt to existing code.

Other articles I found worth reading:
Chris Ericson’s “Design Patterns Are From Hell” (Two articles)
Jeff Atwood’s “Rethinking Design Patterns”
Alex Davies’ “Why Following ‘Design Patterns’ Is a Bad Idea”

There is also an IEEE publication entitled “Design Patterns Are Bad for Software Design”, stating “Design patterns make it too easy to introduce unnecessary complexity into system design and are much too often applied without discipline or experience.” I can’t say I disagree.


Addendum

Here is a small excerpt of the aforementioned IEEE article, almost summarizing my article:

Today, design patterns let average developers design working OO systems that would have otherwise been beyond their capabilities. This might sound like a great thing, but the relative lack of expertise or brilliance can easily result in bigger software design disasters than would occur without them. For example, most GoF patterns are about introducing flexibility by indirection and inheritance. This is great when you use it to reduce code size and simplify logic by applying polymorphism, but it can also be a tool for overengineering and introducing excessive complexity. A designer who can’t decide on a system property can use design patterns to postpone decisions, speculate about features never needed, and lay a heavy burden on system implementers and maintainers.

I recommend anyone with IEEE access to read this article, as it contains far more insight into the problem than the excerpt, and also provides some counter points from other developers.


Version Control (or Revision Control or Source Code Management) is still a somewhat of a mystery to many developers, especially those who are new in the field of software and web development. I am stumped as to why that’s so, because one figures that professors would advise their students that additive backups are an Extremely Good Thing. What does additive backup mean? It’s very simple.

Quick overview of how it works

By using an additive vesion control system, you will never lose your files, because nothing can be deleted, it can only be revised. Each revision marks a change (adding files, modifying files, removing files)  in the version control system, and the system keeps all the files of all revisions (these are highly compressed, so little to no space is wasted between revisions). Every revision is added on top of the last once, hence the name additive. At any point in time, we can go back and access the files from our previous revisions. All of your files are kept in the system’s database, called a repository.

Why use it?

This is a very good question. How do you benefit from version control system? Whether you are a programmer or not, and whether you are storing source code, pictures, music, or any other type of file, a version control system is an indefinite backup system. There is really no way to accidentally delete files or to overwrite them (assuming you’ve backed them up first!).

A lot of the times what people do is they will store their backed up files in:

  • a folder on the computer
  • a password protected zipped file on the computer or on a remote server
  • a USB key

And this is just counting the people who do back up their sensitive data!

The problem with all these methods is that they are prone to human error that cannot be undone. Version control does not suffer from this problem because if you make a mistake, you can always go back to a previous point in time, effectively undoing the changes.

Where do I get it?

There are a number of version control systems, each with pros and cons. The one that I use and highly recommend is Subversion (SVN). It is painless to set up, and you can get it up and running in less than ten minutes. The easiest way to set it up is to download the CollabNet Client and Server Installer. Afterwards, I highly recommend you download TortoiseSVN, providing you with a GUI on Windows accessible with right-mouse click.


Update: A number of readers have also recommended VisualSVN Server — a self-contained SVN repository manager. This is another excellent choice for both personal and commercial use. The free version comes with a few restrictions, but it’s definitely not a deal breaker.


It’s really that easy

For more information, TortoiseSVN provides a very good introduction and manual on managing your Subversion repository.

Conclusion

Try to use version control with all your important documents. This will ensure that your files never go missing, and in case of accidental loss of data, you can always go back to a previous version of the file. Ocassionally, it’s a very good idea to backup the version control system to another computer (password protected by default), in case of a catastrophic hardware or operating system failure.

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!