Monday, November 26, 2012

Regions are a code smell? Please!

I'm a C# developer who uses #regions on a daily basis.

There is a fair chance that the above statement threw off a lot of C# developers. Some may even start running riot, accusing me of "jumping the shark" or calling me a "cowboy coder" whatnot.

It's pretty shocking to see many C# developers hating #regions passionately. I have to admit that this has left me completely baffled for a long period of time.

Yes, even the man himself abhors regions. 

Observing all the strong opinions made by the community in programmers stackexchange had nearly convinced me into not using #regions. But then I remember seeing many code samples and tutorials written by expert programmers like Josh Smith use regions extensively. 

Then it suddenly hit my head. These people complaining about #regions have either never developed a WPF application nor deployed a tangible WPF application that utilizes the core functionality and features (MVVM, data binding, command interface etc).

Most of the code samples I've seen that uses #region blocks are from WPF applications. In fact, after much googling I think it is safe to say that it's hard to find a WPF code that doesn't utilize #regions.

The rationale for this is pretty straight forward: you and your companions will never, ever have to look at the folded lines of codes again! Ok, "Never" might be pushing it a little bit too far, but hopefully you get my point.

You might be saying "Ok, the lines of code you wrote does not have to be read again, there's something clearly wrong with the code you wrote". Don't be ridiculous, we wouldn't even have this discussion to begin with if that were the case. 

I sense an in-depth explanation is in order so I'll demonstrate an example: To reap the benefits of WPF, you are often required to do some "setups" to properly get your UI to display what you want. To use a WPF feature known as Data Binding you first need to implement INotifyPropertyChanged interface. Then you define a private variable for your property to refer to, a PropertyChangedEventHandler event, and a user defined property to perform the notification between your UI and business logic of the previously defined private variable.  (Digressing momentarily, if you are a WPF developer who doesn't know what data-binding is, this is probably a good place to stop reading this post and get yourself to really learn how to use WPF).

Here is the important bit: those properties, notification event and any other potential code to make the WPF feature to work are merely prerequisites to get your code working. In other words, once you verify the data binding working as intended, there is practically no reason to look at your setup code again. Now for those who are versed in WPF will readily recognize that all this code typically goes inside your ViewModel so consequently, that is where you see the regions used most frequently.

The following is a sample code from Josh Smith's WPF Treeview Tutorial:



Seriously, all of what's above is just noise to me. Without even having to look at the code, I expect the necessary properties and interface methods to be in the viewmodel so scrolling down through all this unnecessary, expected information is just a waste of time. 

Now what would be preferable to see is the following:


Immediately, I know that when I'm reading the code, I will probably never have to look at the folded portions, because all they do is relay the information from UI to Business Logic (Model). Everything is organized in a nice fashion, so if by any chance we really needed to fiddle around with our viewmodel, we immediately know where to add our necessary data/property/interface methods. Had the regions not been there, I would've had to scroll miles down my IDE to determine exactly where everything goes.

Admittedly, the above example might be taking things too far - it isn't necessary to literally group everything in regions. For instance, I think just wrapping the properties would've been sufficient.

But the important point I wanted to bring is this: it's OK to have a dogmatic belief or a strong preference towards a particular coding style, as long as it logically makes sense with your colleagues and it helps solving a particular problem. Part of what makes a good programmer is the ability to choose the right tool and having the correct approach to the problem you are trying to solve. The real harmful practice is to state an absolute such as "Never or Always" without considering other domains (Goto statement is an epitome of this, at least for the case of C#).Also remember that programming languages evolve continuously - what might've been a bad practice in the past can very well be the recommended approach now. 

As for the fellow developers, including Jeff Atwood whom I have a lot of respect towards, you can keep hatin' on the #regions but for us WPF developers, no thanks. We will keep using them :P

6 comments:

  1. I get where you're coming from. I also get where the haters are coming from. Let me try to get you to understand each other.

    All the code in the examples you've shown is boilerplate. Boilerplate *is* a code smell. Think about it - if you have to write that code for each ViewModel there's a massive amount of code duplication going on. We all know DRY is a good aim for any software application.

    Then again - as you point out you *can't* avoid this boilerplate.

    The conclusion - #regions hide a code smell built in to the very technology itself. It's similar to the story of a patient who tells the doctor "My hand hurts when I do this". "Don't do it!".

    With current technology #regions are unavoidable but they're still a code smell. Come to think of it, I can think of many features of a typical codebase that fall into the same category.

    ReplyDelete
    Replies
    1. Hello. Thanks for leaving an insightful reply! You've got a very convincing argument so I'd like to take the time to address it. But first, I'd like to ask for a clarification: You agree the "boilerplate" you refer to is unavoidable, yet you still advocate against the use of #regions?

      My opinion on this matter is as follows: Essentially, much design patterns will end up having a similar duplication in the way you state it. This is fundamentally unavoidable as the design pattern opt to create a general reusable solution to a problem by separating the concerns (In this case, that would be UI, logic, state) and by adhering to the single responsibility principle.

      A lot of the so-called boilerplate code aims to set up a very dynamic and flexible foundation for the application. If you are making a large application that requires a lot of maintenance, this boilerplate code is what's going to save you down the line.

      So by the generally accepted definition of code smell, I can agree that the usage of regions here technically can be hiding a code smell but I think the gains for doing so is simply too much to overlook.

      Just to not misrepresent myself from the post: I'm not attempting to strongly advocate the usage of regions - I believe #regions should be the exception, not the rule.

      Delete
    2. By the way.. correct me if I'm wrong.. but are you Jeff Atwood? Apologies in advance if I'm mistaken.

      Delete
    3. No, not Jeff Atwood - just some Jacques Frenkel. No need to apologise either.

      Anyway, let me clarify what I said. I'm not advocating against #regions if you're using any technology currently available. My point is that the technology is deficient and this deficiency is forcing us to use constructs that smell.

      To apply this to the use of #regions and boilerplate code in general. You say "Essentially, much design patterns will end up having a similar duplication in the way you state it. This is fundamentally unavoidable as the design pattern opt to create a general reusable solution". (I know I've cut the quote in mid-sentence. It seems to me that the important part ends there.)

      If the design pattern was truly reusable, it would only have to be coded once and then called in the same way any method is called, with suitable arguments being passed to customize behavior to the caller's need.

      The reason this can't be done is the lack of strong enough flexibility inherent in all existing programming languages. The only way you are able to customize the behavior is by rewriting substantial portions of the block of code. If you do this for method overloads where your language can help you avoid it, you will horrify a decent programmer. It is reasonable to expect his horror to extend to cases where your language forces you into this path.

      Whether an alternative means of programming that would provide the necessary flexibility is possible is an interesting question. My personal opinion is that the answer is yes. But even if you disagree, you should see why #regions provoke the reaction they do.

      Delete
    4. I don't think I tied my argument back to the specific issue of #regions. I'll do so now.

      When you hide code in a #region you're saying - nothing important over here, this should really work based on the other stuff you see.

      In that case you should be asking - so why does the code exist at all. It should have been factored out as I described in the previous post. In fact, in some cases it *could* have been factored out. Distinguishing these cases from the unavoidable ones can sometimes be extremely subtle.

      There's also the use of #regions to organize horrendously bloated code but I don't think we were ever talking about that.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete