Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Software Architecture with C# 9 and .NET 5

You're reading from   Software Architecture with C# 9 and .NET 5 Architecting software solutions using microservices, DevOps, and design patterns for Azure

Arrow left icon
Product type Paperback
Published in Dec 2020
Publisher Packt
ISBN-13 9781800566040
Length 700 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Gabriel Baptista Gabriel Baptista
Author Profile Icon Gabriel Baptista
Gabriel Baptista
Francesco Abbruzzese Francesco Abbruzzese
Author Profile Icon Francesco Abbruzzese
Francesco Abbruzzese
Arrow right icon
View More author details
Toc

Table of Contents (26) Chapters Close

Preface 1. Understanding the Importance of Software Architecture 2. Non-Functional Requirements FREE CHAPTER 3. Documenting Requirements with Azure DevOps 4. Deciding the Best Cloud-Based Solution 5. Applying a Microservice Architecture to Your Enterprise Application 6. Azure Service Fabric 7. Azure Kubernetes Service 8. Interacting with Data in C# – Entity Framework Core 9. How to Choose Your Data Storage in the Cloud 10. Working with Azure Functions 11. Design Patterns and .NET 5 Implementation 12. Understanding the Different Domains in Software Solutions 13. Implementing Code Reusability in C# 9 14. Applying Service-Oriented Architectures with .NET Core 15. Presenting ASP.NET Core MVC 16. Blazor WebAssembly 17. Best Practices in Coding C# 9 18. Testing Your Code with Unit Test Cases and TDD 19. Using Tools to Write Better Code 20. Understanding DevOps Principles 21. Challenges of Applying CI Scenarios 22. Automation for Functional Tests 23. Answers 24. Another Book You May Enjoy
25. Index

Common cases where the requirements gathering process impacted system results

All the information discussed up to this point in the chapter is useful if you want to design software following the principles of good engineering. This discussion is not related to developing by using traditional or agile methods, but focuses on building software professionally or as an amateur.

It's also a good idea to know about some cases where failing to perform the activities you read about caused some trouble for the software project. The following cases intend to describe what could go wrong, and how the preceding techniques could have helped the development team to solve the problems.

In most cases, simple action could have guaranteed better communication between the team and the customer, and this easy communication flow would have transformed a big problem into a real solution. Let's examine three common cases where the requirements gathering impacted the results of performance, functionality, and usability.

Case 1 – my website is too slow to open that page!

Performance is one of the biggest problems that you as a software architect will deal with during your career. The reason why this aspect of any software is so problematic is that we do not have infinite computational resources to solve problems. Besides, the cost of computation is still high, especially if you are talking about software with a high number of simultaneous users.

You cannot solve performance problems by writing requirements. However, you will not end up in trouble if you write them correctly. The idea here is that requirements must present the desired performance of a system. A simple sentence, describing this, can help the entire team that works on the project:

Non-functional requirement: Performance – any web page of this software shall respond in at least 2 seconds, even when 1,000 users are accessing it concurrently.

The preceding sentence just makes everybody (users, testers, developers, architects, managers, and so on) sure that any web page has a target to achieve. This is a good start, but it's not enough. A great environment to both develop and deploy your application is also important. This is where .NET 5 can help you a lot; especially if you are talking about web apps, ASP.NET Core is considered one of the fastest options to deliver solutions today.

If you talk about performance, you, as a software architect, should consider the use of the techniques listed in the following sections together with specific tests to guarantee this non-functional requirement. It's also important to mention that ASP.NET Core will help you to use them easily, together with some Platform as a Service (PaaS) solutions delivered by Microsoft Azure.

Understanding caching

Caching is a great technique to avoid queries that can consume time and, in general, give the same result. For instance, if you are fetching the available car models in a database, the number of cars in the database can increase, but they will not change. Once you have an application that constantly accesses car models, a good practice is to cache that information.

It is important to understand that a cache is stored in the backend and that cache is shared by the whole application (in-memory caching). A point to focus on is that when you are working on a scalable solution, you can configure a distributed cache to solve it using the Azure platform. In fact, ASP.NET provides both, so you can decide on the one that bests fits your needs. Chapter 2, Non-Functional Requirements, covers scalability aspects in the Azure platform.

Applying asynchronous programming

When you develop ASP.NET applications, you need to keep in mind that your app needs to be designed for simultaneous access by many users. Asynchronous programming lets you do this simply, giving you the keywords async and await.

The basic concept behind these keywords is that async enables any method to run asynchronously. On the other hand, await lets you synchronize the call of an asynchronous method without blocking the thread that is calling it. This easy-to-develop pattern will make your application run without performance bottlenecks and better responsiveness. This book will cover more about this subject in Chapter 2, Non-Functional Requirements.

