DEV Community

Rachel Soderberg
Rachel Soderberg

Posted on

The Great C# Regions Debate

C# regions were introduced way back in 2003 via Visual Studio .NET as a way to name and collapse a block of code using the keywords #region to open and #endregion to close a region. The result looks something like:
Region Code SnippetThis concept of collapsible regions came before the time of collapsible namespaces, classes, methods, if-statements, and for loops so it may have been a welcome addition for large portions of generated or boilerplate code.

In today's C# we don't usually have the same need to clear screen space and remove large chunks of code we don't want to see. Generated code is often created in separate files, our blocks of code collapse into neat single lines, and as good developers we're all using the "each method has one job and a descriptive name" rule -- right? 🤓

Using regions in the web service endpoint I'm building at work led me to the question "What are good region practices?" and consequently, to writing this article because there is a number of articles expressing hate for regions and only a few very short (and not very good) statements expressing why they can be used for good.

C# Regions Are Evil

One of the top hits on my search was an article written by Marc Duerst, simply titled: C# Regions are evil. His main points of the article make sense and are absolutely reasons to be wary of your use of regions. He describes regions as painful to the next developer who has to read your code - they get to expand dozens of collapsed sections to view the full picture. Some developers also get in the bad habit of hiding large code blocks in regions instead of refactoring them and considering how their structure could be improved.

Duerst also states that if it were possible for Microsoft to remove regions completely, it would be a good thing, but because it's not we should simply stop using them completely.

Regions Are a Code Smell

Another high hit on my Google search was Regions Are a Code Smell by Erik Dietrich. This article is written more from a middle ground and isn't really blaming the regions themselves, more of his focus is on the developers using bad practices: "regions do not make your 800 or 8000 line classes any less awful and smelly than they would be in a language without regions." He more specifically calls regions code deodorant or code cologne which works for code in much the same way deodorant or cologne works for smelly people - it hides the smells!

Dietrich believes there's no point in removing or rallying against regions because bad developers won't stop making bad choices simply because you've told them to stop using regions.

C# Regions Are To Be Used Gently

I agree with both of these authors for the most part and will stand up and shout from the rooftops that I have used regions for evil in the past. (The first step is admitting, right?) I was new, following the patterns in place by the developers before me, and didn't know any better yet.

Today is a different story though. Today I choose to use regions only in specific situations and would not rally to have them removed because they do occasionally provide value to me in my code and as Dietrich said, it wouldn't stop developers from making bad code smells even if we did.

I don't use regions in the majority of my projects and if I feel the need to make a region I consider the reasons why. Most often it's that I've built a chunk of similar code that is not similar to the code surrounding it. This means I need to create a new method or class to house this chunk of code and other parts that relate to it. Another case may be that my class is just getting too long - that's another great opportunity to consider how I can refactor my code and see what can be pulled out to create a new class. An example: "There's a bunch of Salesforce methods in this Sales Order creation class, why don't I pull those out and make a Salesforce Helper type class to house all of that functionality?"

