Table of Contents

Non-SOLID Single Responsibility Principle (non-SRP)

The non-SOLID Single Responsibility Principle (SRP) is often confused with the SOLID SRP. While both principles sound similar, they have different meanings.

non-SOLID SRP:

"The function should do one thing and only one thing."

This principle is violated when a function becomes a "God" function and can perform many semanticaly unrelated tasks.

Example

The PrepareReport function performs multiple tasks. It downloads report.json from the server, deserializes it, and creates a report with HTML text.

void Main() {
    Console.WriteLine(PrepareReport());
}

async Task<string> PrepareReport() {
    // Initialize settings
    var uri = new Uri("https://.../report.json");
    HttpClient client = new ();

    // Download and deserialize json
    Info? info = await client.GetFromJsonAsync<Info>(uri) ?? throw new NullReferenceException("json is invalid");

    // Prepare report
    return $"""
        <h1>{info.Title}</h1>
        <p>{info.Content}</p>
        """;
}

record Info(string Title, string Content);

"God" functions are difficult to maintain and extend with new functionality. A small change to the code can potentially break subfunctions.

Improvements

To adhere to the non-SOLID SRP, the function should be divided into multiple functions.

void Main()
{
    var settings = InitSettings();
    Console.WriteLine(PrepareReport(settings.Uri, settings.Client));
}

// Initialize settings
(HttpClient Client, Uri Uri) InitSettings()
{
    var uri = new Uri("https://.../report.json");
    HttpClient client = new();

    return (client, uri);
}

// Depending on Settings, prepare a report
async Task<string> PrepareReport(Uri uri, HttpClient client)
{
    Info info = await DownloadInfo(uri, client);

    var report = CreateReport(info);

    return report;
}

// Downloads Info DTO
async Task<Info> DownloadInfo(Uri uri, HttpClient client)
{
    ArgumentNullException.ThrowIfNull(uri, nameof(uri));
    ArgumentNullException.ThrowIfNull(client, nameof(client));

    var json = await client.GetFromJsonAsync<Info>(uri) ?? throw new NullReferenceException("json is invalid");

    return json;
}

// Creates HTML report from Info DTO
string CreateReport(Info info)
{
    ArgumentNullException.ThrowIfNull(info, nameof(info));

    return $"""
        <h1>{info.Title}</h1>
        <p>{info.Content}</p>
        """;
}

record Info(string Title, string Content);

The code became less coupled, functions are smaller, independent, and easier to modify.