The never-ending quest to enhance the quality of our code and improve its readability, maintainability, and performance has produced a number of architectural and design principles over the years. The DRY (“Don’t repeat yourself”), YAGNI (“You’re not gonna need it”), and KISS (“Keep it simple, stupid”) principles are three we should all keep in mind when we code.
These three acronyms represent concepts that can help streamline your development process as well as make your code simpler, cleaner, and more maintainable. We will examine these three principles here as well as learn how they can be applied to the code of your .NET applications.
To work with the code examples provided in this article, you should have Visual Studio 2022 installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 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 2022 is installed in your system, follow the steps outlined below to create a new .NET Core console application project.
- 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 Next.
- In the “Additional information” window, choose “.NET 7.0 (Standard Term Support)” as the framework version you would like to use.
- Click Create.
We’ll use this .NET 7 console application project to work with code examples of the DRY, YAGNI, and KISS principles in the subsequent sections of this article.
The DRY principle
In software development, the “Don’t repeat yourself” principle means you should avoid the duplication of code in your application. DRY emphasizes easing the maintainability of your application’s source code across all stages of the application’s lifecycle. Adhering to this principle would ensure that altering the code in one location would automatically update every occurrence of that code throughout the application.
The DRY principle encourages developers to write code that is clean, modular, and reusable. Modularity can help in making changes and additions to the application more efficient and seamless, with less risk of errors creeping into the system.
DRY can be applied to all aspects of your software development process including code, configuration files, documentation, and the user interface. It can help developers reduce the amount of code they need to write and maintain and eliminate code redundancies, leading to fewer defects and a more effective use of resources.
The DRY principle may be used to enhance collaboration among developers and to teach new developers how to contribute to an existing code base more successfully, in addition to enhancing the quality and maintainability of the code.
Implementing the DRY principle in C#
You can implement the DRY principle in C# in the following ways:
- Using methods: Methods implement the DRY principle by allowing you to centralize code that will be used in multiple parts of your application. It is often easier to move the code that is repeated in multiple places into a method and call it from everywhere. Any required changes can be done at a single location in your code base.
- Using classes and inheritance: When lines of code are spread across many classes and methods, they can be relocated to a parent class, which all of the derived classes can then inherit. This approach ensures that modifications to the code can be made in a single location rather than in each separate class that extends the base class.
- Using interfaces: Code shared across classes without a common base class may be moved into an interface and implemented by the relevant classes. In this way, the code will be shared throughout all types, such that if you ever need to modify the code, you only have to update the interface.
The following code snippet illustrates how you can implement the DRY principle using methods. Note how the AddIntegers method has been reused.
class Program { static void Main(string[] args) { int a = 5; int b = 10; int x = 10; int y = 20; // Calling the AddIntegers method twice int s1 = AddIntegers(a, b); int s2 = AddIntegers(x, y); Console.WriteLine($"Sum of a and b is: {s1}, " + $"Sum of x and y is: {s2}"); Console.ReadKey(); } static int AddIntegers(int num1, int num2) { return num1 + num2; } }
This is a good example of the DRY principle because we avoided duplicating the code to add two numbers and instead created a reusable method that can be called multiple times with different parameters.
The KISS principle
In the context of software architecture and design, the “Keep it simple, stupid” principle advocates more straightforward solutions over complex ones because they are easier to comprehend, utilize, and maintain over time. This principle aims to encourage simplicity in the design and function of applications, products, and services.
You can apply the KISS principle to all aspects of software development from the application architecture to the user interface design. Its core idea involves steering clear of unnecessary complexity and instead prioritizing simplicity and making the simplest solution possible that effectively fulfills the needs of the user or the task at hand.
KISS is an important principle in engineering generally. Kelly Johnson initially employed the KISS principle to emphasize the importance of simple aircraft designs. Over time, this principle attained immense popularity, gaining recognition as a guiding tenet for diverse problems ranging from design to problem solving in software applications.
Implementing the KISS principle in C#
Consider the following two methods. The first method returns the month name as a text string using a Switch-Case construct. The second method achieves the same using an If-Else construct. Can you tell which is the KISS method?
public static string GetMonthNameUsingSwitchCase(int number) { switch (number) { case 1: return "January"; case 2: return "February"; case 3: return "March"; case 4: return "April"; case 5: return "May"; case 6: return "June"; case 7: return "July"; case 8: return "August"; case 9: return "September"; case 10: return "October"; case 11: return "November"; case 12: return "December"; default: throw new InvalidOperationException(); } }
public static string GetMonthNameUsingIfElse(int number) { if ((number < 1) || (number > 12)) throw new InvalidOperationException(); string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return months[number - 1]; }
As you can see here, the method that uses a Switch-Case construct is much simpler and easier to understand.
The YAGNI principle
The YAGNI or “You ain’t gonna need it” principle implies that you should only implement functionality after you need it. The YAGNI principle says unnecessary code adds complexity and makes the system harder to understand, test, and maintain. It’s easier to manage a streamlined and efficient application, so only implement the features you need.
The YAGNI principle is closely related to the Agile software development methodology, which emphasizes delivering working software quickly and regularly. Focusing on the most critical features and delivering them early on will allow developers to get frequent feedback from stakeholders, adjust their plans, and continuously improve the application.
The YAGNI principle doesn’t discourage planning or forethought but encourages developers to focus on the essentials and avoid adding features they won’t use. Developers should also avoid “gold plating” their code, adding unnecessary complexity for the sake of perfection.
Implementing the YAGNI principle in C#
The following code snippet provides an example of the YAGNI principle. Do you see why?
class Author { private string _firstName; private string _lastName; public Author(string firstName, string lastName) { _firstName = firstName; _lastName = lastName; } public string GetAuthorName() { return $"{_firstName} {_lastName}"; } } class Program { static void Main(string[] args) { Author author = new Author("Joydip", "Kanjilal"); Console.WriteLine($"Full name: {author.GetAuthorName()}"); } }
In this example, the Author class follows the YAGNI principle of implementing minimal functionality. For this simple example, we have considered only two attributes of the Author entity, i.e. the first name and last name.
We have not implemented unnecessary characteristics like age, address, or telephone number. We may implement these attributes later, if we discover we have a use for them. In the meantime, we adhere to the YAGNI principle by not implementing unnecessary features and avoiding code bloat—additional features that may make the code harder to comprehend, use, and maintain.
By applying the DRY, KISS, and YAGNI principles, we can build better applications and make developers more productive. We can create better software that is simpler to understand and maintain over time if we minimize duplication of effort, keep our code as simple as possible, and eliminate extraneous features.