Book Image

Enterprise Application Development with C# 9 and .NET 5

By : Rishabh Verma, Ravindra Akella, Arun Kumar Tamirisa, Suneel Kumar Kunani, Bhupesh Guptha Muthiyalu
Book Image

Enterprise Application Development with C# 9 and .NET 5

By: Rishabh Verma, Ravindra Akella, Arun Kumar Tamirisa, Suneel Kumar Kunani, Bhupesh Guptha Muthiyalu

Overview of this book

.NET Core is one of the most popular programming platforms in the world for an increasingly large community of developers thanks to its excellent cross-platform support. This book will show you how to confidently use the features of .NET 5 with C# 9 to build robust enterprise applications. Throughout the book, you'll work on creating an enterprise app and adding a key component to the app with each chapter, before ?nally getting it ready for testing and deployment. You'll learn concepts relating to advanced data structures, the Entity Framework Core, parallel programming, and dependency injection. As you progress, you'll cover various authentication and authorization schemes provided by .NET Core to make your apps and APIs secure. Next, you'll build web apps using ASP.NET Core 5 and deploy them on the cloud while working with various cloud components using Azure. The book then shows you how to use the latest Microsoft Visual Studio 2019 and C# 9 to simplify developer tasks, and also explores tips and tricks in Visual Studio 2019 to improve your productivity. Later, you'll discover various testing techniques such as unit testing and performance testing as well as di?erent methods to deploy enterprise apps. By the end of this book, you’ll be able to create enterprise apps using the powerful features of .NET 5 and deploy them on the cloud.
Table of Contents (24 chapters)
1
Section 1: Architecting an Enterprise Application and its Fundamentals
5
Section 2: Cross-Cutting Concerns
11
Section 3: Developing Your Enterprise Application
15
Section 4: Security
18
Section 5: Health Checks, Unit Testing, Deployment, and Diagnostics

A primer on common design principles and patterns

Every piece of software in the world solves one real-world problem or another. As time goes by, things change, including what we expect from any specific software. To manage this change and deal with various aspects of software, engineers have developed a number of programming paradigms, frameworks, tools, techniques, processes, and principles. These principles and patterns, proven over time, have become guiding stars for engineers to use to collaborate and build quality software.

We will be discussing object-oriented programming (OOP) in this chapter, a paradigm based on the concepts of "objects" and their states, behaviors, and interactions with each other. We will also cover some common design principles and patterns.

Principles are high-level abstract guidelines to be followed while designing; they are applicable regardless of the programming language being used. They do not provide implementation guidelines.

Patterns are low-level specific implementation guidelines that are proven, reusable solutions for recurring problems. Let's first start with design principles.

Design principles

Techniques become principles if they are widely accepted, practiced, and proven to be useful in any industry. Those principles become solutions to make software designs more understandable, flexible, and maintainable. We will cover the SOLID, KISS, and DRY design principles in this section.

SOLID

The SOLID principles are a subset of many principles promoted by American software engineer and instructor Robert C. Martin. These principles have become de facto standard principles in the OOP world and have become part of the core philosophy for other methodologies and paradigms.

SOLID is an acronym for the following five principles:

  1. Single responsibility principle (SRP): An entity or software module should only have a single responsibility. You should avoid granting one entity multiple responsibilities:
    Figure 1.1 – SRP

    Figure 1.1 – SRP

  2. Open-closed principle (OCP): Entities should be designed in such a way that they are open for extension but closed for modification. This means regression testing of existing behaviors can be avoided; only extensions need to be tested:
    Figure 1.2 – OCP

    Figure 1.2 – OCP

  3. Liskov substitution principle (LSP): Parent or base class instances should be replaceable with instances of their derived classes or subtypes without altering the sanity of the program:
    Figure 1.3 – LSP

    Figure 1.3 – LSP

  4. Interface segregation principle (ISP): Instead of one common large interface, you should plan multiple, scenario-specific interfaces for better decoupling and change management:
    Figure 1.4 – ISP

    Figure 1.4 – ISP

  5. Dependency inversion principle (DIP): You should avoid having any direct dependency on concrete implementations. High-level modules and low-level modules should not depend on each other directly, and instead, both should depend on abstractions as much as possible. Abstraction should not depend on details and details should depend on abstractions.
Figure 1.5 – DIP

Figure 1.5 – DIP

Don't repeat yourself (DRY)

With DRY, a system should be designed in such a way that the implementation of a feature or a pattern should not be repeated in multiple places. This would result in maintenance overhead as a change in requirements would result in modification being needed at multiple places. If you fail to make a necessary update in one place by mistake, the behavior of the system will become inconsistent. Rather, the feature should be wrapped into a package and should be reused in all places. In the case of a database, you should look at using data normalization to reduce redundancy:

Figure 1.6 – DRY

Figure 1.6 – DRY

This strategy helps in reducing redundancy and promoting reuse. This principle helps an organization's culture as well, encouraging more collaboration.

Keep it simple, stupid (KISS)

With KISS, a system should be designed as simply as possible, avoiding complicated designs, algorithms, new untried technologies, and so on. You should focus on leveraging the right OOP concepts and reusing proven patterns and principles. Include new or non-simple things only if it is necessary and adds value to the implementation.

When you keep it simple, you will be able to do the following better:

  • Avoid mistakes while designing/developing
  • Keep the train running (there is always a team whose job is to maintain the system, although they are not the team that developed the system in the first place)
  • Read and understand your system and code (your system and code need to be understandable to people new to it or people using it far in the future)
  • Do better and less error-prone change management

With this, we are done with our primer on common design principles; we have learned about SOLID, DRY, and KISS. In the next section, we'll look at some common design patterns in the context of real-world examples to help you understand the difference between principles and patterns and when to leverage which pattern, a skill that's essential for good design and architecture.

Design patterns

While following design principles in the OOP paradigm, you may see the same structures and patterns repeating over and again. These repeating structures and techniques are proven solutions to common problems and are known as design patterns. Proven design patterns are easy to reuse, implement, change, and test. The well-known book Design Patterns: Elements of Reusable Object-Oriented Software, comprising what are known as the Gang of Four (GOF) design patterns, is considered as the bible of patterns.

We can categorize the GOF patterns as follows:

  • Creative: Helpful in creating objects
  • Structural: Helpful in dealing with the composition of objects
  • Behavioral: Helpful in defining the interactions between objects and distributing responsibility

Let's look at the patterns with some real-life examples.

Creational design patterns

Let's have a look at some creational design patterns along with relevant examples in the following table:

Table 1.1

Table 1.1

Structural design patterns

The following table includes some examples of structural design patterns:

Table 1.2

Table 1.2

Behavior design patterns

The following table includes some examples of behavioral design patterns:

Table 1.3

Table 1.3

Sometimes, you can become overwhelmed by all these patterns being on the table, but really, any design is a good design until it violates the basic principles. One rule of thumb that we can use is to go back to basics, and in design, principles are the basics.

Figure 1.7 – Pattern versus principles

Figure 1.7 – Pattern versus principles

With this, we are done with our primer on common design principles and patterns. By now, you should have a good understanding of the different principles and patterns, where to use them, and what it takes to build a great solution. Let's now spend some time looking at common enterprise architectures.