Dealing with object allocation

One very good tip to avoid a lack of performance is to understand how the Garbage Collector (GC) works. The GC is the engine that will free memory automatically when you finish using it. There are some very important aspects of this topic, due to the complexity that the GC has.

Some types of objects are not collected by the GC if you do not dispose of them. The list includes any object that interacts with I/O, such as files and streaming. If you do not correctly use the C# syntax to create and destroy this kind of object, you will have memory leaks, which will deteriorate your application performance.

The incorrect way of working with I/O objects is:

System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\sample.txt");
file.WriteLine("Just writing a simple line");

The correct way of working with I/O objects is:

using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\sample.txt"))
{
file.WriteLine("Just writing a simple line");
}

It might be worth noting that this correct approach also ensures the file gets written (it calls Flush). In the incorrect example, the contents might not even be written to the file. Even though the preceding practice is mandatory for I/O objects, it is totally recommended that you keep doing this in all disposable objects. Indeed, using code analyzers in your solutions with warnings as errors will prevent you from accidentally making these mistakes! This will help the GC and will keep your application running with the right amount of memory. Depending on the type of object, mistakes here can snowball, and you could end up with other bad things at scale, for instance, port/connection exhaustion.

Another important aspect that you need to know about is that the time spent by the GC to collect objects will interfere with the performance of your app. Because of this, avoid allocating large objects; otherwise, it can cause you trouble waiting for the GC to finish its task.

Getting better database access

One of the most common performance Achilles' heels is database access. The reason why this is still a big problem is the lack of attention while writing queries or lambda expressions to get information from the database. This book will cover Entity Framework Core in Chapter 8, Interacting with Data in C# – Entity Framework Core, but it is important to know what to choose and the correct data information to read from a database. Filtering columns and lines is imperative for an application that wants to deliver on performance.

The good thing is that best practices related to caching, asynchronous programming, and object allocation fit completely into the environment of databases. It's only a matter of choosing the correct pattern to get better-performance software.

Case 2 – the user's needs are not properly implemented

The more that technology is used in a wide variety of areas, the more difficult it is to deliver exactly what the user needs. Maybe this sentence sounds weird to you, but you must understand that developers, in general, study how to develop software, but they rarely study to deliver the needs of a specific area. Of course, it is not easy to learn how to develop software, but it is even more difficult to understand a specific need in a specific area. Software development nowadays delivers software to all possible types of industries. The question here is how can a developer, whether a software architect or not, evolve enough to deliver software in the area they are responsible for?

Gathering software requirements will help you in this tough task; writing them will make you understand and organize the architecture of the system. There are several ways to minimize the risks of implementing something different from what the user really needs:

  • Prototyping the interface to achieve an understanding of the user interface faster
  • Designing the data flow to detect gaps between the system and the user operation
  • Frequent meetings to be updated on the user's current needs and aligned to incremental deliveries

Again, as a software architect, you will have to define how the software will be implemented. Most of the time, you are not going to be the one who programs it, but you will always be the one responsible for this. For this reason, some techniques can be useful to avoid the wrong implementation:

  • Requirements are reviewed with the developers to guarantee that they understand what they need to develop.
  • Code inspection to validate a predefined code standard. We will cover this in Chapter 19, Using Tools to Write Better Code.
  • Meetings to eliminate impediments.

Remember, the implementation matching the user needs is your responsibility. Use every tool you can to meet it.

Case 3 – the usability of the system does not meet user needs

Usability is a key point for the success of a software project. The way the software is presented and how it solves a problem can help the user to decide whether they want to use it or not. As a software architect, you must keep in mind that delivering software with good usability is mandatory nowadays.

There are basic concepts of usability that this book does not intend to cover, but a good way to meet the correct user needs when it comes to usability is by understanding who is going to use the software. Design Thinking can help you a lot with that, as was discussed earlier in this chapter.

Understanding the user will help you to decide whether the software is going to run on a web page, or a cell phone, or even in the background. This understanding is very important to a software architect because the elements of a system will be better presented if you correctly map who will use them.

On the other hand, if you do not care about that, you will just deliver software that works. This can be good for a short time, but it will not exactly meet the real needs that made a person ask you to architect the software. You must keep in mind the options and understand that good software is designed to run on many platforms and devices.

You will be happy to know that .NET 5 is an incredible cross-platform option for that. So, you can develop solutions to run your apps in Linux, Windows, Android, and iOS. You can run your applications on big screens, tablets, cell phones, and even drones! You can embed apps on boards for automation or in HoloLens for mixed reality. Software architects must be open-minded to design exactly what their users need.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image