Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Tuesday, 14 July 2015
( SOLID )

http://bit.ly/coffeeheuristics

Pretty good fit for the Observer pattern

IObserver<T> is part of the framework, but no implementations.  They are in ReativeExtensions

SRP as only has 1 reason to change - ie should just react to WarmerPlateStatus values.. ie it just sets the WarmerPlate to a different state.

Dependency Inversion Principle - injecting in.. doesn't depend on details

Very easy to test

Use Rx to poll every second:

  • GetBrewButtonStatus
  • GetBoilderStatus
  • GetWarmerPlaceStatus
| | # 
# Friday, 10 July 2015
( SOLID )

Why write better code?

  • Long term productivity
  • Maintainability

Make clearer code

Make it obvious what a method does ie name, return type, Command/Query

CQS - Command Query Separation

If follow CQS can trust the codebase / easier to reason about the code without fully understanding the implementation details.

Commands - has side effects eg Write file to disk.  Returns void.
Query - returns data (safe to invoke... does not affect anything...so can have confidence to use)

Fail fast and give good exception messages

Nullable References are Evil

Value types eg ints, decimals, bools are non-nullable by default

Ref types eg Classes are nullable.

  • Never return null.. if need the concept of a value not being present then
    • Read returns a Maybe of string.. invalid states are impossible
// Return value may be there, and may not be // and don't want to return null as it is tainted // want a collection of 0 or 1 strings // IEnumerable<string> is too wide as it could have 10 elements // Maybe<T> can return 0 of 1 <T> public Maybe<string> Read(int id) { var path = this.GetFileName(id); if (!File.Exists(path)) return new Maybe<string>(); var message = File.ReadAllText(path); return new Maybe<string>(message); } public void Tester() { // this method may, or may not return a string Maybe<string> thing = Read(49); var message = thing.DefaultIfEmpty("").Single(); }

SOLID

Productive, Maintainable, through decomposition

  • Single Responsibility (SRP)
  • Open Closed (OCP)
  • Liskov Substitution (LSP)
  • Interface Segregation (ISP)
  • Dependency Inversion (DIP)

Single Responsibility Principle

  • A class should have only 1 reason to change  (do 1 thing and do it well)
  • Separation of concerns eg caching/logging

Interface Segregation Principle

Favour Role Interfaces - defines very few members.. even 1

over Header Interfaces - extracted..essentially all the methods.. big interfaces

Dependency Inversion

Favour composition over inheritence

Decorator (Russian Doll)

| | # 
# Thursday, 09 July 2015
( SOLID )

Cross cutting concerns - Logging, Caching... can be factored away with decorators

Business logic left in the class

Solid is a reaction to design smells

rigidity

solid is supple, allowing us to change in direction and requirements as we go along

Code Review

Faced with a codebase I still don't understand, my strategy is:

  • Get it compiling!
  • Run unit tests
  • Make new unit tests to step through code
  • Make a diagram of how it all works
  • Start a new project, and just rip out the simplest section (Saving) to understand pattern
  • Explore different parts of code eg SpySink for testing how logging works
| | # 
# Tuesday, 07 July 2015
( SOLID )

"High-level modules should not depend on low-level modules.
Both should depend on abstractions"

"Abstractions should not depend upon details
Details should depend upon abstractions"

Favour composition over inheritance

Bertrand Meir - talked about inheritance all the time.  He invented Eiffel, which allows for multiple inheritance, so didn't need interfaces in that language.

Composite

A design pattern - a special implementation of an interface.

A handy way of getting rid of implementation detail of what a Save is..

// A Command (returns void) public void Save(int id, string message) { // 4 Commands that take id as an argument //this.log.Saving(id, message); //this.store.Save(id, message); //this.cache.Save(id, message); //this.log.Saved(id, message); // Calls the compositeWriters save this.writer.Save(id, message); }

it is composed in the ctor of the MessageStore

