Showing posts with label clean code. Show all posts
Showing posts with label clean code. Show all posts

Thursday, 2 June 2022

Clean Code Architecture with Mediator & CQRS pattern in .Net Core

 May be for some of you, The Mediator pattern is known but here my focus is to using the Mediator pattern with CQRS (Command and Query Responsibility Segregation) pattern to make our .net core (API or web) code cleaner, extensible and maintainable.

[ApiController]
[Route("[controller]")]
public class LoanProcessController : ControllerBase
{
private ICibilService _cibilService;
private IEmploymentService _employmentService;
private IAccountService _employmentService;
private IPaymentService _paymentService;
private IEMIService _emiService;
public LoanProcessController(ICibilService cibilService,
IEmploymentService employmentService,
IAccountService accountService,
IPaymentService paymentService,
IEMIService emiService)
{
_cibilService = cibilService;
_employmentService = employmentService;
_accountService = accountService;
_paymentService = paymentService;
_emiService = emiService;
}
[HttpGet(Name = "GetWeatherForecast")]
public async Task<IEnumerable<LoanApplication>> ApproveLoan()
{
_cibilService.ValidateCibilScore();
_employmentService.ValidateEmployeeStatus();
_accountService.ValidateAccount();
_paymentService.ValidatePaymentHistory();
__emiService.ValidatePaymentEMIPaymentRatio();
}
}
builder.Services.AddMediatR(Assembly.GetExecutingAssembly());
using MediatR;namespace CQRSWebAPIDemo.CQRS.Query
{
public class GetWeatherForecastQueryRequest : IRequest<IEnumerable<WeatherForecast>>
{
private static readonly string[] Summaries = new[]{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public DateTime DateTime { get; set; }
public class GetWeatherForecastQueryHandler : IRequestHandler<GetWeatherForecastQueryRequest, IEnumerable<WeatherForecast>>
{
private ILogger<GetWeatherForecastQueryHandler> _logger;
public GetWeatherForecastQueryHandler(ILogger<GetWeatherForecastQueryHandler> logger)
{
_logger = logger;
}
public async Task<IEnumerable<WeatherForecast>> Handle(GetWeatherForecastQueryRequest query, CancellationToken cancellationToken)
{
var dateTime = query.DateTime;
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = dateTime.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
}
}
}
}
using CQRSWebAPIDemo.CQRS.Query;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace CQRSWebAPIDemo.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ILogger<WeatherForecastController> _logger;
private IMediator _mediator;
public WeatherForecastController(IMediator mediator, ILogger<WeatherForecastController> logger)
{
_logger = logger;
_mediator = mediator;
}
[HttpGet(Name = "GetWeatherForecast")]
public async Task<IEnumerable<WeatherForecast>> Get()
{
return await _mediator.Send(new GetWeatherForecastQueryRequest { DateTime = DateTime.Now });
}
}
}

Tuesday, 19 April 2022

Clean Code is an Art

 Good Code vs Bad Code, “A code, understood by the machine but not human is an example of Bad code even it is giving the right output whereas a code, understood by machine and human both is the Good code”. So I would say, An expert may write code but only an artists (Code Artist) can write good code. Remember “writing a clean & good code is nothing less than an Art”.

