After a while of not posting any blog content and migrating my blog from AWS to Azure, I quickly find that posting new content after generating static content of my blog and have it uploaded, I have to manually go into Azure CDN profile to have the cache
]]>After a while of not posting any blog content and migrating my blog from AWS to Azure, I quickly find that posting new content after generating static content of my blog and have it uploaded, I have to manually go into Azure CDN profile to have the cache purged for the new content to become visible via my domain. This will quickly become a repetitive task and I wanted to automate this process and safe me time from manually purging the CDN and at the same time, spend little to nothing on costs in doing so. I currently host my blog on Azure blob storage as a static site. Azure has amazing services to do just that.
Azure offer amazing services to help resolve this issue. The proposed solution is summarised as follows; Azure storage blob emits an event whenever new contents are uploaded. Azure Event Grid listens to the event and notifies interested subscriber(s) about the event raised by the blob storage. Event Grid triggers a webhook attached to an automation Powershell runbook which purges the CDN cached contents thereby allowing for the new contents to become available immediately after new content is uploaded to the blob storage.
In short, Azure Event Grid enables you to build event-driven architecture and capable of integrating with a lot of Azure Services. This post will focus on implementing the proposed solution without going into details on what Event Grid is. Feel free to read more on Azure Event Grid here.
This post assumes you already have an Azure CDN profile in place as we won't be creating one in this post. Refer to this link if you need to create an Azure CDN; Quickstart: Create an Azure CDN profile and endpoint.
The Azure run book is the hander of the event and will subsequently run the Powershell code to trigger and purge the CDN profile of its cached content. Let's begin by creating an Azure automation account.
From the Azure portal navigate to Automation Accounts and create an account.
Next navigate to the newly created automation account and nagivate to Modules blade under the Shared Resources section. We will be installing the Powershell Azure Az modules needed to run the Powershell scripts.
Azure currently provides two Powershell modules to interact with Azure resources and they are AzureRM and Az Modules. Azure recommends the use of Az module going forward as AzureRM will not be officially maintained from December 2020. More details here.
Click on Browse Gallery and install the following modules:
Az.Account - For authenticating and authorising with Azure
Az.Resources - For interacting with Azure resources
Az.Cdn - For manipulating Azure CDN resources
Az.Automation - For interraction with Azure automation
The search bar type Az. and hit the enter key on your computer and you should see results similar to the image below. Find all the module listed above and import them. See an example below.
Import example
Now we have the Az modules setup and ready to go. Let's now create the Powershell runbook that will contain the scripts need to get the connection to our Azure automation account, authenticate and authorise with Azure, get details of our CDN and purge its content.
Navigate back to the Automation account and click Runbooks under the Process Automation blade or section and click on Create a runbook. Fill in the name of your runbook, choose Powershell as the Runbook type and give it a description of your choosing.
Copy and paste the below Powershell script into the newly created Powershell runbook.
"Grabbing the connection..."
$connectionName = "AzureRunAsConnection"
$cdnProfileName = "your cdn profile"
$RGName = "your Resource Group"
$CdnEndpointName = "Your Cdn Endpoint Name"
$AutomationAccountName = "Your Automation Account Name"
try{
$servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
"Logging in to Azure...."
Connect-AzAccount `
-ServicePrincipal `
-TenantId $servicePrincipalConnection.TenantId `
-ApplicationId $servicePrincipalConnection.ApplicationId `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch{
if(!$servicePrincipalConnection){
$ErrorMessage = "Connection $connectionName not found."
throw $ErrorMessage
}else{
Write-Error -Message $_.Exception
throw $_.Exception
}
}
"Fetching the CDN custom domain name...."
$customDomain = (Get-AzCdnCustomDomain -ResourceGroupName $RGName -ProfileName $cdnProfileName -EndpointName ghost)[0].HostName
"Purging everything in the CDN with domain name: $customDomain ...."
Unpublish-AzCdnEndpointContent `
-ProfileName $cdnProfileName `
-ResourceGroupName $RGName `
-EndpointName $CdnEndpointName `
-PurgeContent "/*"
It's time to test and publish the runbook. Still, on the runbook, you created the last time, click on the Test pane and click the Start button to manually trigger the runbook.
If everything is properly implemented, the Powershell runbook should start running and have the status displayed in the job stream log and when the test is completed successfully, a completed status along with the stream is displayed.
Navigating to Azure CDN profile and inspecting the activity log, you should now see a Purge operation with a Succeeded status, how long the operation took and the service principal that initiated the action which is the AzureRunAsConnection we agreed for Azure to create when we created the automation account. Behind the scene, Azure created this service principal of type AzureServicePrincipal with Azure Active Directory (AAD) to save us the plumbing details. For more details visit the connections blade under the shared resources section of your automation account to see details this service principal.
Now we have a working Powershell runbook ready to be triggered. Let wire up a webhook that will trigger the runbook.
Azure automation runbook can expose an HTTP endpoint or webhook whichever makes sense. In the context of Azure automation runbook, it's called webhook. The webhook, in this case, is analogous to a different or channel with which messages and triggers get to the runbook.
To create the webhook, navigate to the runbook you have created and tested and click on Add webhook, select Create new webhook, enter your preferred name for the webhook, select enabled, set the expiry date, ensure you keep the webhook URL for later use and click OK and Create to create your webhook.
Before I go any further I would like to clarify that Event Grid System Topics are system topics in Event Grid that represents events published by Azure services such as Event Hubs, Azure storage account. Here is a list of Azure services that supports system topics.
To be able to use Event Grid System Topics, Event Grid services has to be enabled on your Azure account on the subscription level otherwise, Azure services raising events and subscribers/handler for those events will not work.
If you don't have the EventGrid enabled, you can navigate to your Azure subscription and in the Resource Provider section under Settings, type Event in the search bar, select Microsoft.EventGrid, click Register/Re-register and give it a little while to complete the setup. Once completed, you should see a green checkmark with the status of Registered.
As you may have noticed, Azure provides various ways of achieving the same thing. We could go create an Event Grid System Topics and manually work through the steps or we could go via the resource whose event we are interested in and in this case, the azure blob in a storage account. Since we have Event Grid registered, we are ready to go complete the final piece by doing the later.
Navigate the Azure resource you want its events to be raised and navigate to on the Events. For this walk through, I want my event raised from the storage account where I host my static site.
From the Events blade, click Event Subscription to create the subscription
Fill in the parts to have the subscription created. Remember to use the webhook URL we created in the Webhook section of this post, click confirm the selection.
Next, you want to add a filter to the event such that your storage account doesn't fire off event for every blob created across the storage account but limit it to a specific container(s) or event blob. To do this, we have to filter the event and Event Grid is brilliant for that. using the subject filter of /blobServices/default/containers/<containername>/
This filter rule says Blob Created events should only be raised for blob(s) in the container with the name <containername> and in my case, it's $web. This locks the events raised from the storage account to the container level, thereby saving costs and not having events fire when you don't need them to.
Once the subscription is created, at this point you should have everything wired up together and ready to do. You should now have your storage account subscriptions or your Azure resource events subscriptions similar to the image below.
After running a couple of tests via your event producer, in my case, the blob storage where I have my static site hosted, observing the event subscription that we created, you should see the metrics of the event that has occurred and its state.
The cost of Event Grid is £0.448 per million operations while the first 100,000 operations are free per month. Applying the filter as we discussed and reduce the amount of event executed, you may never have to pay for the Event Grid. The monthly free 100,000 operations would do the job just fine. More details of Event Grid pricing here.
In this blog post, the use of Event Grid combined with Azure automation to help automate a process that would otherwise take painstaking time to do. This lays the groundwork to build event-based, decoupled and robust architecture. A good number of Azure resources supports integration with Event Grid and provide a varying number of possibilities.
Managing Connections in Azure Automation
]]>This post focuses on the abstract of Domain Event in Domain Driven Design (DDD) which is also a fundamental building block of microservices or eventing system.
]]>Domain Event pattern with in-built .Net Core IoC Container, scrutor and .Net Core console application. Source code for this post can be found here
This post focuses on the abstract of Domain Event in Domain Driven Design (DDD) which is also a fundamental building block of microservices or eventing system.
An event is something that has happened in the past. A domain event is, something that happened in the domain that you want other parts of the same domain (in-process) to be aware of. The notified parts usually react somehow to the events.
While this post is not specific to microservices, the domain event pattern can be implemented in any system to reduce tight coupling between your services. An example would be an MVC controller with a lot of dependencies, services or repositories injected via constructor injection.
Adapting Udi Dahan's Domain Events Salvation post to .Net Core implementation.
Without injecting any dependencies at compile time, any part of a system can have task completed without having prior knowledge of handler that would handle the commands. Some of the example we would look at includes, completing an order by raising an event and having the proper handler located which will handle the event such as writing the order to a data store or sending an email to the customer.
In the interest of time we'll talk about a domain object and we'll see how that interacts with the system and you may refer to the source code further to see other examples or feel free to leave any questions.
public class Order
{
public Guid OrderId { get; private set; }
public DateTime OrderDate { get; private set; }
public int NumberOfItems { get; set; }
public string OrderName { get; private set; }
public Order(int numberOfItems, string orderName)
{
OrderId = Guid.NewGuid();
OrderDate = DateTime.UtcNow;
NumberOfItems = numberOfItems;
OrderName = orderName;
}
public void OrderComplete()
{
DomainEvent.Raise(new OrderCompletedEvent(DateTime.UtcNow, this));
}
}
The order domain object has a behavior such that when an order is created, it broadcasts an OrderCompletedEvent event of itself to the DomainEvent or Dispatcher and any handler that knows how to handle the event will respond and handles it. These handlers can also be referred to as Event Listeners or Subscribers.
The event is raised via the DomainEvent which is a static class. DomainEvent static class knows about all of the event handler and able to locate and invoke the right event handler for a given event. More about the DomainEvent shortly.
public class OrderCompletedEvent : IDomainEvent
{
public DateTime OrderCreatedDate { get; private set; }
public Order Order { get; private set; }
public OrderCompletedEvent(DateTime orderCreatedDate, Order order)
{
OrderCreatedDate = orderCreatedDate;
Order = order;
}
}
The OrderCompletedEvent class implements an interface without any contract to implement merely decorating the class as a type called IDomainEvent.
public interface IDomainEvent{}
The OrderCompletedEvent has an instance of the Order object and it's duty is to transport the Order object along with any needed property or behavior to the handler.
The DomainEvent is responsible for some behaviors and they include
Registering handler manually via its Register method
Forwarding an event to the proper handler by iterating over all handlers for a particular type resolved from the IoC container
An IoC container is not required but imagine if you have to manually register tens of handlers in your system.
public static class DomainEvent
{
[ThreadStatic]
private static List<Delegate> _actions;
public static IServiceProvider _serviceProvider { get; set; }
public static void Register<T>(Action<T> callback) where T : IDomainEvent
{
_actions = _actions ?? new List<Delegate>();
_actions.Add(callback);
}
public static void ClearCallbacks()
{
_actions = null;
}
public static void Raise<T>(T args) where T : IDomainEvent
{
if (_serviceProvider != null)
{
//Fetch all handler of this type from the IoC container and invoke their handle method.
foreach (var handler in (IEnumerable<IDomainHandler<T>>)_serviceProvider
.GetService(typeof(IEnumerable<IDomainHandler<T>>)))
{
handler.Hanle(args);
}
}
if (_actions != null)
{
foreach (var action in _actions)
{
if (action is Action<T>)
{
((Action<T>) action)(args);
}
}
}
}
}
The generic Raise<T> method in the DomainEvent static class iterates through all the handler using the resolved types from the IoC container. The DomainEvent has to be bootstrapped on application startup taking in an instance of the IoC container or resolver. In the case of this application, takes an instance of ServiceProvider built from type registration on the instance of ServiceCollection. Don't pay attention to the ServiceProvider and ServiceCollection as they specific to .Net Core and you can choose to use any IoC container of your choice.
The EventHandlers go into a separate project that mimics the Onion architecture. According to the onion architecture, the handlers fits into the Infrastructure layer as they most likely will interact with other services and data stores or carry out some infrastructure related tasks. You get the gist.
OrderCompleteHandler.cs
public class OrderCompleteHandler : IDomainHandler<OrderCompletedEvent>
{
public void Hanle(OrderCompletedEvent @event)
{
@event.Order.NumberOfItems = 100;
Console.WriteLine($"Order Information: \n=======================" +
$"\nOrder completed on {@event.OrderCreatedDate.ToShortDateString()} " +
$"at {@event.OrderCreatedDate:HH:mm:ss tt}\nID: {@event.Order.OrderId}" +
$"\nNumber of order items: {@event.Order.NumberOfItems}" +
$"\n____________________________________");
}
}
The event handler in this case, OrderCompleteHandler knows to listens for and knows how to handle OrderCompletedEvent we talked about earlier above. All handlers implement a generic IDomainHandler<T> which describes the general signature of an event handler. It will make more sense when we talk about gluing the whole pieces together next.
public interface IDomainHandler<T> where T : IDomainEvent
{
void Hanle(T @event);
}
Rather than registering each handler or subscriber on demand as they are created, an IoC container best suit this scenario by registering all types that implements IDomainHandler<T>. For this purpose, Scrutor has been used. Scrutor can tie itself into the .Net Core IoC container which provides extensibility to register decorators currently not possible with the in-built .Net Core IoC.
Since a .Net Core console application is used as our client, the bootstrap and type registration is setup in the main method of the console app's Program.cs class.
class Program
{
static void Main(string[] args)
{
//Set up the DI
//Scan the assembly and register types that implements IDomainHandler interface with .Net Core IoC
var serviceProvider = new ServiceCollection()
.Scan( scan => scan
.FromAssemblyOf<StudentRegisteredHandler>()
.AddClasses(classes =>
classes.AssignableTo(typeof(IDomainHandler<>)))
.AsImplementedInterfaces()
).BuildServiceProvider();
DomainEvent._serviceProvider = serviceProvider;
//Create an order
var newOrder = new Order(5, "Amazon");
//Raise an order completed event
newOrder.OrderComplete();
var studentReg = new Student(Title.Mr, "John", "Murphy");
studentReg.RegisterStudent();
var emailSent =
new Email("[email protected]",
"[email protected]", "Event Message Subject",
"This is a short email to say thank you!");
emailSent.RaiseEmailSent();
Console.ReadKey();
}
}
Scrutor provides an extension method, Scan on the IServiceCollection interface. using Scrutor, the assembly of type that implements IDomainHandler<T> are scanned and registered with the .Net Core IoC container which becomes automatically available to the DomainEvent static class which its Raise<T> method uses to locate the proper handler for a particular event.
This post mainly focused on one example of raising an event from a Domain object using a DomainEvent static class which its Raise method taps into an IoC container to locate the handler. The output below shows three samples of events that are raised and handled. Check out the source code for reference.
Order Information:
=======================
Order completed on 09/14/2019 at 17:04:30 PM
ID: 07fa61ed-d5b4-4ed4-9ee1-30e4971972e8
Number of order items: 100
____________________________________
Mr. John Murphy registration is now complete
_____________________________
Email to the address [email protected] has been sent!
_________________________
Hopefully, you have learned something today.
Happy coding..
]]>I have been an adept C# .Net-ter and always will be. One of my favourites is still C# .NET Core as I do C# almost on a daily basis, but a side of me wanted to be platform and framework agnostics as much as I can. I have been taking advantage of tradeoffs in the different languages/framework in developing micro-services. Some argue that you've got to master one language really well and then one framework really well. I say, You can master them all, be proficient and be able to develop production ready applications. In my case, I currently do .Net Core (MVC/Web API), Spring Boot (Java, Kotlin (preferred)), Python (Django, Flask(preferred)), JavaScript/TypeScript is also worth mentioning, but that's another topic for another day. In a future post, I shall detail a small project using all these technology and framework in a architecture of micro-services . As I sink my feet more into the world of micro-services, and the plethora of technologies that can come together and function as a big ol system, it is a fascinating and yet intriguing experience. Having had a strong Java programming experience under my belt, I was able to get started quickly with Kotlin and the transition is almost none existent. I'd say flawless. I have been using Kotlin in production at work and it's a pure joy to work with in comparison to Java. An analogy to explain Kotlin vs Java would be taking the elevator or using the stairs to get to the 100th floor of a building, and Kotlin is the elevator. One catch is that Kotlin compiles to Java in the background. More also, Kotlin and Java can interop really well. You can extend your existing Java codes with Kotlin or mix-match them.
With the knowledge of Java, I do catch myself inspecting the compiled Java code to see the nitty-gritty of what's happening under the hood when I come across some not so understandable Kotlin syntax. No matter how Kotlin syntax looks on IntelliJ Idea, my god, it's still beautiful wow!
Let's say we want to create an InvoiceModel class that represents an invoice for a nursery. The properties of the class should allow for change or update. Let's see this in Java and Kotlin.
//InvoiceModel.java
public class InvoiceModel {
private String fullName;
private String invoicedate;
private String term;
private List<InvoiceData> invoiceDatas;
private Integer breakfasttotal;
private Integer lunchtotal;
private Integer afterSchooltotal;
private double breakfastamount;
private double lunchamount;
private double afterschoolamount;
private double totaldue;
private double breakfastprice;
private double lunchprice;
private double afterschoolprice;
public InvoiceModel(String fullName, String invoicedate, String term, List<InvoiceData> invoiceDatas,
Integer breakfasttotal, Integer lunchtotal, Integer afterSchooltotal, double breakfastamount,
double lunchamount, double afterschoolamount, double totaldue, double breakfastprice, double lunchprice,
double afterschoolprice) {
super();
this.fullName = fullName;
this.invoicedate = invoicedate;
this.term = term;
this.invoiceDatas = invoiceDatas;
this.breakfasttotal = breakfasttotal;
this.lunchtotal = lunchtotal;
this.afterSchooltotal = afterSchooltotal;
this.breakfastamount = breakfastamount;
this.lunchamount = lunchamount;
this.afterschoolamount = afterschoolamount;
this.totaldue = totaldue;
this.breakfastprice = breakfastprice;
this.lunchprice = lunchprice;
this.afterschoolprice = afterschoolprice;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getInvoicedate() {
return invoicedate;
}
public void setInvoicedate(String invoicedate) {
this.invoicedate = invoicedate;
}
public String getTerm() {
return term;
}
public void setTerm(String term) {
this.term = term;
}
public List<InvoiceData> getInvoiceDatas() {
return invoiceDatas;
}
public void setInvoiceDatas(List<InvoiceData> invoiceDatas) {
this.invoiceDatas = invoiceDatas;
}
public Integer getBreakfasttotal() {
return breakfasttotal;
}
public void setBreakfasttotal(Integer breakfasttotal) {
this.breakfasttotal = breakfasttotal;
}
public Integer getLunchtotal() {
return lunchtotal;
}
public void setLunchtotal(Integer lunchtotal) {
this.lunchtotal = lunchtotal;
}
public Integer getAfterSchooltotal() {
return afterSchooltotal;
}
public void setAfterSchooltotal(Integer afterSchooltotal) {
this.afterSchooltotal = afterSchooltotal;
}
public double getBreakfastamount() {
return breakfastamount;
}
public void setBreakfastamount(double breakfastamount) {
this.breakfastamount = breakfastamount;
}
public double getLunchamount() {
return lunchamount;
}
public void setLunchamount(double lunchamount) {
this.lunchamount = lunchamount;
}
public double getAfterschoolamount() {
return afterschoolamount;
}
public void setAfterschoolamount(double afterschoolamount) {
this.afterschoolamount = afterschoolamount;
}
public double getTotaldue() {
return totaldue;
}
public void setTotaldue(double totaldue) {
this.totaldue = totaldue;
}
public double getBreakfastprice() {
return breakfastprice;
}
public void setBreakfastprice(double breakfastprice) {
this.breakfastprice = breakfastprice;
}
public double getLunchprice() {
return lunchprice;
}
public void setLunchprice(double lunchprice) {
this.lunchprice = lunchprice;
}
public double getAfterschoolprice() {
return afterschoolprice;
}
public void setAfterschoolprice(double afterschoolprice) {
this.afterschoolprice = afterschoolprice;
}
}
Now Kotlin
// InvoiceModel.kt
data class InvoiceModel(
var fullName: String,
var invoicedate: String,
var term: String,
var invoiceDatas: List<InvoiceData>,
var breakfasttotal: Int,
var lunchtotal: Int,
var afterSchooltotal: Int,
var breakfastamount: Double,
var lunchamount: Double,
var afterschoolamount: Double,
var totaldue: Double,
var breakfastprice: Double,
var lunchprice: Double,
var afterschoolprice: Double
)
Just look at the beauty. Now compare the Java's 151 lines of code to Kotlin's 17 lines. Wow! Simply beautiful isn't it?
Convention over Configuration
Spring Boot abstracts all of the configuration you would have to do with the Spring framework. But if you would like to control or extend the default configurations, Spring Boot provides application.properties for this purpose.
Dependency Injection
Right out of the box, you get dependency injection for free with Spring Boot. The framework does this uplifting for you and you just worry about writing codes rather than registering your types explicitly like in .NET Core. Oh boy they got this right with Spring Boot.
Modular Boilerplate Code
You can generate your Spring Boot boiler code at http://start.spring.io to build the tempplate for your project and you can make it as modular as you want. They include but not limited to:
Conclusion
Getting started with the Spring framework using Spring Boot is very interesting if you already know Java as the framework is Java based, but came along Kotlin which makes it super fun to work with. You should easily get started with Kotlin if you are already comfortable with Java. You can learn Kotlin from scratch, but you will be better off knowing some Java at least the basics as most of the library and import you will be doing in Kotlin, are Java libraries. If you want to get started with developing Java based enterprise application, the Spring framework via Spring Boot is matured to take you there and Kotlin over Java should be your choice. Future post will talk about how to get started with Spring Boot using Kotlin. Happy Coding!
]]>In this blog post, I will quickly discuss the call(), apply() & bind() methods. These methods allows for dynamic change in the JavaScript "this". The this can be changed depending on the context being used. The usefulness of these methods comes when you want to do some method or function borrowing. Without further due, let's master this methods with examples.
The call(), apply(), and bind() method all do the same thing with some slight variation.
Method borrowing in JavaScript is the concept of reusing an exiting method within the context of different object or reuse method outside the context with which it was created.
Say object A has a method f, object B should be able to use method f of A if the same property(ies) are present in both object.
Let's illustrate this concept in code.
Let's say objects A and B
//object A
let A = {
name: "Michael",
lastName: "Programmer",
getFullName(){
console.log(`The full name is ${this.name} ${this.lastName}`)
}
}
//object B
let B = {
name: "Another",
lastName: "Michael"
}
Now let's borrow the getFullName method of object A to output to the console details of object B
call(thisArg: any, arg1, arg2...argn)
The call method accepts an argument list separated by commas. The first argument references the this keyword, which is the object you are trying to switch context to. In the example below, object B is this
A.getFullName.call(B); // The full name is Another Michael
Boom! that simple.
We could also rip out the method from the object A and have object A and object B borrow and use the function.
let namePrinter = function(){
console.log(`The full name is ${this.name} ${this.lastName}`);
};
//object A
let A = {
name: "Michael",
lastName: "Programmer"
}
//object B
let B = {
name: "Another",
lastName: "Michael"
};
namePrinter.call(A); //The full name is Michael Programmer
namePrinter.call(B); //The full name is Another Michael
Passing argument
In case you are wondering, we can also pass arguments let see this with an example. Suppose the namePrinter function also accepts and output a country. You can pass in the argument after referencing this. Let's create another function accepting an argument and let's borrow it. Let's also add objects C and D.
let namePrinterWithHomeTown = function (hometown) {
console.log(`${this.name} ${this.lastName} is from ${hometown}`);
}
//object C
let C = {
name: "Jack",
lastName: "Black"
};
//object D
let D = {
name: "Alaka",
lastName: "Kamba"
};
namePrinterWithHomeTown.call(A, "Serbia") // Michael Programmer is from Serbia
apply(thisArg: [args])
The apply method works the exact same way as the call method but it accepts an array of argument after referencing this.
namePrinter.apply(C) //The first name is Jack, last name is Black
Passing arguments
namePrinterWithHomeTown.apply(C, ["Madagascar"]) //Jack Black is from Madagascar
bind(thisArg, Args)
Bind behaves very similar to apply and call method with the only difference being bind is deferred which means it has to be manually invoked because it's not invoked automatically like call and apply. Let see this in code.
let objD = namePrinter.bind(D);
objD(); // The first name is Alaka, last name is Kamba
Passing argument
let nameCountry = namePrinterWithHomeTown.bind(C, "Peru");
nameCountry(); // Jack Black is from Peru
A great benefit of these methods is reusability. If you have multiple object having same or very similar shape, and you want to carry out a common operation across these objects, you can function borrow if you are not using prototypical inheritance.
Throughout the javascript ecosystem, the call, bind, & apply method can be used with almost anything in terms or attaching and switching contexts. Below is a playground to play around with these methods. Open up the console at the bottom right to see results.
I will explore some advance application of these methods in another post which will go in-depth to explain some powerful concepts.
Happy Coding!
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
This post is a continuation of the object-oriented programming in JavaScript where we discuss polymorphism.
Polymorphism in the ability to exist and appear in many forms.
Let's explain this concepts in JavaScript while building upon the Shape object and its derived objects from the inheritance post.
A Child object or subclass or derived object may be treated as a parent objects of a base class
Let's borrow some code from the inheritance post.
function Shape(color, name){
this.color = color;
this.name = name;
}
Shape.prototype.draw = function(){
console.log(`${this.name} with color ${this.color} is drawn!`);
};
//Circle Shape
function Circle(radius, name, color){
//Calling the base or parent class
Shape.call(this, color, name);
this.radius = radius;
}
//Circle inherit from Shape
inherit(Shape, Circle);
//Triangle Shape
function Triangle(base, height, name, color){
Shape.call(this, color, name);
this.radius = radius;
}
//Triangle inherit from Shape
inherit(Shape, Triangle);
//Rectangle Shape
function Rectangle(length, breath, name, color){
Shape.call(this, color, name);
this.radius = radius;
}
//Rectangle inherit from Shape
inherit(Shape, Rectangle);
function inherit(Parent, Child){
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
Treating all kinds of shape as a Shape object yet still able to behave in the form of the different shapes.
const shapes = [
new Circle(10, 'Circle', 'red'),
new Triangle(5, 10, 'triangle', 'black'),
new Rectangle(10, 10, 'rectangle', 'blue')
]
shapes.forEach(shape => shape.draw());
//Circle with color red is drawn!
//triangle with color black is drawn!
//rectangle with color blue is drawn!
All the shapes object are now treated like a single Shape object while they behave differently.
Derived objects can override methods of a base object by providing their own implementations
This concept of having a child object overridding the parent's method is referred to as method overriding. Let's now implement method override for each of the child object of the Shape object by providing different implementation of the draw() method on each child object except the Circle object.
function Shape(color, name){
this.color = color;
this.name = name;
}
Shape.prototype.draw = function(){
console.log(`${this.name} with color ${this.color} is drawn!`);
};
//Circle Shape
function Circle(radius, name, color){
Shape.call(this, color, name); //Calling the base or parent class
this.radius = radius;
}
//Circle inherit from Shape
inherit(Shape, Circle);
//Triangle Shape
function Triangle(base, height, name, color){
Shape.call(this, color, name);
this.base = base;
this.height = height;
}
//Triangle inherit from Shape
inherit(Shape, Triangle);
Triangle.prototype.draw = function(){
console.log(`From Triangle override: ${this.name} with color ${this.color} is drawn!`);
}
//Rectangle Shape
function Rectangle(length, breath, name, color){
Shape.call(this, color, name);
this.length = length;
this.breath = breath;
}
//Rectangle inherit from Shape
inherit(Shape, Rectangle);
Rectangle.prototype.draw = function(){
console.log(`From Rectangle override: ${this.name} with color ${this.color} is drawn!`);
}
function inherit(Parent, Child){
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
const shapes = [
new Circle(10, 'Circle', 'red'),
new Triangle(5, 10, 'triangle', 'black'),
new Rectangle(10, 10, 'rectangle', 'blue')
]
shapes.forEach(shape => shape.draw());
//Circle with color red is drawn!
//From Triangle override: triangle with color black is drawn!
//From Rectangle override: rectangle with color blue is drawn!
The Triangle and Rectangle objects now have their own implementation of the draw method which is slightly different from their ancestor's implementation. The way this works in JavaScript is that when a method or property is invoked on an object, the property is first looked up on the object and if not found, its prototype (parent) is checked for the property and if not found, it continues to the next prototype up the chain until it's found and if eventually, it's not found, the JavaScript engine then errors out.
This concludes the post on polymorphism in JavaScript object oriented programming
Happy coding...
Credits:
Image by LOISLEARNS : https://loislearns.com/2016/08/30/polymorphism/
This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
If you are still following this series, then you are doing really fine. Today we will continue this series with inheritance.
JavaScript doesn't have the concept of classes like in other programming languages like C# or Java. While ES6 introduces the concept of classes, it's just a wrapper around object. Everything in JavaScript is object We will further explain what that means when we talk about ES6 classes.
If you remember, we talked about prototype in our previous post Prototype holds the key to truly understand object-oriented programming in JavaScript. Prototype in JavaScript is simply, parent of another object. So when I use the word prototype, I am referring to the parent of an object e.g If object B inherits from object A, then B's prototype is A.
Inheritance is the ability of an object to take on the property and method of another object. Meaning if object B inherits from object A, then object B should have all the properties and behaviours of object A.
To help solidify JavaScript OOP, we will use the analogy of shapes like Square, Circle, Triangle to illustrate this concept. Suppose we are tasked to implement a solution to store and keep tracks of different shapes, how would we go about designing our system conforming to OOP?
Our focus is on inheritance right now. Let's design out shape application. A shape object with a basic property or method that knows how to draw shapes.
function Shape(){
}
Shape.prototype.draw = function(){
console.log("This shape is drawn");
};
Now we have a base object (Shape) which will serve as a prototype (or parent) to other types of shapes we will implement. Let's create a circle shape that inherits from our base Shape object.
function Circle(radius){
this.radius = radius;
}
//Circle inherits from Shape object
Circle.prototype = Object.create(Shape.prototype);
//Setting the constructor to Circle object
//to allow for creation of new Circle Object
Circle.prototype.constructor = Circle;
The parent object (Shape) has a property draw which is inherited by the the child object (Circle).
Now let's give each shape object color and names without repeating codes. We will further add other shapes such as triangle and rectangle. The list can go on and on for all possible shapes. However, we will stick to few shapes.
function Shape(color, name){
this.color = color;
this.name = name;
}
Shape.prototype.draw = function(){
console.log(`${this.name} with color ${this.color} is drawn!`);
};
//Circle Shape
function Circle(radius, name, color){
Shape.call(this, color, name); //Calling the base or parent class
this.radius = radius;
}
//Circle inherit from Shape
inherit(Shape, Circle);
//Triangle Shape
function Triangle(base, height, name, color){
Shape.call(this, color, name);
this.base = base;
this.height = height;
}
//Triangle inherit from Shape
inherit(Shape, Triangle);
//Rectangle Shape
function Rectangle(length, breath, name, color){
Shape.call(this, color, name);
this.length = length;
this.breath = breath;
}
//Rectangle inherit from Shape
inherit(Shape, Rectangle);
function inherit(Parent, Child){
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
}
Now we have different shapes implementing or inheriting from the Shape object. Let's have a quick look how the children object behave. I have encapsulated the two lines of code of changing the prototypes into a re-usable function inherit to make our code easy to read.
let circle = new Circle(10, 'Circle', 'red'),
triangle = new Triangle(5, 10, 'triangle', 'black'),
rectangle = new Rectangle(10, 10, 'rectangle', 'blue');
In addition to their proprties, all the children objects now have access to the parent(prototype) object property.
This completes the basis of inheritance in object-oriented JavaScript.
Happy Coding...
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
Let's demystify encapsulation in this episode. As a reminder, encapsulation is all about information hiding. In a simple sentence, this means we as developers should try by all means to ensure our internal implementation details never leak to the outside or specific property never get accessed from the outside and also not modifiable from the outside if our intention is not to do so.
By design, JavaScript doesn't have the concept of private access modifiers like in strongly typed languages like C# and Java, but they are ways to ensure a property not intended to be accessed from the outside remains so. We will be looking at ways to ensure encapsulation for our object. We will continue to examine the CassettePlayer object from the last episode:
function CassettePlayer(cassette){
this.cassette = cassette;
this.play = function(){
console.log(`I am playing ${this.cassette}`);
};
this.pause = function(){
//pause cassette
}
this.stop = function(){
//stop playing
};
this.record = function(){
//record onto a cassette
};
this.forward = function(){
//forward cassette
};
this.rewind = function(){
//rewind cassette
};
this.eject = function(){
//eject cassette
};
}
let cassetPlayer = new CassettePlayer("Hip-hop");
cassetPlayer.play() // I am playing Hip-hop
Visualising the CassettePlayer's property:
If you've been following you must have noticed I mentioned there was an issue in the previous post and how we are going to use encapsulation to solve the problem.
the this.cassette property of the CassettePlayer object is not meant to be accessed or modified from outside. This is dangerous as anyone can cause the state of our object to change intentionally or by accident. It is possible to do something like cassetPlayer.cassette = "something else" This should never happen as the CassettePlayer object depends or make use of this property internally.
Let's see how to resolve the problem encapsulating away internal property: To make them private and not accessible from the outside.
let & const keywords
The let and const are introduced to JavaScript in the ECMAScript 6 or ES6 features. They are block-scoped modifiers, meaning if you declare a variable with the let or const keyword, that variable will only be accessible within the block it was declared.One fundamental difference between let and const is that once you declare a variable using const, value of that variable cannot be changed. Apply that to our CassettePlayer object we have:
function CassettePlayer(cassette){
const _cassette = cassette;
this.play = function(){
console.log(`I am playing ${this.cassette}`);
};
this.pause = function(){
//pause cassette
}
this.stop = function(){
//stop playing
};
this.record = function(){
//record onto a cassette
};
this.forward = function(){
//forward cassette
};
this.rewind = function(){
//rewind cassette
};
this.eject = function(){
//eject cassette
};
}
let cassettePlayer = new CassettePlayer("Hip hop");
cassettePlayer.play();
console.log(cassettePlayer);
Our internal variable is now concealed and not accessible from the outside. The CassettePlayer object now satisfies abstraction and encapsulation.
Revealing Module Pattern
The Revealing module pattern is a JavaScript design pattern that supports and enforces encapsulation. This pattern helps you decide what you want to expose and not expose. Let have a look:
function cassettePlayer(cassette){
var _cassette = cassette;
function play(){ console.log(`I am playing ${_cassette}`); }
function pause(){}
function stop(){}
function record(){}
function forward(){}
function rewind(){}
function eject(){}
function connectToWifi(){} // Not accessible!
return {
play: play,
pause: pause,
stop: stop,
record: record,
forward: forward,
rewind: rewind,
eject: eject
};
}
The connect connectToWifi property is not accessible from the outside even if you try to access it.
By all means, this is not the exhaustive list of how to create private properties in JavaScript. In other not to get too ahead of ourselves, we'll stick to these for now. If you want to explore further, have a look at ES6 symbols and weakMaps. Symbols and weakMaps can also be used to create private properties. We will be exploring them further in the future post on ES6.
I hope you have learned something new today.
Happy coding.
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
Let's get to the fun part, see how we can implement abstraction in JavaScript. As a reminder, abstraction is the process of hiding away implementation and internal details and present the user with what's needed. We are going to focus on the cassette player we used in the previous post on abstraction. Remember this?
Let's now represent our cassette player as an object by abstracting away the internal implementation:
function CassettePlayer(cassette){
this.cassette = cassette;
this.play = function(){
console.log(`I am playing ${this.cassette}`);
};
this.pause = function(){
//pause cassette
}
this.stop = function(){
//stop playing
};
this.record = function(){
//record onto a cassette
};
this.forward = function(){
//forward cassette
};
this.rewind = function(){
//rewind cassette
};
this.eject = function(){
//eject cassette
};
}
Now as we have abstracted the CassetPlayer object and do not care about its implementation details. All a user cares about is to play, pause, stop, rewind, forward, record, and eject using the CassettePlayer.
This is abstraction. Present the user or consumer of an object with only what it needs. Keep it simple. There's a small issue which am going to point out and solve it using encapsulation.
We may now call the CassettePlayer object to play a cassette:
let cassetPlayer = new CassettePlayer("Hip-hop");
cassetPlayer.play() // I am playing Hip-hop
Visualising the CassettePlayer's property:
The issue of the CassettePlayer's internal property, cassette leaking to the outside shall be taken care of by implementing encapsulation which we'll look at next.
Happy coding.
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
In the previous part of this series, we went through JavaScript objects and how they work under the hood. As a refresher, JavaScript objects are created at the low-level using new Object(). We will go through Object creation in JavaScript, but bare in mind that almost everything in JavaScript revolves around objects, and inherit from Object's prototype. Now let's examine different way how objects are created in JavaScript. In demonstrating object creation, we will focus on a representing a person.
We've previously gone through creating an object using the Object constructor, but it's worth mentioning again to help solidify the concept.
var person = new Object();
person.id = 123;
person.firstname = "John";
person.lastname = "Fischer"
person.age = 24;
person.showMove = function(){
console.log("I can do a split!");
};
Using the new Object() constructor can be quite convoluted and lengthy, but object literals provide shortcut for creating objects, but under the hood, new Object() is still being used.
var person = {
id: 123,
firstname: "John",
lastname: "Fischer",
age: 24;
showMove : function(){
console.log("I can do a split!");
};
}
Constructor Functions
Constructor functions try to emulate the concept of classes in strongly typed languages such as C# and Java. There are some convention to adhere to though. The naming convention for constructor function starts with uppercase letter and the rest lowe-case letters.
Note: Functions are also objects. A function's prototype points to/inherits from Object which is the root object in JavaScript
function Person(firstname, lastname, age) {
this.firstname = firstname;
this.lastname = lastname;
this.age = age;
this.showMove = function(){
console.log("I can do a split!");
}
}
With this pattern, all kind of Person object can be created say, Bob and Alice.
let alice = new Person("Alice", "Guru", 27);
let bob = new Person("Bob", "Don", 32);
We now have Alice and Bob objects, and more can be created, but always pay attention that the constructor function is always instantiated or activated with the new keyword.
Factory function
Factory function is a pattern for creating objects, and it's reusable. We see how this function can be used to enforce privacy in later series. For now, let's see how to create object using the factory pattern.
function createPerson(firstname, lastname, age) {
return {
firstname,
lastname,
age,
showMove: function(){
console.log("I can do a split!");
}
}
}
let alice = createPerson("Alice", "Guru", 27);
let bob = createPerson("Bob", "Don", 32);
Prototype pattern
Objects can also be created in JavaScript using prototype property of an object. Remember that every created object in JavaScript automatically has a prototype at the time of creation. Let's see how we can use prototype to create an object.
function Person() {
}
Person.prototype.firstname = "Bob";
Person.prototype.lastname = "Guru";
Person.prototype.age = 24;
Person.prototype.showMove = function(){
console.log("I can do a split!");
}
We shall examine prototype property further as it holds the key to OOP in JavaScript.
This concludes the objection creation series. We'll use all we've learned so far in the next coming series to really make sense of OOP in JavaScript.
Happy coding.
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
According to Mozilla, JavaScript is designed on a simple object-based paradigm, and an object is a collection of properties, and property is an association between a name(or key) and a value. A property's value can be a function, in which case the property is known as a method.
In other words, an object is a collection of key=value pair.
e.g firstname = "John", lastname = "Fischer" . These two key-value pair can make up an object
To represent a Person object in JavaScript, let's use Object with is JavaScript in-built. It's the low-level way of creating an object.
var person = new Object();
person.firstname = "John";
person.lastname = "Fischer"
person.age = 24
The person object has three properties, firstname, lastname, and age. Remember a property's value can also be a function which is refered to as a method. Methods add behaviour to an object. Let's add a behaviour to the person object.
person.showSkill = function(){
console.log("I can code in JavaScript")
}
It's possible to add more property to the object because JavaScript is a dynamic language and that's powerful.
Now, this is the main thing that answers all questions you may have about OOP in JavaScript.
What is prototype ?
In simple English, a prototype is a blueprint, first design, a layout etc. It is what it says.
In almost every invention that has ever existed, they can all be traced to a prototype or a blueprint of some sort.
Note: When an object is created in JavaScript, a prototype object is also created and associated with that object.This happens all the time and almost all JavaScript's object prototype is Object
Let's inspect the person object we created earlier
Almost every object in JavaScript has prototype pointing to Object in JavaScript.
An object's prototype can be accessed by using the __proto__ or prototype properties.
The prototype property of an object is used to access an object's prototype in constructor functions, functions that are instantiated using the new keyword
__proto__ property is used to access prototype on object's instance.
e.g person.__proto__ & <constructor function >.prototype. The person object we saw earlier is an example of an instance of an object which is Object, we can say person object is an instance of Object. From the person object above, we can clearly see there's no prototype property, but __proto__ property.
Constructor is found on the prototype object's property; it's a pointer or reference back to an object as the creator. This feature can be dynamically used to create an object dynamically, but that's a more advanced topic.
All objects in JavaScript are descended from Object; all objects inherit methods and properties from Object.prototype
The Object constructor creates an object wrapper for the given value.
Every property available on the Object prototype is also available to all object created in javaScript. Object represents the global JavaScript Object. Object constructor and methods are preffered way of implementing prototypical inherirance and object creation. We will be seeing more of the Object constructor in action in the next series.
In conclusion, almost everything in JavaScript resolves around Object. Understanding how Object works under the hood will pave way to understanding how OOP work in JavaScript. If the concepts of prototype is not very clear. We shall cement that in the next series.
Happy coding !
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
]]>This post is part of a series of posts on JavaScript object-oriented programming. Link to the series are as follows:
This series is as follows:
Object-oriented programming has four pillars which we will quickly go over. These pillars or concept define or set some guidelines on how to write codes to represent objects with characteristics and behaviours. E.g., A person may be described as an object with attributes like first name, last name, date of Birth and a person can eat, walk, run, and dance.
The four pillars are namely, Abstraction, Encapsulation, Inheritance, and Polymorphism.
An abstraction in object-oriented programming (OOP) is the process of hiding away the complexity of an object's internal implementation details and present relevant information without noise. An example of abstraction in the real world is a simple cassette player
This cassette player has few buttons on it, but the implementation details of how the electronics embedded inside work are abstracted away, it's hidden, and all that's useful to a music listener is the play, pause, forward, rewind and record buttons. The details of how the capacitors, diode , resistors, circuit board work is of no importance and as a music listener, I don't know want know either.
In a simple sentence, encapsulation is the process of hiding internal details or implementation from the outside such that it helps prevent tampering and accidental modification. As you programming more and create objects, you will quickly realise some details should never leak as a result of our code which could lead to serious problems like data breach, losing sensitive data and confidentiality. Different programming languages use different implementation to achieve encapsulation. In the coming post, we will see how we can implement encapsulation in JavaScript which is a bit different from strongly typed languages like C# and Java.
Inheritance in OOP is just like inheritance in real life whereby a child inherits the parent(s) trait(s) such as eye colours, height etc. Inheritance describes an "IS-A" relationship e.g. a dog is an Animal etc. Inheritance in OOP helps reduce code duplication by re-using codes or sharing codes. E.g. You are writing an application for a vet. You have to ensure that your application can handle check-in and check-out of all kinds of animal. The only way to make this possible is by re-using code. In this case, you will have a base object called Animal with general characteristics animal characteristics and have, e.g. dogs; cat inherits from the Animal class. In conclusion, inheritance is the ability of a child object to inherit a parent object properties and behaviours in addition to its own.
Poly means many, and morphism means forms. Polymorphism is the ability of an object to exist or represented in many forms. In OOP, child or children object may inherit behaviour from a parent object and override or implement that object differently from the parent. In conclusion, polymorphism is the ability of an object to change behaviour at runtime.
Composition is an important OOP concept worth mentioning. It's not one of the four listed pillars of OOP, but OOP is not complete without it. Unlike inheritance, composition is a "HAS-A" relationship. A dog is an animal, but a dog has an owner. An object representing a dog will relate to the animal object by inheritance, but relate to owner through composition.
This concludes the information needed to delve into the concepts of OOP deeper.
]]>For a while, the concept of OOP in Javascript bewildered me that I tried on several occasions to avoid it in the past. Avoiding it didn't help, it kept haunting me everywhere I turned as a software developer. Having been in such position, I will help you demystify Object Oriented
]]>For a while, the concept of OOP in Javascript bewildered me that I tried on several occasions to avoid it in the past. Avoiding it didn't help, it kept haunting me everywhere I turned as a software developer. Having been in such position, I will help you demystify Object Oriented Programming in JavaScript, and you will never be scared again just like I was.
This post will be divided up into mini-series to help us keep things light, easy to grasp and remember. These series assume you have some knowledge of Javascript and you want to understand how OOP works in JavaScript.
This series is as follows:
We now have our content structure to follow, let's get started here: Pillars of Objected-Oriented Programming
]]>In this post, I try to leave out the intricacies of the SOLID principle and write about it succinctly in detail, but yet simple codes samples. Let’s get started
The SOLID principle is a design pattern that enables and disciplines us to write reusable, decoupled, and maintainable code. That
]]>In this post, I try to leave out the intricacies of the SOLID principle and write about it succinctly in detail, but yet simple codes samples. Let’s get started
The SOLID principle is a design pattern that enables and disciplines us to write reusable, decoupled, and maintainable code. That is as simple as it can get.
Now, we know what the SOLID principles want to get out of us, let’s briefly talk about what makes a code SOLID. SOLID codes have to satisfy SOLID principle checklist which leads us to the SOLID acronym and what it means.
Let’s go throw each with code walkthrough
A class should have only one reason to change
SRP says that a class should focus on one specific thing rather than do multiple things. The SRP simple does not mean a class should have only one method, but everything the class does should revolve around one thing.
For example, a Person class might have the responsibility of carrying out a various operation such as creating a new person’s record, update, delete, and retrieve from a data store. The class can also be tasked on how to present information to a user such as print, display, sending email, logging etc.
Mixing up responsibility makes a class unmaintainable, challenging to understand and makes writing unit tests a nightmare because the responsibilities cannot be separated and thus ultimately violates SRP.
Let’s see an example of SRP violation:
public class Person
{
public Guid PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
private decimal Salary { get; set; }
private string Mydocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public string FullName()
{
return $"{FirstName} - {LastName}";
}
public decimal GetSalary()
{
return this.Salary;
}
public void IncreaseSalary(decimal percentage)
{
this.Salary += this.Salary * percentage;
}
public void SavePerson()
{
try
{
// code for saving person to a data store
//After a person has been saved, we send confirmation email
var mailMessage = new MailMessage("MailFrom", "MailTo", "Subject", "Body");
this.SendEmail(mailMessage);
}
catch (Exception e)
{
System.IO.File.WriteAllText(this.Mydocpath + @"\Exceptionsfile.txt", e.ToString());
}
}
public void SendEmail(MailMessage mail)
{
try
{
// Code for getting Email setting and send mail
}
catch (Exception e)
{
System.IO.File.WriteAllText(this.Mydocpath + @"\Exceptionsfile.txt", e.ToString());
}
}
}
The Person class violates SRP, as it behaves like a God Object. A God Object is a class which does everything. An example of a God Object is this:
The Swiss army knife in the pictures does so much than just being a pocket tool. It can also store your files .
Back to the Person class which carries out own responsibilities such as get full name, get a salary, increase salary and also sending emails and logging as well.
The "A class should have only one reason to change" will not be met if for example, you want to modify the email, logging functionalities or perhaps writing a unit test to test each feature.
Let's refactor the code to satisfy SRP
public class Person
{
public Guid PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
private decimal Salary { get; set; }
private FileLogger fileLogger;
private MailSender mailSender;
public Person()
{
fileLogger = new FileLogger();
mailSender = new MailSender();
}
public string FullName()
{
return $"{FirstName} - {LastName}";
}
public decimal GetSalary()
{
return this.Salary;
}
public void IncreaseSalary(decimal percentage)
{
this.Salary += this.Salary * percentage;
}
public void SavePerson()
{
try
{
// code for saving person to a data store
//After a person has been saved, we send confirmation email
//Abstracting away how email is being sent
fileLogger.Info("Add method Start");
// Code for adding invoice
// Once Invoice has been added , send mail
mailSender.From = "[email protected]";
mailSender.To = "[email protected]";
mailSender.Subject = "Verification";
mailSender.Body = "This is an email message for Bob and Alice";
mailSender.SendEmail();
}
catch (Exception e)
{
fileLogger.Error("Exception message", e);
}
}
}
public interface ILogger
{
void Info(string info);
void Debug(string info);
void Error(string info, Exception e);
}
public class FileLogger : ILogger
{
private string MyDocpath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public FileLogger()
{
//Initialization code(s)
}
public void Info(string info)
{
// Code for details to text file
}
public void Debug(string info)
{
// Code for debug information to text file
}
public void Error(string message, Exception ex)
{
// Code for erros with message and exception details
}
}
public class MailSender
{
public string From { get; set; }
public string To { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
public void SendEmail()
{
// Code for sending mail
}
}
Now the Person class can focus on what it knows how to do best, and that is how to create, save, calculate salary about a user and cares less about sending emails or logging hence satisfies the Single Responsibility Princciple. The other tasks of logging and email sending are delegated to the responsible classes separating the concerns and responsibilities.
Software entities (classes, modules, functions, etc) should be open for extension , but closed for modification.
To put it in a simple sentence, change a class behaviour using inheritance and composition.
"Open for extension" means we ought to design our classes in a way that will allow new feature or functionality to be added when new requirements arise or a change of request comes up. "Closed for modification means" we should not alter codes that have already gone through design, coding, unit testing and it is in-production unless it is a bug.
Let's demonstrate OSP using codes using a Shape class.
OSP violation:
public enum ShapeType
{
Triangle, Rectangle, Circle
}
public class Shape
{
public ShapeType ShapeType { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public string CalculateArea( )
{
var calculatedArea = default(double);
if (ShapeType == ShapeType.Triangle)
{
calculatedArea = Height * Width;
}else if (ShapeType == ShapeType.Triangle)
{
calculatedArea = 0.5 * Width * Height;
}
else if(ShapeType == ShapeType.Circle)
{
calculatedArea = Math.PI * Math.Pow(Height, 2);
}
return calculatedArea.ToString(CultureInfo.InvariantCulture);
}
}
Now, this simple Shape class represents a shape and calculates its area. This scenario will work well without issues only if we have to calculate only three shapes, Triangle, Rectangle Circle. What if we need to calculate the area of a sphere tomorrow or a rhombus? We will have to alter the Shape class and add one or more if condition to satisfy the requirement and equally alter the enum to add the new type of shape. Adding more if conditions to cater to new shapes will quickly run out of hands and make the code unmaintainable and difficult to test. Hence, the class is not "closed for modification".
Let's make the Shape class "Open for extension, but closed for modification" hence satisfying OSP.
public abstract class Shape
{
public abstract double CalculateArea();
}
public class Triangle : Shape
{
public double Base { get; set; }
public double Height { get; set; }
public override double CalculateArea()
{
return 0.5 * Base * Height;
}
}
public class Cirle : Shape
{
public double Radius { get; set; }
public override double CalculateArea()
{
return Math.PI * (Radius * Radius);
}
}
Now that looks much better. The Shape class is now closed for modification because to add a new feature of calculating a new shape, we don't alter or modify the Shape class. Instead, we extended it by using inheritance.
Extending the Shape class further by adding the rhombus shape will look like this:
public class Rhombus : Shape
{
public double Diagonal { get; set; }
public override double CalculateArea()
{
return (1/2) * Diagonal * Diagonal;
}
}
Viola! we have satisfied OSP.
Objects in a program should be replacable with instances of their subtypes without altering the correctness of the that program.
In a simple translation, a child class can replace a parent class in a code, and it should not break that code. e.g. If class Dog is a child(derived class) of class Animal(base class), then instances of Dog can replace the instance of Animal without issue. Liskov substitution principle goes a bit deeper, but for a simple explanation is a good starting position.
Note: LSP is about honoring contracts and not intending to change the behaviour of a base class.
The code below violates LSP in that derived class Square changed the behaviour of the base class.
Violation of LSP:
public class Rectangle
{
public virtual Int32 Height { get; set; }
public virtual Int32 Width { get; set; }
public virtual void CalculateArea()
{
Console.WriteLine($"The area is: {Height * Width}");
}
}
public class Square : Rectangle
{
public override Int32 Height
{
get => base.Height;
set => SetDimensions(value);
}
public override Int32 Width
{
get => base.Width;
set => SetDimensions(value);
}
private void SetDimensions(Int32 value)
{
base.Height = value;
base.Width = value;
}
}
Giving the above code, a quick run, the output says The area is 9, which is correct as the area of a square is (width)2. But! this violates the LSP that states that a derived class should replace a base class without breaking or altering the program.
static void Main(string[] args)
{
Rectangle rectangle = new Square();
rectangle.Height = 2;
rectangle.Width = 3;
rectangle.CalculateArea(); // The area is 9
Console.ReadKey();
}
Let implement the code to become LSP compliant. The solution to this problem is not straightforward, but let have a look. Remember the OCP, if a code is OCP complaint, that code is more likely to be LSP compliant as well. As a rule of thumb, try to move implementation that may differ to the derived classes and leave the more general implementation to the base class.
public interface IShape
{
void CalculateArea();
}
public class Square : IShape
{
public double Width { get; set; }
public void CalculateArea()
{
Console.WriteLine($"The area is {Math.Pow(Width, 2)}");
}
}
public class Rhombus : IShape
{
public double Diagonal { get; set; }
public void CalculateArea()
{
Console.WriteLine($"The area is: {(1 / 2) * Diagonal * Diagonal}");
}
}
The base class IShape contract is now implemented by Square and Rhombus with no violation by not allowing the subclasses to change the behaviour of the base class.
Important: If a code is OSP complaint, it is likely, it is LSP complaint as both go hand in hand.
No client should be forced to depend on methods it does not need. Split large interfaces into smaller and more specific ones so clients can pick and choose methods that are of interest to them.
In a simple sentence, this means a derived class should only implement what it needs and not all methods in the parent class or interface.
Using the analogy of a manager, a lead developer, and a developer.
Violation of ISP:
public interface ILead
{
void CreateSubTask();
void AssginTask();
void WorkOnTask();
}
public class Developer : ILead
{
public void CreateSubTask()
{
throw new Exception("Cannot create subtasks");
}
public void AssginTask()
{
throw new Exception("Cannot assign tasks");
}
public void WorkOnTask()
{
//codes to implement working on tasks
}
}
public class LeadDeveloper : ILead
{
public void CreateSubTask()
{
//code to create subtasks
}
public void AssginTask()
{
//code to assign tasks
}
public void WorkOnTask()
{
//codes to implement working on tasks
}
}
public class Manager : ILead
{
public void CreateSubTask()
{
//code to create subtasks
}
public void AssginTask()
{
//code to assign tasks
}
public void WorkOnTask()
{
throw new Exception("Manager cannot work on programming tasks");
}
}
We have three roles in that a Manager cannot work on tasks and no can assign a task to a manger aside from the manager's boss if there's another layer of hierarchy. But the Manager implements the WorkOnTask() method it doesn't need. Same for the Developer class, a developer cannot create subtasks and assign tasks hence should not be implementing both methods. As for the LeadDeveloper, it implements all method on the ILead interface as needed.
The solution is to split the interfaces into manageable chunks to clients can pick and choose what they need to implement.
public interface ILead
{
void CreateSubTask();
void AssginTask();
}
public interface IProgrammer
{
void WorkOnTask();
}
public class Developer : IProgrammer
{
public void WorkOnTask()
{
//codes to implement working on tasks
}
}
public class LeadDeveloper : ILead, IProgrammer
{
public void CreateSubTask()
{
//code to create subtasks
}
public void AssginTask()
{
//code to assign tasks
}
public void WorkOnTask()
{
//codes to implement working on tasks
}
}
public class Manager : ILead
{
public void CreateSubTask()
{
//code to create subtasks
}
public void AssginTask()
{
//code to assign tasks
}
}
High level modules should not depend on low level modules, Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions
In a simple sentence, high-level modules and low-level module should be loosely coupled as much as possible. They need not know the detail implementation of each other, in other words, they should depend on a contract.
Let's use the example of a notification system where we can either send Email, SMS or Mail depending on a user choosing. Alternatively, all three if the user opt-in for all.
public class Email
{
public string ToAddress { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public void SendEmail()
{
//Send email
}
}
public class SMS
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void SendSMS()
{
//Send sms
}
}
public class Mail
{
public string Address { get; set; }
public string Message { get; set; }
public void SendMail()
{
//Send Mail by post
}
}
public class Notification
{
private Email _email;
private SMS _sms;
private Mail _mail;
public Notification()
{
_email = new Email();
_sms = new SMS();
_mail = new Mail();
}
public void Send()
{
_email.SendEmail();
_sms.SendSMS();
_mail.SendMail();
}
}
As we can see from the code sample above, the higher-level (Notification) module has dependencies on Email, SMS, and Mail modules, which are lower-level modules which violate DIP, and the also violates Single Responsibility Principle.
public interface IMessage
{
void SendMessage();
}
public class Email : IMessage
{
public string ToAddress { get; set; }
public string Subject { get; set; }
public string Content { get; set; }
public void SendMessage()
{
//Send Email
}
}
public class SMS : IMessage
{
public string PhoneNumber { get; set; }
public string Message { get; set; }
public void SendMessage()
{
//Send SMS
}
}
public class Mail : IMessage
{
public string Address { get; set; }
public string Message { get; set; }
public void SendMessage()
{
//Send Mail by post
}
}
The Notification system can now do one thing and one thing only. Send message without bothering about the implementation details, but depend on abstraction.
public class Notification
{
private ICollection _messages;
public Notification(ICollection messages)
{
this._messages = messages;
}
public void SendMessage()
{
foreach(var message in _messages)
{
message.SendMessage();
}
}
}
This concludes SOLID principles. Hope you've learned something today. Happy Coding!
]]>