jingkecn/blog

[C#] How To: Use `partial` Keyword To Improve Our Codebase

jingkecn opened this issue · 0 comments

Problematic

There's always an epic subject of our codebase, when coding in the OOP way, on how to find the balance between the total code lines of a class and the quantity of classes.

When there're too many code lines in a single class, let's say 10K lines for example, you could find it annoying to scroll your source file from top to bottom and vice versa. That's to say, the class is not well designed and it lacks of abstraction, you just put pieces together in this class. A common way to improve our code in this case seems quite straight, it's to either split or encapsulate implementations into several classes, which results in an increment of the quantity of classes.

When there're too many classes in our project, let's say 10M for example, you could also get frustrated to navigate among them, especially when you're reading the codebase or trying to find some APIs somewhere, it's called over-abstraction. So what's next? You're going to regroup them to reduce the quantity of classes?

Analysis

So let's do some math here, by taking the following example:

// MyClass.cs
class MyClass : IMyInterface1, IMyInterface2, ..., IMyInterfaceN
{
}

Let's assume:

  1. MyClass implements N interfaces;
  2. Each interface IMyInterface{K} defines x APIs in average;
  3. Each API requires y code lines in average.

So how many code lines in total are required in MyClass for all API implementations?
It's simple:

$Total = x * y * N$

So if x = 10, y = 100 and N = 10, for example, you will get at least 10K lines in you codebase for MyClass.

The total lines of the codebase depends on 3 variables: x, y and N.
Let's observe them one by one, and find out which variables are stable and which are not.

First of all, N, the number of interfaces to implement.
I would say the value of N is undecided, you'll never know how many interfaces you are should implement along with the evolution of the codebase, so it's an unstable variable that we are not quit sure of its final value.

Then x, the number of APIs that an interface defines.
A well-designed interface, by intuition, is supposed to have a stable number of its APIs, and should not be changed frequently, so let's say, x is definitely stable.

At last, y, the number of code lines that we have to implement an API (method, property, etc.).
This is not easy to see. But as a good practice, we should not have a method with more than 100 lines, so let's say y could a variable with an upper limit.

Therefore, the total lines of MyClass approximates to linearity with N.

Solution

In C#, we can split a class into multiple source files by using the partial keyword.

// MyClass.IMyInterface1.cs
partial class MyClass : IMyInterface1
{
}

// MyClass.IMyInterface2.cs
partial class MyClass : IMyInterface2
{
}

...
// MyClass.IMyInterfaceN.cs
partial class MyClass : IMyInterfaceN
{
}

So there would be x*y lines in average per source file, which results in a relatively stable total number of code lines in each source file.

Moreover, we can also benefit more from this pattern, as is stated in the Microsoft Docs: When working on large projects, spreading a class over separate files enables multiple programmers to work on it at the same time, it's desirable to split a class definition.