DEV Community

Cover image for Clean Code in C# Part 8 Classes
Caio Cesar
Caio Cesar

Posted on

Clean Code in C# Part 8 Classes

Introduction

A class in C# is considered a referenced type, within classes one can create Properties, Methods, Constructors, and other components available within the programing language. Developers can create several methods in a class however, a concrete class cannot be created within a method in C#. Therefore, classes are a level higher than methods and of extreme importance to clean code.

Class Organization

It is recommended to maintain minimal class organization when it comes to ordering the elements that composes a class. This consistency should be applied throughout all projects within an organization. When ordering elements in a class one could consider the order:

  1. Constants
  2. Variables
  3. Properties
  4. Constructor
  5. Methods
    • 5-1. Public Methods
    • 5-2. Protected Methods
    • 5-3. Private Methods

I have not found any official rules or recommendations for ordering elements in C# code, but keeping a consistent order between classes in a project or solution is wise.

Class Size

Classes should be small, however to measure the size of a class, lines of code is not the only concern, the responsibilities should also be considered. Giving meaningful names to classes helps one to describe the responsibilities it has. Some names makes classes seem like it has generic or too much responsibility, as described in the following example:

Example 1:


public class PageManager{}

public class MasterTab{}

public class SuperAlgorithm{}

Enter fullscreen mode Exit fullscreen mode

The SRP is part of the 'S' in the SOLID principles that composes of good practices in object oriented programing. It states that modules including classes should have single responsibility and only one reason to change. However it is common to see this principle violated. Uncle Bob states that

writing code that executes is not the same as developing clean code.

Dependency Inversion Principle (DIP)

In Object Oriented Programing (OOP), concrete classes contains implementation details and interfaces that includes the definitions of the services within a group.

Checkout the following code taken from the NLOG library, it has an example of a concrete implementation of the logging:

Example 2:

using NLog.Web;
using Microsoft.Extensions.Logging;

public static void Main(string[] args)
{
    // NLog: setup the logger first to catch all errors
    var logger = NLog.LogManager.Setup().RegisterNLogWeb().GetCurrentClassLogger();

    try
    {
        logger.Debug("init main");
        CreateWebHostBuilder(args).Build().Run(); 
    }
    catch (Exception ex)
    {
        //NLog: catch setup errors
        logger.Error(ex, "Stopped program because of exception");
        throw;
    }
    finally
    {
        // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
        NLog.LogManager.Shutdown();
    }
}
Enter fullscreen mode Exit fullscreen mode

As displayed in Example 2, to depend on concrete implementations one would could setup a new instance of a logger every time it needs to be used. However NLog provides abstractions where Dependency injection can be configured as seen in the following code:

Example 3:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureLogging(logging =>
        {
            logging.ClearProviders();
            logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
        })
        .UseNLog();  // NLog: setup NLog for Dependency injection
Enter fullscreen mode Exit fullscreen mode
using Microsoft.Extensions.Logging;

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;

    public HomeController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    public IActionResult Index()
    {
        _logger.LogInformation("Index page says hello");
        return View();
    }
}
Enter fullscreen mode Exit fullscreen mode

In Example 3 the Microsoft extension logging library injects the NLOG implementations. The power of this implementation is that it is easy to change logging technologies and its loosely coupled because the implementation does not depend on concrete implementation in this case NLOG it uses a generic logging interface.

Conclusion

When creating classes think about the impacts the class you are creating can have on the overall system. Creating abstractions such as interfaces is a good idea if the implementation details may change in the future. It also provides better testing functionalities where one could mock the abstractions.

References

  1. Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin.
  2. https://github.com/NLog/NLog/wiki/Getting-started-with-ASP.NET-Core-2

Discussion (0)