Follow these best practices to eliminate God objects and design classes that are loosely coupled, cohesive, and easy to maintain Credit: geralt In object-oriented programming (OOP), so-called God objects are an anti-pattern because they violate a number of good design principles. God objects are objects of classes that know too much or do too much, and hence make your code tightly coupled and difficult to maintain. This article talks about this anti-pattern and how you can get rid of it. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. Create a console application project in Visual Studio First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed. Click Next. In the “Configure your new project” window shown next, specify the name and location for the new project. Click Create. This will create a new .NET Core console application project in Visual Studio 2019. We’ll use this project in the subsequent sections of this article. What is a God object? Writing code without following the best practices might lead to code that is hard to debug, extend, and maintain over time. Object-oriented programming has become extremely popular over the past few decades because it is adept at helping you to eliminate poorly written code from your application. However, anti-patterns might often emerge if you take shortcuts and your primary objective is getting the task done rather than getting it done the right way. Whereas a design pattern is a proven solution to a common design problem in software development, an anti-pattern is an ineffective pattern that shows us how not to solve a problem, because doing so would result in poor design. In other words, an anti-pattern is a common solution to a given problem that can have negative consequences — a solution that is ineffective or counterproductive in practice. A God object is one such anti-pattern. A God object contains cluttered code that is difficult to maintain, extend, use, test, and integrate with other parts of the application. God objects violate the single responsibility principle and the Law of Demeter. I will discuss the single responsibility principle below. The Law of Demeter, or principle of least knowledge, reduces dependencies between classes and helps build components that are loosely coupled. Here is a list of the characteristics of a God object: Too many functions in a class Knows too much about the application and can interact with all the data Difficult to maintain over time because changes to the class of the God object typically introduce problems or side effects Extremely complicated since it maintains the state of most of the application God objects and the single responsibility principle When multiple responsibilities are assigned to a single class, the class violates the single responsibility principle. Again, such classes are difficult to maintain, extend, test, and integrate with other parts of the application. The single responsibility principle states that a class (or subsystem, module, or function) should have one and only one reason for change. If there are two reasons for a class to change, the functionality should be split into two classes with each class handling one responsibility. Some of the benefits of the single responsibility principle include orthogonality, high cohesion, and low coupling. A system is orthogonal if changing a component changes the state of that component only, and doesn’t affect other components of the application. In other words, the term orthogonality means that operations change only one thing without affecting other parts of the code. Coupling is defined as the degree of interdependence that exists between software modules and how closely they are connected to each other. When this coupling is high, then the software modules are interdependent, i.e., they cannot function without each other. Cohesion denotes the level of intra-dependency among the elements of a software module. In other words, Cohesion is a measure of the degree to which the responsibilities of a single module or a component form a meaningful unit. God object example in C# The solution to the God object anti-pattern is to split related functionality into smaller and more manageable classes — i.e., to design classes that have strong cohesion and are loosely coupled with one another. Let’s dig into some code to understand the God object anti-pattern better. Let’s say you are building a recruitment management system. Create the following class in the Program.cs file. public class Candidate { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } public DateTime InterviewDate { get; set; } public int RecruiterId { get; set; } public string Recruiter { get; set; } public int InterviewerId { get; set; } public string Interviewer { get; set; } public string InterviewerRemarks { get; set; } public decimal CurrentSalary { get; set; } public decimal ExpectedSalary { get; set; } } The Candidate class shown here contains several properties that shouldn’t be part of it. In essence, this class is doing too many things, and thus violates the single responsibility principle. This is a good example of a God object. In other words, an instance of the Candidate class is a God object because it contains too much information. Refactor a God object in C# To fix a God object problem, you can follow these steps: Create unit tests. Create a comprehensive unit test suite before you start refactoring the classes. This would help you to know if any functionality in the application is broken due to a change. Group related methods and properties. Group the common methods and properties in a class while keeping the classes loosely coupled. Divide large classes and methods. If classes or methods have a lot of code or functionality in them, break them into simple, manageable, testable classes and methods. Remove the God object. Finally, delete or deprecate the God object. Referring back to our example above, what if there are multiple rounds of interviews and each of those rounds are taken by a different interviewer? The current version of the Candidate class wouldn’t be able to support this. Let’s now refactor this class to make it simple, testable, and more manageable. The following code snippet illustrates the new version of the Candidate class. Note that the new Candidate class contains information pertaining to the candidate only. public class Candidate { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string Address { get; set; } public decimal CurrentSalary { get; set; } public decimal ExpectedSalary { get; set; } } The Recruiter and Interviewer classes are given below. public class Recruiter { public int RecruiterId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } public class Interviewer { public int InterviewerId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } } Finally, the Interview class contains the candidate, the recruiter, and other information related to the interview as shown below. public class Interview { public int Id { get; set; } public int CandidateId { get; set; } public int RecruiterId { get; set; } public DateTime InterviewDate { get; set; } public string InterviewerRemarks { get; set; } } And that’s it! If a candidate attends several rounds of interviews, then you might want to create multiple instances of the Interview class. That would suffice for storing candidate information for multiple interview rounds. God objects are common in poorly designed systems. The solution is to refactor either the source code or the design or both, and create types (classes, structs, and interfaces) that are highly cohesive and loosely coupled. Despite all of its pitfalls, a God object is a good design choice in micro-controllers because centralized control is of utmost importance rather than flexibility and ease of maintenance. How to do more in C#: How to use ValueTask in C# How to use immutability in C How to use const, readonly, and static in C# How to use data annotations in C# How to work with GUIDs in C# 8 When to use an abstract class vs. interface in C# How to work with AutoMapper in C# How to use lambda expressions in C# How to work with Action, Func, and Predicate delegates in C# How to work with delegates in C# How to implement a simple logger in C# How to work with attributes in C# How to work with log4net in C# How to implement the repository design pattern in C# How to work with reflection in C# How to work with filesystemwatcher in C# How to perform lazy initialization in C# How to work with MSMQ in C# How to work with extension methods in C# How to us lambda expressions in C# When to use the volatile keyword in C# How to use the yield keyword in C# How to implement polymorphism in C# How to build your own task scheduler in C# How to work with RabbitMQ in C# How to work with a tuple in C# Exploring virtual and abstract methods in C# How to use the Dapper ORM in C# How to use the flyweight design pattern in C# Related content feature 14 great preprocessors for developers who love to code Sometimes it seems like the rules of programming are designed to make coding a chore. Here are 14 ways preprocessors can help make software development fun again. By Peter Wayner Nov 18, 2024 10 mins Development Tools Software Development feature Designing the APIs that accidentally power businesses Well-designed APIs, even those often-neglected internal APIs, make developers more productive and businesses more agile. By Jean Yang Nov 18, 2024 6 mins APIs Software Development news Spin 3.0 supports polyglot development using Wasm components Fermyon’s open source framework for building server-side WebAssembly apps allows developers to compose apps from components created with different languages. By Paul Krill Nov 18, 2024 2 mins Microservices Serverless Computing Development Libraries and Frameworks news Go language evolving for future hardware, AI workloads The Go team is working to adapt Go to large multicore systems, the latest hardware instructions, and the needs of developers of large-scale AI systems. By Paul Krill Nov 15, 2024 3 mins Google Go Generative AI Programming Languages Resources Videos