The WCF Web Service Application I'm currently building onto at work is one of the rare situations where I have opted to use regions - and several of them at that. I will give you some details into this so you can form an idea why I've chosen to use regions:

  • I was asked to follow the structure already in place in the application. Currently there are five listener endpoints that watch for various Salesforce Outbound Messages to fire. The application's classes are limited to the interfaces and services with a rigid naming standard. This means no breaking out sets of similar methods into new classes for readability and unfortunately makes for a very long Listener class.
  • The listener is reading and updating many different portions of our Salesforce org as well as our ERP database, so there will be many large sets of similar variables all contained in one portion of the Listener class. This is normally frowned upon, but to be able to collapse fifteen Customer variables and ten Employee variables so I can view my RMA variables is a lifesaver (and helps with organization, so they don't end up mixed into one another).
  • This project is on a stricter time requirement and my next task will be taking many of these regions out into completely new applications because many of these methods are used across our entire organization and currently require us to make code updates in 2-5 different places when one change needs to be made. Having them organized and separate will make that job easier.

So how do I keep these regions from deodorizing my code? The biggest step is avoiding the use of a region until I've considered the code that will go into it "done". This means it's been written, tested to ensure it works, and refactored out into small well-named methods. I pull these methods out, much as I'd pull them out to put them in a new class, and store them in their region at the bottom of the class (please, do not leave regions randomly scattered between your methods!) Method Regions In this case, I am essentially considering my regions to be their own class-like entities and handle them as such. If you're curious, my variables are in regions like so: Variable Regions

Once again I'd like to reiterate that while I realize these are not best practices, sometimes as developers we are restricted to criteria (that may not be best practices themselves) that require us to bend some rules. I believe that as long as we knowingly bend these rules and use the best practices possible for our situation, we can sleep soundly knowing we wrote the best code we could. Even if it contains regions. If you're thinking about breaking code out into a region stop for a moment, ask yourself why, and consider whether it's due to a need to refactor or to hide something yucky you've done.

Top comments (13)

Collapse
 
twigman08 profile image
Chad Smith

My view on regions is mixed. I will say, I do usually sense a code smell when I see a region when I first get into a code base. Mostly because I've lived the nightmare of diving into a region and seeing another region inside that region, and then even regions inside single functions. When I see that then they really get to me as it's just trying to hide the fact that you need to rewrite this code.

I've also seen regions used in places that I'm fine with. An example being a RESTFUL API. I have seen regions used to keep GET requests separate from POST requests in a controller with the controller being well written and skinny. I'm fine with them being used in situations like that.

So like a lot things: use them appropriately. Don't use them to try to hide your badly designed code, and please don't start using nested regions inside a single function call.

Collapse
 
rachelsoderberg profile image
Rachel Soderberg

Have you ever seen a region nested in a region? That would probably make me cry...

Collapse
 
twigman08 profile image
Chad Smith

I sadly have. I definitely cried.

To make it worse: I have seen a nested regions inside a constructor before. I am still having nightmares over that...

Thread Thread
 
rachelsoderberg profile image
Rachel Soderberg

Oy, I didn't even consider that as a possibility. It hurts to even read it

Collapse
 
beagle1984 profile image
Sergio Aquilini

Maybe CustomerService and CustomerLogic aren't such a great design. Did you ever consider this?

In order to avoid god classes and really strive for that SRP, you should start with giving your classes a meaningful name that implies a single responsibility, something like CustomerMailer, CustomerPurchaseStatistics, CustomerTicketsHandler, etc.

Collapse
 
netferret profile image
netferret

I think its quite simple, if you need to hide blocks of code like this then your class is clearly too large. You need to use Separation of Concern and split it out accordingly.

Hiding properties, constructors etc is just silly as you need to need to see them as developer or how can you analyse the code and do your job?

I personally hate the use of these regions, its a faff, hides code, make its look nicer for the person who wrote it, but its not the person who is going to do the development on the code going forward its a hassle. At least with methods you can press CTRL+M CTRL+O to collapse all.

Collapse
 
davidisnotnull profile image
David Johnson

I can see the horror show that regions can represent if they're used with abandon, but I do occasionally find some uses. If I need a couple of private methods to handle functionality in a class, then I'd create a region called "Private Methods" at the bottom so I can separate out the public and private sections.

Collapse
 
scotthannen profile image
Scott Hannen

Those are good rules, although I'd be way more restrictive. Yes, they are arbitrary numbers. They are pulled from thin air. I prefer no more than 15 lines per method.
Those arbitrary limits are important. If you can't have a 30 line method then you can't have a 200 line method.

Collapse
 
rachelsoderberg profile image
Rachel Soderberg • Edited

You make a good point! I would definitely keep all of the customer logic methods in one class. Made up rules for the sake of making up rules can be silly.

Collapse
 
lexruster profile image
Alexander

Looks like to late for comment. Any plain structure with dozens of child of the same rang is hard to maintain, navigate. It is not only about methods in the class. It is about everything. Like UI with 100 buttons. You want to group it. Almost everything can be grouped. So even this CustomerLogic can be decomposed. May be to
CustomerOrderLogic
CustomerAccountLogic. Need real examples.

Thread Thread
 
rachelsoderberg profile image
Rachel Soderberg

Never too late! And you are absolutely right, it could be broken even further into more refined classes that only perform one job. I love that you mentioned this point, because I am definitely still learning and appreciate any holes in my knowledge being pointed out.

Collapse
 
kubiak200 profile image
Alex

Regions should have another background color,
closing the code is horrible

Collapse
 
rachelsoderberg profile image
Rachel Soderberg

It would be nice if regions had a slightly different back color, you make a great point! Even if it were just a slightly off-grey to set them apart from the rest of the code. I've found myself overlooking a region because it just didn't catch my eye well enough at first glance.