🙏Thoughts & Prayers

The Class That Does Everything (Except Follow SOLID)

TL;DR: God class violates Single Responsibility by handling connections, validation, logging, and control in one place.

#solid#csharp#single-responsibility#god-class

The Code

csharp
1using System;
2using System.Collections.Generic;
3using System.Linq;
4
5namespace PowerPointToOBSSceneSwitcher
6{
7    public class ObsLocal : IDisposable
8    {
9        private bool _DisposedValue;
10        private ObsWebSocket _OBS;
11        private List<string> validScenes;
12        private string defaultScene;
13
14        public string DefaultScene
15        {
16            get { return defaultScene; }
17            set
18            {
19                if (validScenes.Contains(value))
20                {
21                    defaultScene = value;
22                }
23                else
24                {
25                    Console.WriteLine($"Scene named {value} does not exist and cannot be set as default");
26                }
27            }
28        }
29
30        public bool ChangeScene(string scene)
31        {
32            if (!validScenes.Contains(scene))
33            {
34                Console.WriteLine($"Scene named {scene} does not exist");
35                if (String.IsNullOrEmpty(defaultScene))
36                {
37                    Console.WriteLine("No default scene has been set!");
38                    return false;
39                }
40                scene = defaultScene;
41            }
42            _OBS.Api.SetCurrentScene(scene);
43            return true;
44        }
45
46        public bool StartRecording()
47        {
48            try { _OBS.Api.StartRecording(); }
49            catch {  /* Recording already started */ }
50            return true;
51        }
52
53        // ... (additional code omitted)
54    }
55}
56
57*(Excerpt from larger file - showing relevant section only)*
58
59

The Prayer 🙏

🙏 Dear SOLID principles, please forgive this class that's trying to be a Swiss Army knife in a world that needs specialized tools. We promise we'll stop making our OBS wrapper also handle scene validation, default management, error logging, and probably our morning coffee routine too.

The Reality Check

This ObsLocal class is a textbook violation of the Single Responsibility Principle, juggling connection management, scene validation, default scene handling, recording control, and console logging all in one place. When any of these responsibilities need to change - say you want to log to a file instead of console, or add authentication to the connection - you're forced to modify this monolithic class.

The tight coupling makes testing a nightmare. Want to unit test the scene validation logic? Good luck mocking out the OBS WebSocket connection. Need to test recording functionality? Hope you enjoy setting up the entire scene management infrastructure first. This design makes your code brittle and your future self will curse your name when trying to add new features.

In production, this becomes a maintenance bottleneck where every feature request touches this God class. The catch-all exception handling (catch { /* Recording already started */ }) masks real errors, and the mixed concerns make it impossible to reason about what might break when you change seemingly unrelated functionality.

The Fix

The solution is to break this monolith into focused, single-responsibility classes following SOLID principles. Start by separating the core OBS connection from the business logic:

csharp
1public interface IObsConnection
2{
3    Task ConnectAsync();
4    void SetCurrentScene(string sceneName);
5    void StartRecording();
6    void StopRecording();
7    IEnumerable<string> GetSceneNames();
8}
9
10public class ObsWebSocketConnection : IObsConnection, IDisposable
11{
12    private ObsWebSocket _obs;
13    
14    public async Task ConnectAsync()
15    {
16        _obs = new ObsWebSocket();
17        _obs.Connect("ws://127.0.0.1:4444", "");
18    }
19    
20    public void SetCurrentScene(string sceneName) => _obs.Api.SetCurrentScene(sceneName);
21    // ... other methods
22}
23

Next, create a dedicated scene manager that handles validation and defaults:

csharp
1public class SceneManager
2{
3    private readonly IObsConnection _connection;
4    private readonly ILogger _logger;
5    private List<string> _validScenes;
6    private string _defaultScene;
7    
8    public SceneManager(IObsConnection connection, ILogger logger)
9    {
10        _connection = connection;
11        _logger = logger;
12    }
13    
14    public async Task<bool> ChangeSceneAsync(string sceneName)
15    {
16        if (!_validScenes.Contains(sceneName))
17        {
18            _logger.LogWarning($"Scene {sceneName} not found, using default");
19            sceneName = _defaultScene ?? throw new InvalidOperationException("No default scene set");
20        }
21        
22        _connection.SetCurrentScene(sceneName);
23        return true;
24    }
25}
26

Finally, compose these focused components in a facade or service class that provides a clean API while keeping responsibilities separate. This approach makes each component testable, maintainable, and follows the Open/Closed Principle - you can extend behavior without modifying existing code.

Lesson Learned

A class that does everything well usually does everything poorly - embrace single responsibility and your future debugging sessions will thank you.