Showing posts with label Design Patterns. Show all posts
Showing posts with label Design Patterns. 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.

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

Saturday, 26 June 2021

WPF Data Binding Best Practices

 I just started learning WPF and today I’m gonna share the WPF basics for two way data bindings and the focus would be on designing your Model and ViewModel.

WPF is based on MVVM design patterns and this is how I see/understand it.

Model should only be responsible for Business & Data logics and it should not have any dependency with UI. Well, I say it as I have seen many articles where people have used INotifyPropertyChanged derived with their Models. I’m not saying it is completely wrong but doesn’t seems to be a best practices as well. Think about a scenario where your Model is shared among multiple services and wpf application.

So what I prefer here to use MVVM with Facade Pattern to separate out the UI dependency with Model.

Another important thing which I noticed with articles flooded over the internet is, Use of DependencyObject override for ViewModel for data binding. I didn’t find it a best practice as well because of the limitations/issues it is giving like:
1. It creates a View dependencies and it never meant to be a source of a binding.
2. Can’t override Equals or GetHashCode (may be less important)
3. Thread affinity problem: a huge issue dealing with multi threading
4. Serialization problem: another problem if you want to serialize anything in ViewModel
5. Difficult to read: I hate this as this implementation makes code too difficult to read/understand specially for people like me, who is learning.
6. Still need INotifyPropertyChanged for CLR properties.

Hence finally here we got two best practices to be followed for WPF data binding:
1. Use Facade for Models and 2. use INotifyPropertyChanged.

Now lets do the programming. A simple application which has a person info, First Name, Last Name and Full Name and how we bind it by following above two best practices.

Model (Person.cs)

public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";

public Person() { }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}

As I said, we will not keep any dependency with Model to UI and ViewModel and the reason could be like, this model has too much probably not needed for me or we need to use multiple models together for view model.

Model Facade (ModelFacade.cs =>you name it as you want)

public class ModelFacade
{
public Person Person { get; set; }
public ModelFacade(string firstName, string lastName)
{
Person = new Person
{
FirstName = firstName,
LastName = lastName
};
}
}

Now here we go with ViewModel which will be implementing INotifyPropertyChanged. Also for code extendibility or avoid code duplicity I prefer (actually I recommend it as a best practice) ViewModelBase to separate the INotifyPropertyChanged implementation.

ViewModel (ViewModel.cs) and ViewModelBase (ViewModelBase.cs)

public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}

public class ViewModel : ViewModelBase
{
ModelFacade _model;
public string FirstName
{
get { return _model.Person.FirstName; }
set
{
_model.Person.FirstName = value;
OnPropertyChanged("FirstName");
OnPropertyChanged("FullName");
}
}
public string LastName
{
get { return _model.Person.LastName; }
set
{
_model.Person.LastName = value;
OnPropertyChanged("LastName");
OnPropertyChanged("FullName");
}
}
public string FullName
{
get { return _model.Person.FullName; }
}
public ViewModel()
{
_model = new ModelFacade("Binod", "Mahto");
}
}

View (MainWindow.xaml)

<Window x:Class="WpfAppNet2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppNet2"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:ViewModel x:Name="vm"/>
</Window.DataContext>
<Grid Margin="10" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<TextBlock Text="First Name:" Grid.Column="1" Grid.Row="1"/>
<TextBox Text="{Binding Mode=TwoWay, Path=FirstName, UpdateSourceTrigger=PropertyChanged}" Grid.Column="2" Grid.Row="1" Width="100" />
<TextBlock Text="Last Name:" Grid.Column="1" Grid.Row="2"/>
<TextBox Text="{Binding Mode=TwoWay, Path=LastName, UpdateSourceTrigger=PropertyChanged}" Grid.Column="2" Grid.Row="2" Width="100"/>
<TextBlock Text="Full Name:" Grid.Column="1" Grid.Row="4"/>
<TextBlock Text="{Binding FullName}" Grid.Column="2" Grid.Row="4"/>
<TextBlock Text="{Binding Mode=TwoWay, Path=Message}" Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="5"/>
<Button Content="Save Me!" Name="btnSave" Click="btnSave_Click" Grid.Column="1" Grid.Row="6"/>
<TextBox TextWrapping="Wrap" AcceptsReturn="True" Name="txtSavedData" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="7"/>
</Grid>
</Window>

Suggestion: Avoid doing control drag & drop if you really want to use the WPF best of it and follow Grid Rows and Columns based design as I did here otherwise you will never get your code right in UI because of autogenerated margins when you drag and drop controls.

Code Behind. (MainWindow.xaml.cs)

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnSave_Click(object sender, RoutedEventArgs e)
{
txtSavedData.Text = vm.FirstName + "\n" + vm.LastName + "\n" + vm.FullName;
}
}

and here is the output:
1. When it loads:

2. Either change First Name or Last Name, you will the Full Name changing accordingly.

3. Click on save to see the modified state of Model Facade properties.

Now you can easily use the ModelFacase modified state to send the data back from ViewModel to Model for update.

Hope you like it.