public MessageStore(DirectoryInfo workingDirectory) { // Fail fast.. so can't have an invalid state of no working directory if (workingDirectory == null) throw new ArgumentNullException("There must be a working directory passed to save to"); if (!Directory.Exists(workingDirectory.FullName)) throw new ArgumentException("The workingDirectory must exist", "workingDirectory"); this.WorkingDirectory = workingDirectory; this.log = new StoreLogger(); var c = new StoreCache(); this.cache = c; var fileStore = new FileStore(workingDirectory); this.store = fileStore; this.fileLocator = new FileLocator(); // Deterministic order this.writer = new CompositeStoreWriter( new LogSavingStoreWriter(), fileStore, c, new LogSavedStoreWriter()); }

And here:

public class CompositeStoreWriter : IStoreWriter { private IStoreWriter[] writers; public CompositeStoreWriter(params IStoreWriter[] writers) { this.writers = writers; } public void Save(int id, string message) { foreach (var w in this.writers) w.Save(id, message); } }

Works well with composing commands - save doesn't return anything

2015-07-07 06.53.48

Decorator (Russian Doll model)

If want to compose queries, decorator is better.

// IStore Writer is the role interface that defines the Save method public class StoreCache : IStoreCache, IStoreWriter { private ConcurrentDictionary<int, Maybe<string>> cache; public StoreCache() { this.cache = new ConcurrentDictionary<int, Maybe<string>>(); } public void Save(int id, string message) { var m = new Maybe<string>(message); // add key, value or update with int, string message this.cache.AddOrUpdate(id, m, (i, s) => m); } // A Function that takes an int and returns a string // the signature of the ConcurrentDictioary GetOrAdd method public Maybe<string> GetOrAdd(int id, Func<int, Maybe<string>> messageFactory) { return this.cache.GetOrAdd(id, messageFactory); } }

Before decorator

// IStore Writer is the role interface that defines the Save method public class StoreCache : IStoreCache, IStoreWriter { private readonly IStoreWriter writer; private ConcurrentDictionary<int, Maybe<string>> cache; public StoreCache(IStoreWriter writer){ this.cache = new ConcurrentDictionary<int, Maybe<string>>(); this.writer = writer; } public void Save(int id, string message) { // If you squint it could be base.Save(id, message) // favouring composition over inheritance this.writer.Save(id, message); var m = new Maybe<string>(message); // add key, value or update with int, string message this.cache.AddOrUpdate(id, m, (i, s) => m); }

after

// Applied decorator pattern to the StoreCache // so when Save is called on the StoreCache // it actually calls Save on the fileStore.. the 'base' // before, as they both implement IStoreWriter var c = new StoreCache(fileStore); this.cache = c; this.log = new StoreLogger(); this.store = fileStore; this.fileLocator = new FileLocator(); this.writer = new CompositeStoreWriter( new LogSavingStoreWriter(), c, new LogSavedStoreWriter());

image

The 'Russian Doll' model

| | # 
# Monday, 06 July 2015
( SOLID )

Functional

"Objects are truly a poor mans closures!"
"Closures are poor mans objects!"

SRP - end up with lots of small classes
ISP - extreme version of role interface with only has 1 method

So have lots of fine grained classes with a single method

Objects are data with behaviour

// An object is data with behaviour public class FileStore : IMessageQuery { // The data of the object private DirectoryInfo workingDirectory; public FileStore(DirectoryInfo workingDirectory) { this.workingDirectory = workingDirectory; } // The behaviour of the object public string Read(int id) { var path = Path.Combine( this.workingDirectory.FullName, id + ".txt"); return File.ReadAllText(path); } } public interface IMessageQuery { string Read(int id); }


Functions are pure behaviour

// Functions are pure behaviour... no data captured // same thing as the object does // takes workingDirectory and id (DirectoryInfo and int) as input // returns string as output Func<DirectoryInfo, int, string> read = (workingDirectory, id) =>{ var path = Path.Combine( workingDirectory.FullName, id + ".txt"); return File.ReadAllText(path); };

Closures

// An outer variable var workingDirectory = new DirectoryInfo(Environment.CurrentDirectory); // This function 'closes over' or captures the workingDirectory Func<int, string> read = id => { var path = Path.Combine( workingDirectory.FullName, id + ".txt"); return File.ReadAllText(path); };

However this actually compiles (to IL, but then back to C# as)

image

So it has data and behaviour.. so closures are behaviour with data

What's more lightweight?

Don't need to come up with a name for the concrete class in a closure or interface.. just need a name for the function

| | # 
# Monday, 29 June 2015
( SOLID )

Clients should not be forced to depend on methods they do not use

Favour Role Interfaces - defines very few members.. even 1

over Header Interfaces - extracted..essentially all the methods.. big interfaces

| | # 
( SOLID )

Commonly programmers react badly when they see a 'SOLID' codebase - as it has lots of small classes

- same amount of code
- arranged differently

- prefer 100's of classes which are all very small

| | # 
# Thursday, 25 June 2015
( SOLID )

"Consume any implementation without changing the correctness of the system"

ReadOnlyCollection<T> breaks LSP,
because it implements ICollection<T> which has Add and Clear methods
which now throw new NotSuportedException()

Reused Abstractions Principle - have more than 1 implementation of an interface

FileStore is currently a base class (as members are virtual and can be overridden)

want to use MSSQL

// SqlStore derives from FileStore.. strange public class SqlStore : IStore { public void WriteAllText(string path, string message){ // Write to db } public string ReadAllText(string path){ // read return null; } public FileInfo GetFileInfo(int id, string workingDirectory){ throw new System.NotSupportedException(); } }

GetFileInfo is a problem..doesn't mean anything.

More interaction between members of an Interface, the most we'lll probably violate LSP

Refactorings towards a more flexible interface

| | # 
( SOLID )

Open for extensibility
Closed for modification

If you've put the class into production/others rely on it, then shouldn't makes changes.

However if you control the entire codebase, then don't need OCP - can use a refactoring tool eg R#

eg Open Source software - don't control who uses it, so don't want to introduce breaking changes

 

If want to redefine the behaviour, extend it

Favouring composition over inheritance

Strategy Pattern
asdf

Make methods Virtual
Eg StoreLogger if we want to have Log4NetStoreLogger : StoreLogger

then can override all the base class's methods

Factory Method
Creates an instance of a polymorphic class

// A Query (so this shouldn't have any side effects) public FileInfo GetFileInfo(int id) { // This can never be null as int is a value type, and workingDirectory is a pre-condition // talking to the virtual Property now (which can be overridden) return this.Store.GetFileInfo( id, this.WorkingDirectory.FullName); } // Factory readable properties (compiles to a method) // virtual means can be overridden protected virtual FileStore Store { get { return this.fileStore; } } protected virtual StoreCache Cache { get { return this.cache; } } protected virtual StoreLogger Log { get { return this.log; } }

So can override any of these Factory Methods and return  something else eg Log4NetStoreLog

This gets messy though. Not the preferred way! As want to favour composition.

Append Only
If you can't change the code you've already written...

Strangler pattern

| | # 
# Tuesday, 23 June 2015
( SOLID )

Mark Seemann's course again on Pluralsight

Test app is FileStoreTest4

Logging
to its own class

StoreCache
Using a ConcurrentDictionary

// Gets message from the cache, or if not there, gets then adds it var message = this.cache.GetOrAdd( id, arg => this.fileStore.ReadAllText(file.FullName));
public class StoreCache { private ConcurrentDictionary<int, string> cache; public StoreCache() { this.cache = new ConcurrentDictionary<int, string>(); } public void AddOrUpdate(int id, string message) { // add key, value or update with int, string message this.cache.AddOrUpdate(id, message, (i, s) => message); } // A Function that takes an int and returns a string // the signature of the ConcurrentDictioary GetOrAdd method public string GetOrAdd(int id, Func<int, string> messageFactory) { return this.cache.GetOrAdd(id, messageFactory); } }

FileStore
Renamed the overall class to be MessageStore, and created a FileStore class to write to the filesystem

Reused Abstraction Principle
If we want to make things more general (discover that we need as we go along)

public class FileStore : IStoreWriter, IStoreReader, IFileLocator { public void WriteAllText(string path, string message){ File.WriteAllText(path, message); } public string ReadAllText(string path){ return File.ReadAllText(path); } public FileInfo GetFileInfo(int id, string workingDirectory){ return new FileInfo( Path.Combine(workingDirectory, id + ".txt")); } }

Abstractions - elimination of the irrelevant... (in the case above, the interfaces)

however, is the interface being used in more than 1 place?

Rule of Three
Only abstract when there are at least 3 :-)

| | # 
# Monday, 01 June 2015
( SOLID )

 

  • A class should have only 1 reason to change  (do 1 thing and do it well)
  • Separation of concerns eg caching/logging
  • So a class should be 1 thing and do it well

How many reasons for change does the FileStore class have?

  • Logging
  • Caching
  • Storage (eg not filesystem use db)
  • Orchestration

image_thumb2

1. Logging - How to refactor – decompose each reason for change to other Classes

Move logging to another class – Serilog

public class StoreLogger { public void Saving(int id) { Log.Information("Saving message {id}.", id); } public void Saved(int id) { Log.Information("Saved message {id}.", id); }

and then:

public void Save(int id, string message) { this.log.Saving(id); //... this.log.Saved(id);

Test app working

http://xunit.github.io/docs/getting-started.html

xunit.net
xunit.runner.console

xUnit.net console test runner (64-bit .NET 4.0.30319.34209)
Copyright (C) 2015 Outercurve Foundation.

Discovering: SRPTests
Discovered:  SRPTests
Starting:    SRPTests
Finished:    SRPTests

=== TEST EXECUTION SUMMARY ===
   SRPTests  Total: 1, Errors: 0, Failed: 0, Skipped: 0, Time: 0.292s

packages\xunit.runner.console.2.0.0\tools\xunit.console SRPTests\bin\Debug\SRPTests.dll

xunit.runner.visualstudio

Serilog – having trouble getting it to compile from nuget

install-package serilog

gets 1.5.6

Got it working by starting a new project, then adding in logging first.  SerilogTest

using Serilog; namespace SerilogTest { public class FileStoreLogger { public void Save(string message) { var log = new LoggerConfiguration() .WriteTo.ColoredConsole() .WriteTo.RollingFile(@"C:\Temp\Log-{Date}.txt") .CreateLogger(); log.Information("Saving"); } } }

and

using Xunit; namespace SerilogTest { public class Tests { [Fact] public void Thing() { var fileStoreLogger = new FileStoreLogger(); fileStoreLogger.Save("test"); Assert.Equal(1, 1); } } }

which dumped a log file into c:\temp\

Xunit2 not picking up tests

Create project
compile
restart vs
install-package xunit
compile
restart vs
install-package xunit.runner.visualstudio
restart vs

install-package seriolog

install-package AutoFixture.XUnit2

| | # 
# Friday, 29 May 2015
( SOLID )

Supple/Pliable code – can change shape as we go along (as requirements always change)

  • Purpose of SOLID is to make you more productive
  • ..by making code more maintainable
  • ..through decomposition and decoupling

SOLID is a reaction to code smells

  • Rigidity – the design is difficult to change
  • Fragility – the design is easy to break
  • Immobility – the design is difficult to reuse
  • Viscosity – difficult to do the right thing
  • Overdesign – needless complexity

The 5 Principles (Uncle Bob first described)

  • Single Responsibility (SRP)
  • Open Closed (OCP)
  • Liskov Substitution (LSP)
  • Interface Segregation (ISP)
  • Dependency Inversion (DIP)
| | # 
# Thursday, 28 May 2015

https://github.com/djhmateer/githubscratch/tree/master/maybe

I like the concept behind Maybe<T>..  Option Type in functional programming. 

  • List/Collection of 0 or 1 elements
  • eg if a TextFileRead operation is legal it returns the contents of the file as 1 element
  • eg if a TextFileRead operation fails it returns 0 elements

[Theory, AutoData] //[Theory] //[InlineData("test message")] public void ReadReturnsMessage(string message) { var fileStore = new FileStore(Environment.CurrentDirectory); fileStore.Save(44, message); Maybe<string> actual = fileStore.Read(44); Assert.Equal(message, actual.Single()); }

To get these tests to run, I had to install: (commented out text above shows how to run it not using AutoFixture)

https://www.nuget.org/packages/xunit/1.9.2 – not version 2

https://www.nuget.org/packages/xunit.extensions/1.9.2 – not version 2

https://www.nuget.org/packages/AutoFixture/ – used latest

https://www.nuget.org/packages/AutoFixture.Xunit/ – used latest

AutoFixture puts in random data into the string message.

Also found I had to use R#9 to get xunit2 runner working (although using xunit1 now)

| | # 
# Wednesday, 13 May 2015

Methods that return something…(Queries)

public string GetFileName(int id) { // This can never be null as int is a value type, and workingDirectory is a pre condition return Path.Combine(this.WorkingDirectory, id + ".txt"); }

Null is never a valid return value (a good design decision)
// Could return a null/empty string if 1) no message 2) exception is thrown public string Read(int id) { var path = this.GetFileName(id); if (!File.Exists(path)) throw new ArgumentException("bad path", "read"); var message = File.ReadAllText(path); return message; }
3 ways to approach this problem of – “is it legal to invoke this operation?”

Tester/Doer

Always pairs.. the first is a ‘test’ to see if the operation is valid

public bool Exists(int id){ var path = GetFileName(id); return File.Exists(path); }

then

// client invokes string message = ""; if (fileStore.Exists(49)) message = fileStore.Read(49);

So, ok but not brilliant as need to know the idiom.  Also not thread safe

TryRead (or TryParse idiom)

// 2.TryRead (TryParse) public bool TryRead(int id, out string message){ message = null; var path = this.GetFileName(id); if (!File.Exists(path)) return false; message = File.ReadAllText(path); return true; }

Can be made threadsafe.  Not very OO – can’t have a fluent interface on top of this as TryRead returns a bool.

Maybe

Borrowed from functional (option type).. so it’s a collection with 0 or 1 elements

// Return value may be there, and may not be // and don't want to return null as it is tainted // want a collection of 0 or 1 strings // IEnumerable<string> is too wide as it could have 10 elements // Maybe<T> can return 0 of 1 <T> public Maybe<string> Read(int id) { var path = this.GetFileName(id); if (!File.Exists(path)) return new Maybe<string>(); var message = File.ReadAllText(path); return new Maybe<string>(message); }
public void Tester() { // this method may, or may not return a string Maybe<string> thing = Read(49); var message = thing.DefaultIfEmpty("").Single(); }

Synthesis/Summary

Making it easier for colleagues (and yourself in the future) to use your classes

  • Split methods into Commands (eg Save return void) and Queries eg GetFileName
  • Fail fast, and give good exception message
  • Never return null.. if need the concept of a value not being present then
    • Read returns a Maybe of string.. invalid states are impossible

 

Maintainability and Productivity improved

Decompose operations that return a value and one that has a side effect

| | # 

Robustness principle

  • Conservative in what you send (give good guarantees)
  • Liberal in what you accept
    • fail fast if can’t understand

Input

var fileStore = new FileStore();
fileStore.Save(42, “Hello world”); // Throws

As FilePath on the object is null.  So will fail/throw at runtime.

Could make an explicit constructor, so.

public FileStore(string workingDirectory) { // Guard clause as string is a ref type, so could be set to null outside if (workingDirectory == null) throw new ArgumentNullException("workingDirectory"); this.WorkingDirectory = workingDirectory; } // Private set public string WorkingDirectory { get; private set; }

Nullable References are Evil

Value types are primitive types like: ints, decimals, bools – non nullable by defaults

Ref types are Classes – nullable by default (non-nullable ref types not possible..language problem)

Fail Fast

// Exception messages are like documentation if (!Directory.Exists(workingDirectory)) throw new ArgumentException("You tried to supply a working directory string which doesn't exist." + " Please supply a valid path to an existing directory", "workingDirectory");

Be as tolerant as possible for inputs.

Be an explicit as possible about problems, and how to fix the problems.

| | # 
# Tuesday, 12 May 2015

http://www.pluralsight.com/courses/encapsulation-solid

Code that Sucks – many programmers in orgs feel their codebase does

Stand on the shoulders of giants (ie use ‘frameworks’ like ORMS etc..)

Make clearer code

public string Save(int id, string message) – what is the return string?? not obvious… need to read source

public void Read(int id).. why does this return void? need to read source

The Impact of Code that sucks

Long term productivity – a few weeks!!.. hard to write new features

Maintainability – if built up lots of technical debt

Encapsulation

  • Information hiding (Implementation hiding is a better name)
    • property / field.. eg password on a user class..maybe want to hide keeping an array of previous ones
  • protection of invariants
    • invalid states are difficult/impossible
    • assertions

Beyond OO

Command Query Separation (CQS) Principal

Bertand Meyer

CQRS – something different..architectural design pattern.. distributed architecture

Commands – have observable side effects eg send an email, write something to disk

Should do 1 or another

Query – returns data

Commands – returns void ie should do something

void Save(Order order); – what does it do? probably saves an order
void Send (T message) -
void Associate (IFoo foo, Bar bar);

All return void… so, it must have a side effect… so must be a command (otherwise what's the point)

Ok to invoke a queries eg

// Command
public void Save(int, id, string message)
{
  // GetFileName is a Query
  var path = this.GetFileName(id);
  File.WriteAllText(path, message);
}

Queries – return data (no side effects)

Do not mutate observable state

Order[] GetOrders(int userId); – probably gets orders associated with that userId
IFoo Map(Bar bar);
T Create(); – returns an instance of T

Idempotent – if invoke n times, it wont change the state of the system

If follow CQS can trust the codebase / easier to reason about the code without fully understanding the implementation details

http://blog.ploeh.dk/2014/08/11/cqs-versus-server-generated-ids/

| | # 
# Monday, 08 September 2014

Goal is to rewrite www.davesjokes.co.uk in a SOLID way:

Source is:  https://github.com/djhmateer/solidjokes

  • Single Responsibility
  • Open Closed Principle
  • Liskov substitution
  • Interface segregation
  • Dependency Inversion

Pure DI (Poor Mans), aim for open closed and SRP so testing is easier and  Decorator for logging

public class HomeController : Controller {
    private readonly ILogger logger;

    public HomeController() {
        logger = new Logger();
    }

    // So this is useful for testing now
    public HomeController(ILogger logger) {
        this.logger = logger;
    }

    public ActionResult Index() {
        logger.Log("In Index of Home Controller");
        return View();
    }

    public ActionResult About() {
        ViewBag.Message = "Your application description page.";

        return View();
    }

    public ActionResult Contact() {
        ViewBag.Message = "Your contact page.";

        return View();
    }
}

public interface ILogger { void Log(string text);}
public class Logger : ILogger {
    public void Log(string text) {
        Console.WriteLine(text);
    }
}

Simplest possible DI in MVC – in fact we’re only using DI when it’s called from a test method through the overloaded ctor.
public class HomeController : Controller {
    private readonly ILogger logger;

    public HomeController(ILogger logger) {
        this.logger = logger;
    }

    public ActionResult Index() {
        logger.Log("In Index of Home Controller");
        return View();
    }

    public ActionResult About() {
        ViewBag.Message = "Your application description page.";
        return View();
    }

    public ActionResult Contact() {
        ViewBag.Message = "Your contact page.";
        return View();
    }
}

public interface ILogger { void Log(string text);}
public class Logger : ILogger {
    public void Log(string text) {
        Console.WriteLine(text);
        Debug.WriteLine(text);
    }
}
public class MvcApplication : System.Web.HttpApplication {
    protected void Application_Start() {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);

        // Patch in our own Factory/Composition Root into MVC pipeline
        var controllerFactory = new SolidJokesControllerFactory();
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }
}

public class SolidJokesControllerFactory : DefaultControllerFactory {
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
        var logger = new Logger();
        if (controllerType == typeof(HomeController)) {
            return new HomeController(logger);
        }

        return base.GetControllerInstance(requestContext, controllerType);
    }
}

image
Debug.WriteLine logging, and our own Pure DI setup in the simplest way.

SRP – Decorating a Controller

HomeController has logging inside of it.  Lets decorate it, so making sure the HomeController does only 1 thing.

public class SolidJokesControllerFactory : DefaultControllerFactory {
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType) {
        if (controllerType == typeof(HomeController)) {
            // Decorating HomeController with HomeControllerLogger
            return new HomeControllerLogger(new HomeController());
        }
        // AccountController will still go the normal tightly coupled way
        return base.GetControllerInstance(requestContext, controllerType);
    }
}
public interface IHomeController
{
    ActionResult Index();
    ActionResult About();
    ActionResult Contact();
}
    public class HomeControllerLogger : Controller, IHomeController {
        private readonly IHomeController homeController;

        public HomeControllerLogger(IHomeController homeController) {
            this.homeController = homeController;
        }

        public ActionResult Index() {
            Debug.WriteLine("In Index of HomeControllerLogger");
            var result = homeController.Index();
            Debug.WriteLine("End Index of HomeControllerLogger");
            return result;
        }

        public ActionResult About() {
            Debug.WriteLine("In About of HomeControllerLogger");
            var result = homeController.About();
            Debug.WriteLine("End About of HomeControllerLogger");
            return result;
        }

        public ActionResult Contact() {
            return homeController.Contact();
        }
    }

image

Added in a test project to solution taking the boilerplate tests from VS2013.  Using xunit.  Updated references and went to MVC5.2.2 in both projects.

| | # 
# Thursday, 21 August 2014

Pluralsight course with Mark Seemann

  • Write better code
    • in teams
    • Maintainable
    • Readable

Encapsulation

Do you build applications on top of reusable components? eg ORM tools, caching, DI Frameworks.. we don’t dig into their internals normally…

that's basically what encapsulation is.

Most code sucks

normal in an organisation..

encapsulation is a technique for making code suck less.

image

difficult to understand how it works, unless you read the code.

Long term productivity if code deteriotates..

  • harder to maintain

Uses CQS.. examples look very good.

Summary of entire course

Encapsulation + SOLID = Maintainable Code

| | #