int c = 0; \\counter value
DateTime dt;
int counter = 0; 
DateTime systemGeneratedDate;
class Customer
{
}
is better thanclass CustomerDetails
{
}
public DateTime GetPlannedScheduledDate()
{
return plannedScheduledDate;
}
is better than the below function here:public DateTime GetDate()
{
return plannedScheduledDate;
}
//Bad comments example//Comment:Checking if an account is currently active
if(!account.IsDeleted && account.AvailableBalance > 500 && account.lastTransactionDate > DateTime.Now.AddMonths(-3))
{
//code logic
}
if(account.checkIfAccountActive())
{
//code logic
}
private bool checkIfAccountActive()
{
return !account.IsDeleted && account.AvailableBalance > 500 && account.lastTransactionDate > DateTime.Now.AddMonths(-3);
}
//This is our best attempt to get a race condition by creating large number of threads. 
for (int counter = 0; counter < 2500; counter ++)
{
//Code which creates a thread with every loop here.
}
  1. Peer Code Review: This is best techniques to clean your code. The more persons review your code, you get more ideas to make your code better. It is a human tangency to miss small things when you are on a problem to solve but those small things may affect the code readability, performance or security. Hence this is where Peer Code Review helps.
  2. Keep yourself updated: Whatever technology or language you use, it is very important to keep yourself updated so that you can use the latest technology or features to make your code better & better. Hence thumb rule here, keep learning.
  3. Use libraries (nuget packages): There are many useful open source libraries available to do which you might want to do so I recommend to use them instead of reinventing the wheel by your own. i.e. for data operations in .net there is a library called Dapper which is very useful”, so I recommend to use this instead of writing the whole piece from connection management to data management etc.
    At the same time, Be careful also while choosing the libraries and you must read the licenses or the terms & conditions.

Exception Handling Techniques & Tricks C#

 Exception handling could turn to costly operation in your code if you don’t pay much attention to it.

  1. Use Catch only if needed as it is costly operation, if possible use if instead.
    i.e. Divide by zero exception. why not do a check for zero before divide operation if possible.
try
{
var result = myVal/someParam;
}
catch(DivideByZeroException ex)
{
//do what you want
}
above code can be refactored like below to avoid the costly catch operation.if(someParam != 0)
{
var result = myVal/someParam;
}
else
{
//do what you wanted to do in the catch block
}
try
{
//code
}
catch(Exception)
{
}
return something;
try
{
//code
}
catch(Exception ex)
{
throw ex;
}
return something;
ORtry
{
//code
}
catch(Exception)
{
throw;
}
return something;
//Bad Code
try
{
//code
}
catch(Exception ex)
{
//do something
throw ex;
}
return something;
//better Code
try
{
//code
}
catch(Exception ex)
{
//do something
throw;
}
return something;
//Bad code
try
{
//some code
try //inner try catch 1
{
//some code
}
catch(Exception ex)
{
throw ex;
}
try //inner try catch 2
{
//some code
}
catch(Exception ex)
{
throw;
}
}
catch(Exception ex)
{
//code to handle the exception
}
{
method1();
method2();
}
private void method1()
{
try //inner try catch 1
{
//some code
}
catch(Exception ex)
{
//Handle exception and do not throw back to caller.
}
}
private void method2()
{
try //inner try catch 1
{
//some code
}
catch(Exception ex)
{
//Handle exception and do not throw back to caller.
}
}
try
{
method1();
method2();
}
catch(NullException ex)
{
//Handle exception. If needed catch can be classified well based on the exception type behavior of method1 and method 2.
}
catch(Exception ex)
{
//Handle exception
}
private void method1()
{
//code
}
private void method2()
{
//code
}
{
var result = method1();
method2();
}
private int method1()
{
int result;
try //inner try catch 1
{
//some code
}
catch(Exception ex)
{
//Handle exception and do not throw back to caller.
}
finally
{
result = 0;
}
return result;
}
private void method2()
{
try //inner try catch 1
{
//some code
}
catch(Exception ex)
{
//Handle exception and do not throw back to caller.
}
finally
{
//clean your mess-ups, like closing the open connection, fallback mechanism etc.
}
}
//Bad Practice
public Result PerformAction()
{
try
{
}
catch(Exception ex)
{
throw;
}
}
//Good Practice
public Result PerformAction()
{
try
{
}
catch(Exception ex)
{
return new CustomException("An internal error occured");
}
}
public class CustomException : Exception
{
}

Wednesday, 6 April 2022

Anti-corruption Layer pattern a life saver

 Anti-corruption layer pattern allows communication between one system or subsystem to another system or sub system without corrupting each other system domain or model or the objectives.

When to use this pattern