Logging/Clean arch Flashcards
Logging
Logging is the process of recording run-time actions as they happen in real-time.
Helps us to understand the failures and performance bottlenecks of the application.
ILogger levels
Debug
ILogger.LogDebug(“log_message”);
Logs that provide details & values of variables for debugging purpose.
Information
ILogger.LogInformation(“log_message”);
Logs that track the general flow of the application execution.
Warning
ILogger.LogWarning(“log_message”);
Logs that highlight an abnormal or unexpected event.
Error
ILogger.LogError(“log_message”);
Logs to indicate that flow of execution is stopped due to a failure.
Critical
ILogger.LogCritical(“log_message”)
Logs to indicate an unrecoverable application crash.
Serilog
Serilog is a structured logging library for Asp.Net Core.
Supports variety of logging destinations, referred as “Sinks” - starts with Console, Azure, DataDog, ElasticSearch, Amazon CloudWatch, Email and Seq.
Serilog - File Sink
The “Serilog.Sinks.File” logs into a specified file.
You can configure the filename, rolling interval, file size limit etc., using configuration settings.
Serilog - Seq Sink
The “Serilog.Sinks.Seq” is a real-time search and analysis server for structured application log data.
Seq server can run on Windows, Linux or Docker.
Serilog - RequestId
“RequestId” is the unique number (guid) of each individual requests, used to identify to which request the log belongs to.
RequestId is “TraceIdentifier” internally, that is generated by Asp.Net Core.
Serilog - Enrichers
Enrichers are additional details that are added to LogContext; so they’re stored in logs.
Eg: MachineName[or]Custom Properties.
Filters
Filters are the code blocks that execute before / after specific stages in “Filter Pipeline”.
Filters perform specific tasks such as authorization, caching, exeption handling etc.
Overview of Types of Filters
Authorization Filter
Determines whether the user is authorized to access the action method.
Resource Filter
Invoking custom model binder explicitly
Caching the response.
Action Filter
Manipulating & validating the action method parameters.
Manipulating the ViewData.
Overriding the IActionResult provided by action method.
Exception Filter
Handling unhandled exception that occur in model binding, action filters or action methods.
Result Filter
Preventing IActionResult from execution.
Adding last-moment changes to response (such as adding response headers).
Action Filter
When it runs
Runs immediately before and after an action method executes
‘OnActionExecuting’ method
It can access the action method parameters, read them & do necessary manipulations on them.
It can validate action method parameters.
It can short-circuit the action (prevent action method from execution) and return a different IActionResult.
‘OnActionExecuted’ method
It can manipulate the ViewData.
It can change the result returned from the action method.
What are global filters?
Global filters are applied to all action methods of all controllers in the project.
Filters [vs] Middleware
Middleware
Middleware pipeline is a superset of Filter pipeline, which contains the full-set of all middlewares added to the ApplicationBuilder in the application’s startup code (Program.cs).
Middleware pipeline execute for all requests.
Middleware handles application-level functionality such as Logging, HTTPS redirection, Performance profiling, Exception handling, Static files,
Authentication etc., by accessing low-level abstractions such as HttpContext.
__________________________________________________________
Filter
Filter pipeline is a subset of Middleware pipeline which executes under “EndPoint Middleware”.
filter pipeline executes for requests that reach “EndPoint Middleware.
Używany do walidacji, autoryzacji, obsługi wyjątków, modyfikacji wyników
Exception Handling Middleware
Handles all errors occurred in filter pipeline (including model binding, controllers and filters).
Should be added to the application pipeline, before RoutingMiddleware.
Custom Exceptions
A custom exception class is an exception class that inherits from System.Exception class & represents a domain-specific excpetion
Used to represent the domain-specific errors stand-out of system-related (.NET) related exceptions.
UseExceptionHandler()
The built-in UseExceptionHandler() middleware redirects to the specified route path, when an unhandled exception occurs during the application execution.
Can be used as an alternative to custom exception handling middleware.
Catches and logs unhandled exceptions.
Re-executes the request in an alternative pipeline using the specified route path.
Overview of SOLID Principles
“SOLID” is a set of five design patterns, whose main focus is to create loosely coupled, flexible, maintainabile code.
Broad goal of SOLID Principles:Reduce dependencies of various classes / modules of the application.
5 solid principles
Single Responsibility Principle (SRP)
A software module or class should have one-and-only reason to change.
Liskov Subsitution Principle (LSP)
Subtypes must be substitutable for their base types.
Open-Closed Principle (OCP)
A class is closed for modifications; but open for extension.
Interface Segregation Principle (ISP)
No client class should be forced to depend on methods it does not use.
Dependency Inversion Principle (DIP)
High-level modules should not depend on low-level modules. Both should depend upon abstractions.
Dependency Inversion Principle (DIP)
Dependency Problem
Higher-level modules depend on lower-level modules.
Means, both are tightly-coupled.
The developer of higher-level module SHOULD WAIT until the completion of development of lower-level module.
Requires much code changes in to interchange an alternative lower-level module.
Any changes made in the lower-level module effects changes in the higher-level module.
Difficult to test a single module without effecting / testing the other module.
Dependency Inversion Principle
Dependency Inversion Principle (DIP) is a design principle (guideline), which is a solution for the dependency problem.
“The higher-level modules (clients) SHOULD NOT depend on low-level modules (dependencies).
Both should depend on abstractions (interfaces or abstract class).”
“Abstractions should not depend on details (both client and dependency).
Details (both client and dependency) should depend on abstractions.”
Single Responsibility Principle (SRP)- class
A class should have one-and-only reason to change.
A class should implement only one functionality.
Avoid multiple / tightly coupled functionalities in a single class.
Eg: A class that performs validation should only involve in validation.
But it should not read configuration settings from a configuration file.
But instead, it call a method of another class that reads configuration settings.
Single Responsibility Principle (SRP)- interface
Create alternative implementation of the class by implementing the same interface.
Benefit: Makes the class independent of other classes, in terms of its purpose / functionality.
So that, the classes become easier to design, write, debug, maintain and test.
Interface Segregation Principle (ISP)
No client class should be forced to depend on methods it doesn’t use.
We should prefer to make many smaller interfaces rather than one single big interface.
The client classes may choose one or more interfaces to implement.
Benefit: Makes it easy to create alternative implementation for a specific functionality, rather than recreating entire class.
Assume, a class has two methods: GetPersons() and AddPerson().
Instead of creating both methods in a single interface, create them as two different interfaces: IPersonGetter, IPersonAdder
interface IPersonsGetter (methods to get persons data)
interface IPersonsAdder(methods to create person)
Open/Closed Principle (OCP)
A class is closed for modifications; but open for extension.
You should treat each class as readonly for development means; unless for bug-fixing.
If you want to extend / modify the functionality of an existing class; you need to recreate it as a separate & alternative implementation; rather than modifying existing code of the class.
Eg:
Assume, a class has a method: GetPersons().
The new requirement is to get list of sorted persons.
Instead of modifying existing GetPersons() method, you need to create an alternative class that gets sorted persons list.
Benefit: Not modifying existing code of a class doesn’t introduce new bugs; and keeps the existing unit tests stay relavant and needs no changes.
Interfaces
Create alternative implementation of the class by implementing the same interface.
Inheritance
Create a child class of the existing class and override the required methods that needs changes.
Liskov Substitution Principle (LSP)
Functions that use references of base classes must be able to use objects of derived classes without breaking / changing its functionality.
The child classes that override methods of base class, should provide same behavior.
Using object of parent class
ParentClass variable = new ParentClass();
variable.Method(); //executes ParentClass.Method
Using object of child class
ParentClass variable = new ChildClass();
variable.Method(); //executes ChildClass.Method
[Both methods should offer same functionality]
Functions that use references of base classes must be able to use objects of derived classes without breaking / changing its functionality.
The child classes that override methods of base class, should provide same behavior.
If a derived class overrides a method of base class; then the method of derived class should provide same behavior:
With same input, it should provide same output (return value).
The child class’s method should not introduce (throw) any new exceptions than what were thrown in the base implementation.
The child class’s method should not implement stricter rules than base class’s implementation.
Benefit: Prevents code to break - if by mistake or wantedly, someone has replaced the derived class with its base class (or even vice versa), as its behavior doesn’t change.
Overview of Clean Architecture
Instead of “business logic” depend on “data access logic”, this dependency is inverted; that means, the “data access logic” depend on “business logic”.
Benefit: The business logic is highly clean-separated, independent of data storage and UI, unit-testable.
Traditional Three-Tier / N-Tier Architecture
User Interface (UI)
Business Logic Layer (BLL)
Repository Layer (RL)
Data Access Layer (DAL)
Clean Architecture elements
UI
Controllers, Views, View Models
Filters, Middleware
Core
Business Logic Services
Business Logic Interfaces
Data Transfer Objects (DTO)
Domain
Repository Interfaces
Entity Classes
Infrastructure
DbContext, Repositories
External API Calls
Clean Architecture benefits
Changing external system
Allows you to change external systems (external APIs / third party services) easily, without affecting the application core.
Scalable
You can easily scale-up or scale-out, without really affecting overall architecture of the application.
Database independent
The application core doesn’t depend on specific databases; so you can change it any time, without affecting the application core.
Testable
The application core doesn’t depend on any other external APIs or repositories; so that you can write unit tests against business logic services easily by mocking essential repositories.
Clean architecture is earlier named as “Hexagonal architecture”, “Onion architecture”, “Domain-Driven Design”, “Vertical Slice Architecture”. Over time, it is popular as “clean architecture”.