Wednesday, January 23, 2019

Harry Potter Kata Written in C#(C Sharp) .net

So I've been looking at some Kata lately and trying to see how they can be approached in different ways.

My initial attempts were pretty poor and didn't have the scalability of testing.

I've since thought about the issues I've tried to address them.

The original Kata can be found on http://codingdojo.org/kata/Potter/

Like with most coding problems you need to take a step back and understand the problem you are trying to solve.

In this case the approach was quite simple, spin up an excel sheet, ensure that we are the results we expect.

So lets look at prices without the discount

for 1 Book the price would be 8
for 2 Books the price would be 16
for 3 Books the price would be 24
for 4 Books the price would be 32
for 5 Books the price would be 40

The with discounts applied:

so in excel we can simply use:
8 * 1 = 0% Discount
16 * 0.95 = 5% Discount
24 * 0.90 = 10% Discount
32 * 0.80 = 20% Discount

Alternative way to work out percentage is (N / 100) * Percentage,

so for example to calculate 5% discount it would be  16 - ((16 / 100) * 5)  = 15.2

for 1 Book the price would be 8
for 2 Books the price would be 15.2
for 3 Books the price would be 21.60
for 4 Books the price would be 25.60
for 5 Books the price would be 30



Our data representation


Ok, so now we have understood the problem, we can look at possible solutions.

I opted for lists of lists, this was to clearly separate the books and make it easier to calculate against.  My original implementation included quantities, but I found this tricky to reduce down and calculate against.  Maybe you know a better way?

If this was to be used on the frontend of a site we could easily cycle through and display the number of books.

I started using XUnit, this is by far better than NUnit and MS Test as it can been extended.  We can use setup coverage tests which allow us to run through several different scenarios.

Below we setup several scenarios in which order to test.  This helps us in several different ways, we can reuse the same test, increase coverage and keep our tests clean.

InlineData will allow us pass through the given parameters for each test as shown below.



So for the next stage we needed to look at the discount mechanism, so how could we know what discount to apply?

Well there are probably a lot of more complex ways to solve this, but sticking to KISS principles I've kept it simple.

Ok, so basically we have a series of cases in a switch statement.  This will allow us to add different logic or discounts as required.  Ideally these would be abstracted away and then created in more flexible generic way for a real application, but for now this fulfills its purpose for this test. 


For the discounts tests, I have made it so we can pass the first parameter to check against the price and the amount of books that we want to test against.  Again we can always go further with these tests and add in mutations, but it proves our code is working as expected for these sequences of books.  Another approach might be to randomise the books in our lists and mix them up.  We could also look at removing specific books systematically then testing again.  

It all boils down to that question "How far do you want to go?" and "Is the code behaving as expected?"


Anyway hopefully this has given you some insights in my though process.  This code is available on GitHub and open to anyone's comments on how this could be made more elegant.

Have Fun and the code can be find in the repo below.

HarryPotterKataV2 Repository

Wednesday, November 7, 2018

Dependency Injection - AutoFac in C#

Context

These examples will mainly be from an MVC based solution in C#.  The principles however will be very similar for any other application.

Audience

You should have basic knowledge of what Dependency Injection is and understand why we use interfaces.  Domain Driven Design Knowledge would also be benefit when creating projects using DI.

Example

Nuget Package Required is ASP.NET MVC 5 Integration for Autofac 4.0.2

Full Example: https://github.com/netferret/AutoFacExample

Bootstrapping AutoFac in an MVC based project.
 using Autofac;  
 using Autofac.Integration.Mvc;  
 using AutoFacExample.Domain.Service.Abstract;  
 using AutoFacExample.Domain.Service.Concrete;  
 using System;  
 using System.Collections.Generic;  
 using System.Linq;  
 using System.Web;  
 using System.Web.Mvc;  
 using System.Web.Optimization;  
 using System.Web.Routing;  
 namespace AutoFacExample  
 {  
   public class MvcApplication : System.Web.HttpApplication  
   {  
     protected void Application_Start()  
     {  
       var builder = new ContainerBuilder();  
       builder.RegisterType<ExampleService>().As<IExampleService>();  
       builder.RegisterControllers(typeof(MvcApplication).Assembly);  
       builder.RegisterModelBinders(typeof(MvcApplication).Assembly);  
       builder.RegisterModelBinderProvider();  
       builder.RegisterModule<AutofacWebTypesModule>();  
       builder.RegisterSource(new ViewRegistrationSource());  
       builder.RegisterFilterProvider();  
       var container = builder.Build();  
       DependencyResolver.SetResolver(new AutofacDependencyResolver(container));  
       AreaRegistration.RegisterAllAreas();  
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);  
       RouteConfig.RegisterRoutes(RouteTable.Routes);  
       BundleConfig.RegisterBundles(BundleTable.Bundles);  
     }  
   }  
 }  

Firstly we will look at the lines in order to hook up our service,  we have created a very basic service which will take a string and then return the string with the current date and time.  This is specified as ExampleService which implements IExampleService interface.

Its important that ExampleService inherits IExampleService in order for dependency injection to work correctly.

ContainerBuilder will need register all of the Services, Controllers, Views and Models.

Ok so lets break this down

Register our example service
builder.RegisterType<ExampleService>().As<IExampleService>();  

Register all controllers
       builder.RegisterControllers(typeof(MvcApplication).Assembly);  

Register all our models
       builder.RegisterModelBinders(typeof(MvcApplication).Assembly);  
       builder.RegisterModelBinderProvider();  

Register Views for System.Web.Mvc.WebViewPage, System.Web.Mvc.ViewPage, System.Web.Mvc.ViewMasterPage and System.Web.Mvc.ViewUserControl derived types
builder.RegisterSource(new ViewRegistrationSource());  

Ok, so by now you should understand how the bootstrapping works for AutoFac, so next let look at how we hook this up to a standard controller.

We have a standard controller setup called HomeController, this will resolve as usual, however we want to add some logic from our Example Service

First we need to inject our Example Service into the controller which will automatically resolve using AutoFac.  As you look at the pattern you will see why this approach is so effective as you can mix & match services and switch out functionality based on your needs.

  private IExampleService _exampleService;  
     public HomeController(IExampleService exampleService)  
     {  
       _exampleService = exampleService;  
     }  

ok so now we have setup our service, so how do we know its hooked and how can we use it?

Well this is pretty straight forward as well, so usually we would just return ActionResult and return a View Model, but for the sake of this example lets keep it really simple. 

The following will output a string with the current date and time. Everytime its refeshed the date and time should update.

  public string Index()  
     {  
       var result = _exampleService.GetMessage("Welcome to our first example using AutoFac.");  
       return result;  
     }  

The result should then be something very similar to this.