Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
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

Usability – why inserting data takes too much time

Scalability, performance tips, and multithreading are the main tools we can use to tune machine performance. However, the effectiveness of the system you design depends on the overall performance of the whole processing pipeline, which includes both humans and machines.

As a software architect, you cannot improve the performance of humans, but you can improve the performance of man-machine interaction by designing an effective user interface (UI), that is, a user interface that ensures fast interaction with humans, which, in turn, means the following:

  • The UI must be easy to learn in order to reduce the time that is needed for learning and time wasting before the target users learn to operate it quickly. This constraint is fundamental if UI changes are frequent, and for public websites that need to attract the greatest possible number of users.
  • The UI must not cause any kind of slowdown in data insertion; data entry speed must be limited only by the user's ability to type, not by system delays or by additional gestures that could be avoided.

It is worth mentioning that we have UX experts in the market. As a software architect, you must decide when they are essential to the success of the project. The following are a few simple tips when it comes to designing easy to learn user interfaces:

  • Each input screen must state its purpose clearly.
  • Use the language of the user, not the language of developers.
  • Avoid complications. Design the UI with the average case in mind; more complicated cases can be handled with extra inputs that appear only when needed. Split complex screens into more input steps.
  • Use past inputs to understand user intentions and to put users on the right paths with messages and automatic UI changes; for instance, cascading drop-down menus.
  • Error messages are not bad notes the system gives to the user, but they must explain how to insert correct input.

Fast user interfaces result from efficacious solutions to the following three requirements:

  • Input fields must be placed in the order they are usually filled, and it should be possible to move to the next input with the Tab or Enter key. Moreover, fields that often remain empty should be placed at the bottom of the form. Simply put, the usage of the mouse while filling a form should be minimized. This way, the number of user gestures is kept to a minimum. In a web application, once the optimal placement of input fields has been decided, it is enough to use the tabindex attribute to define the right way users move from one input field to the next with the Tab key.
  • System reactions to user inputs must be as fast as possible. Error messages (or information ones) must appear as soon as the user leaves the input field. The simplest way to achieve this is to move most of the help and input validation logic to the client side so that system reactions do not need to pass through both communication lines and servers.
  • Efficacious selection logic. Selecting an existing item should be as easy as possible; for example, selecting one out of some thousands of products in an offer must be possible with a few gestures and with no need to remember the exact product name or its barcode. The next subsection analyzes techniques we can use to decrease complexity to achieve fast selection.

In Chapter 16, Blazor WebAssembly, we will discuss how this Microsoft technology can help us with the challenges of building web-based applications with C# code in the front-end.

Designing fast selection logic

When all the possible choices are in the order of magnitude of 1-50, the usual drop-down menu is enough. For instance, this currency selection drop-down menu:

 

Figure 2.13: Simple drop-down menu

When the order of magnitude is higher but less than a few thousand, an autocomplete that shows the names of all the items that start with the characters typed by the user is usually a good choice:

Figure 2.14: Complex drop-down menu

A similar solution can be implemented with a low computational cost since all the main databases can efficiently select strings that start with a given substring.

When names are quite complex, when searching for the characters that were typed in by the user, they should be extended inside each item string. This operation cannot be performed efficiently with usual databases and requires ad hoc data structures.

Finally, when we are searching inside descriptions composed of several words, more complex search patterns are needed. This is the case, for instance, with product descriptions. If the chosen database supports full-text search, the system can search for the occurrence of several words that have been typed by the user inside all the descriptions efficiently.

However, when descriptions are made up of names instead of common words, it might be difficult for the user to remember a few exact names contained in the target description. This happens, for instance, with multi-country company names. In these cases, we need algorithms that find the best match for the character that was typed by the user. Substrings of the string that was typed by the user must be searched in different places of each description. In general, similar algorithms can't be implemented efficiently with databases based on indexes, but require all the descriptions to be loaded in memory and ranked somehow against the string that was typed by the user.

The most famous algorithm in this class is probably the Levenshtein algorithm, which is used by most spell checkers to find a word that best fits the mistyped one by the user. This algorithm minimizes the Levenshtein distance between the description and the string typed by the user, that is, the minimum number of character removals and additions needed to transform one string into another.

The Levenshtein algorithm works great, but has a very high computational cost. Here, we give a faster algorithm that works well for searching character occurrences in descriptions. Characters typed by the user don't need to occur consecutively in the description but must occur in the same order. Some characters may miss. Each description is given a penalty that depends on the missing characters and on how far the occurrences of the characters typed by the user are from the others. More specifically, the algorithm ranks each description with two numbers:

  • The number of characters typed by the user that occurs in the description: the more characters contained in the description, the higher its rank.
  • Each description is given a penalty equal to the total distance among the occurrences of the characters typed by the user in the description.

The following screenshot shows how the word Ireland is ranked against the string ilad, which was typed by the user:

Figure 2.15: Sample of Levenshtein usage

The number of occurrences is four (4), while the total distance between character occurrences is three (3).

Once all the descriptions have been rated, they are sorted according to the number of occurrences. Descriptions with the same number of occurrences are sorted according to the lowest penalties. The following is an autocomplete that implements the preceding algorithm:

Figure 2.16: Levenshtein algorithm user interface experience

The full class code, along with a test console project, is available in this book's GitHub repository.

Selecting from a huge number of items

Here, huge does not refer to the amount of space needed to store the data, but to the difficulty the user has in remembering the features of each item. When an item must be selected from among more than 10,000-100,000 items, there is no hope of finding it by searching for character occurrences inside a description. Here, the user must be driven toward the right item through a hierarchy of categories.

In this case, several user gestures are needed to perform a single selection. In other words, each selection requires interaction with several input fields. Once it's decided that the selection can't be done with a single input field, the simplest option is cascading drop-down menus, that is, a chain of drop-down menus whose selection list depends on the values that were selected in the previous drop-down menus.

For example, if the user needs to select a town located anywhere in the world, we may use the first drop-down menu to select the country, and once the country has been chosen, we may use this choice to populate a second one with all the towns in the selected country. A simple example is as follows:

Figure 2.17: Cascading drop-down menu example

Clearly, each drop-down menu can be replaced by an autocomplete when required due to having a high number of options.

If making the right selection can be done by intersecting several different hierarchies, cascading drop-down menus become inefficient too, and we need a filter form, as follows:

Figure 2.18: Filter form sample

Now, let us understand interoperability with .NET Core.

You have been reading a chapter from
Software Architecture with C# 9 and .NET 5 - Second Edition
Published in: Dec 2020
Publisher: Packt
ISBN-13: 9781800566040
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 $15.99/month. Cancel anytime
Visually different images