Wednesday, July 22, 2015

Visual Studio code regions

The Visual Studio IDE allows user-defined regions to easily expand / collapse sections of code.
#region "public methods"
public void Add(int x, int y)
{
  
}

public void Subtract(int x, int y)
{

}
#endregion
When this feature was introduced, I was a proponent of using regions to organize code, and would create sections for fields, properties, public methods, private methods, etc. Over the years, I've changed my mind about using regions and no longer recommend them.

If my classes are large enough that adding regions to show/hide relevant sections is helpful, that is a good indication that my class is probably too large. The Single Responsibility Principle of SOLID suggests that a class should only have one reason to change. A class that only has one reason to change is usually going to be a small class. If the entire class can be viewed in one or two screens / pages of code, the need for regions is eliminated, or at least greatly reduced.

Even if you don't agree with the benefits of smaller classes, another reason against grouping sections of code by scope is that it is not particularly productive. Consider the following (admittedly, contrived) example of methods grouped by scope (public methods on top, private methods on the bottom)
#region "public methods"
public void Insert(Order order)
{
  InsertOrder(order);
  InsertLineItems(order);
  UpdateInventory(order);
  UpdateAccountsReceivable(order);
}

public void Update(Order order)
{
  UpdateOrder(order);
  UpdateLineItems(order);
  UpdateInventory(order);
  UpdateAccountsReceivable(order);
}

#endregion

#region "private methods"

private void InsertOrder(Order order)
{
  //Insert the order
}

private void InsertLineItems(Order order)
{
  //Insert order line items
}

private void UpdateInventory(Order order)
{
  //Update inventory
}

private void UpdateAccountsReceivable(Order order)
{
  //Update accounting information
}

private void UpdateOrder(Order order)
{
  //Update the order
  InsertLineItems(order);
  UpdateLineItems(order);
  DeleteLineItems(order.LineItems);
}

private void UpdateLineItems(Order order)
{
  //Update order line items
}

private void DeleteLineItems(LineItems items)
{
  //Delete order line items
}

#endregion
Again, this is a contrived example, but it illustrates the issue with grouping by scope. Attempting to debug the Update method at the top would require a fair amount of scrolling to view the private methods at the bottom, especially if any of the methods are large. That makes it harder to remember the context of the currently executing code. If the public/private regions were removed and the methods were rearranged to be closer based on functionality rather than scope, debugging is easier because more relevant code can fit on the screen at the same time.

Some may suggest surrounding the groups of methods in regions after they have been rearranged by functionality. In that case I would suggest taking the extra step and refactoring that functionality into its own class. With the prevalence of multiple widescreen monitors, displaying the relevant code across multiple monitors is more productive than splitting a single class in the same window/tab and continually scrolling up and down among the relevant methods.

No comments:

Post a Comment