Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Friday, 11 September 2015

Below is code from https://github.com/djhmateer/Refactoring,
Based on http://mikehadlow.blogspot.co.uk/2015/08/c-program-entirely-with-static-methods.html  *

The objective of this talk is to refactor a simple Console Application which does an ETL towards code which is:

  • Easier to understand (less WTF’s per minute)
  • Easier to test
  • More pleasing

In general I firstly went in an OO style towards composition.  Then got rid of the ceremony of OO which I didn’t need, and used a simpler functional approach

  • Code looks ‘a little odd to the uninitiated’ *
  • Less lines code
  • Very easy to test
// Functional style of the QuoteImporter app, with logging using a decorator // Firstly decorate each separate function (1,2,3) with it's logger // Then compose together, decorating that top level function too private static void Main() { // 1. ReadFileListOfLines is a function with 0 Parameters, which returns a List of strings // passing it a lambda expression (anonymous function) // Log takes 1 parameter s // ReadFileListOfLines takes 0 parameters // returns a string Func<IEnumerable<string>> readFileListOfLines = () => ReadFileListOfLinesLogger(() => ReadFileListOfLines(), s => Log(s)); // 2. ParseLine takes 1 Parameter string s, which is wired up to lineToParse // using method group - don't need to specify s => Log(s) // returns a Quote Func<string, Quote> parseLine = lineToParse => ParseLineLogger(s => ParseLine(s), Log, lineToParse); // 3. InsertQuoteIntoDatabase takes 1 parameter Quote // returns nothing (therefore its an Action) // quote is wired up to q in the logger Action<Quote> insertQuoteIntoDatabase = quote => InsertQuoteIntoDatabaseLogger(q => InsertQuoteIntoDatabase(q), Log, quote); // Compose the Functions together (without running them) // Passing in a lambda expression (anonymous function) to Action run Action quoteImporter = () => QuoteImporter(readFileListOfLines, parseLine, insertQuoteIntoDatabase); // Decorating logging in the top level function (but no logging in this composition root function) Action run = () => QuoteImporterLogger(quoteImporter,Log); run(); } public static void QuoteImporterLogger(Action quoteImporter, Action<string> log) { log("Start QuoteImporter"); quoteImporter(); log("End QuoteImporter"); } // Top level function, which depends upon 3 other functions (passed in as parameters) public static void QuoteImporter( Func<IEnumerable<string>> readFileListOfLines, Func<string, Quote> parseLine, Action<Quote> insertQuoteIntoDatabase) { IEnumerable<string> lines = readFileListOfLines(); foreach (var line in lines) { var quote = parseLine(line); insertQuoteIntoDatabase(quote); } } // 1 ReadFile List public static IEnumerable<string> ReadFileListOfLinesLogger( Func<IEnumerable<string>> readFileListOfLines, Action<string> log) { log("Start ReadFileListOfLines"); var result = readFileListOfLines(); // Easy way to view contents of IEnumerable to log log($"result of ReadFileListOfLines: {string.Join(Environment.NewLine,result.Select(s => s))}"); log("End ReadFileListOfLines"); return result; } public static IEnumerable<string> ReadFileListOfLines() { string[] fileTextLines = File.ReadAllLines(@"..\..\quotesWithTitles.csv"); return fileTextLines.ToList(); } // 2 ParseLine public static Quote ParseLineLogger( Func<string, Quote> parseLine, Action<string> log, string lineToParse) { log($"Start ParseLine with input {lineToParse}"); Quote result = parseLine(lineToParse); log($"End ParseLine with ouput {result.Title}, {result.Body}"); return result; } public static Quote ParseLine(string line) { string[] values = line.Split(','); if (values.Length < 2) throw new ApplicationException("Unknown state - too few commas"); if (values.Length > 2) throw new ApplicationException("Unknown state - too many commas"); string title = values[0]; string body = values[1]; return new Quote{Title = title,Body = body}; } // 3 InsertQuote public static void InsertQuoteIntoDatabaseLogger( Action<Quote> insertQuoteIntoDatabase,Action<string> log, Quote quote) { log($"Start InsertQuoteIntoDatabase with input {quote.Title} {quote.Body}"); insertQuoteIntoDatabase(quote); log($"End InsertQuoteIntoDatabase"); } private static void InsertQuoteIntoDatabase(Quote quote) { string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Dev\Refactoring\Refactoring\Database1.mdf;Integrated Security=True"; using (var connection = new SqlConnection(connectionString)) { var cmd = new SqlCommand("INSERT INTO Quotes (Title, Text) VALUES (@Title, @Quote)", connection); cmd.Parameters.AddWithValue("@Title", quote.Title); cmd.Parameters.AddWithValue("@Quote", quote.Body); connection.Open(); cmd.ExecuteNonQuery(); } } public static void Log(string message) { Console.WriteLine("log: {0}", message); }

The tests:

[Fact] public void ReadFileList_ShouldReturn3Lines() { IEnumerable<string> result = ImporterFunctional.ReadFileListOfLines(); Assert.Equal(3, result.Count()); } [Fact] public void ParseLine_AValidLine_ShouldReturnAQuote() { string line = "Basic,Programming in Basic causes brain damage - Edsger Wybe Dijkstra"; Quote result = ImporterFunctional.ParseLine(line); Assert.Equal("Basic", result.Title); Assert.Equal("Programming in Basic causes brain damage - Edsger Wybe Dijkstra", result.Body); } [Fact] public void ParseLine_AnEmptyLine_ShouldThrow() { string line = ""; Assert.Throws<ApplicationException>(() => ImporterFunctional.ParseLine(line)); } [Fact] public void ParseLine_TooManyCommas_ShouldThrow() { string line = "asdf,asdf,asdf"; Assert.Throws<ApplicationException>(() => ImporterFunctional.ParseLine(line)); } // 2. Testing the top level Orchestration function [Fact] public void QuoteImporter_GivenMockFile_ShouldInsertIntoMockDatabase() { // 1. ReadFileListOfLines mock string actualLineFromFile = ""; Func<IEnumerable<string>> readFileListOfLines = () => { var listOfLines = new[] {"title, quote here"}; actualLineFromFile = listOfLines[0]; return listOfLines; }; // 2. ParseLine mock string actualLineSentToParseLine = ""; Func<string, Quote> parseLine = s => { actualLineSentToParseLine = s; var quote = new Quote {Title = "title2", Body = "quote here2"}; return quote; }; // 3. InsertQuoteIntoDatabase mock // using a closure IList<Quote> actualQuotes = new List<Quote>(); Action<Quote> insertQuoteIntoDatabase = quote => { actualQuotes.Add(quote); }; // compose. Action is a delegate - doesn't return anything Action run = () => ImporterFunctional.QuoteImporter( readFileListOfLines, parseLine, insertQuoteIntoDatabase); run(); // 1. Testing the ReadFileListOfLines mock was called Assert.Equal("title, quote here", actualLineFromFile); // 2. Testing the mock parser received the data from the ReadFileListOfLines mock Assert.Equal("title, quote here", actualLineSentToParseLine); // 3. Testing the mock database received the data from the ParseLine mock Assert.Equal("title2", actualQuotes[0].Title); Assert.Equal("quote here2", actualQuotes[0].Body); }
| | # 
# Thursday, 10 September 2015

Passing 0 Parameters to a function and logging

// Logging using a decorator - passing 0 parameters to // Action is like a function which can take parameters but doesn't return anything. // Passing in 2 method group QuoteImporter, Log // Passing in 2 lambda expression (anonymous function) () => QuoteImporter, s => Log(s) // Passing in 2 anonymous methods delegate() { QuoteImporter(); }, delegate(string s) {Log(s);}; Action run = () => QuoteImporterLogger(QuoteImporter, Log); run(); } public static void QuoteImporterLogger(Action quoteImporter, Action<string> log) { log("Start QuoteImporter"); quoteImporter(); log("End QuoteImporter"); } // Don't want logging code cluttering up public static void QuoteImporter() { Console.WriteLine("In QuoteImporter"); } public static void Log(string message) { Console.WriteLine($"log: {message}"); }

Passing 1 Parameter to a function and logging

// Logging using a decorator - passing in 1 parameter private static void Main() { // Function - given a string, return a string. // s and t represent the inbound parameters into ParseLine and Log (not needed) // line is inbound parameter into ParseLineLogger Func<string, string> run = line => ParseLineLogger(s => ParseLine(s), t => Log(t), line); string result = run("blah"); } public static string ParseLineLogger(Func<string, string> parseLine, Action<string> log, string line) { Console.WriteLine($"Start ParseLine with line: {line}"); string result = parseLine(line); Console.WriteLine($"Result: {result}"); Console.WriteLine("End ParseLine"); return result; } public static string ParseLine(string line) { return line + " ok"; } public static void Log(string message) { Console.WriteLine($"log: {message}"); }
| | # 
# Monday, 07 September 2015
( Action | Func | Functional )

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

The program does a:

  • Extract from a csv file of quotes
  • Transform using a ParseLine to split each line into a title and a quote
  • Load to insert into a database

Its a Console application designed to be run every night.  So just simple enough to really be able to explore techniques.  Based off http://mikehadlow.blogspot.co.uk/2015/08/c-program-entirely-with-static-methods.html

First Iteration which is using the blog post above’s architecture

// Functional style of the QuoteImporter app private static void Main() { // Compose the Functions together (without running them) Action run = () => QuoteImporter(ReadFileListOfLines, ParseLine, InsertQuoteIntoDatabase); run(); } // 1. Takes a Function with no input, which returns a list of strings // 2. Takes a Function with a string input, which returns a Quote // 3. Takes an Action with a Quote input public static void QuoteImporter( Func<IEnumerable<string>> readFileListOfLines, Func<string, Quote> parseLine, Action<Quote> insertQuoteIntoDatabase) { IEnumerable<string> lines = readFileListOfLines(); foreach (var line in lines) { var quote = parseLine(line); insertQuoteIntoDatabase(quote); } } // If there is a return type, then must be a Func<input, input..., output> public static IEnumerable<string> ReadFileListOfLines() { return File.ReadAllLines(@"..\..\quotesWithTitles.csv"); } public static Quote ParseLine(string line) { string[] values = line.Split(','); if (values.Length < 2) throw new ApplicationException("Unknown state - too few commas"); if (values.Length > 2) throw new ApplicationException("Unknown state - too many commas"); string title = values[0]; string body = values[1]; return new Quote { Title = title, Body = body }; } private static void InsertQuoteIntoDatabase(Quote quote) { string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=C:\Dev\Refactoring\Refactoring\Database1.mdf;Integrated Security=True"; using (var connection = new SqlConnection(connectionString)) { var cmd = new SqlCommand("INSERT INTO Quotes (Title, Text) VALUES (@Title, @Quote)"); cmd.Connection = connection; cmd.Parameters.AddWithValue("@Title", quote.Title); cmd.Parameters.AddWithValue("@Quote", quote.Body); connection.Open(); cmd.ExecuteNonQuery(); } }
| | # 
# Sunday, 16 August 2015
( C#6 | Functional )

http://mikehadlow.blogspot.co.uk/2015/08/c-program-entirely-with-static-methods.html

and my fork: https://github.com/djhmateer/FunctionalDemo

"More concise and easier to test"

"Gone are interfaces and instance classes to be replaced by static methods, higher-order functions and closures"

Procedural –> Object-Oriented –> Functional

OO code .. "is typical of much well-constructed C# code that you will find in the wild"

OO Example

Why is composition root a static class?
Put properties below the ctor?
Why class properties and not a class field?
Why Console.Out.Writeline and not Console.WriteLine.. no real difference
RunCustomerReportBatch – interesting how to test this method, when it returns void, so have to test it’s dependencies’ results (the mocks)

public Report CreateCustomerReport(Customer customer) { // C#6 string interpolation var body = $"This is the report for {customer.Email}!"; return new Report(customer.Email, body); }

So this is exciting – new C#6 features.  Stable release of C#6 was on 20th July 2015 as part of .NET4.6. 

image
However I’m targeting 4.5.2, and not 4.6 (which is installed).  In fact it works targeting 4.5

C#6 requires the new Roslyn compiler http://stackoverflow.com/a/28921749/26086  but the compiler can target older versions of the framework for some features eg string interpolation as it results in a call to String.Format.

image

Functional Example

private static void Main() { // Action is a delegate. Doesn't return a value Action runProcessing = () => RunProcessing(Log); runProcessing(); } public static void RunProcessing(Action<string> log) { log("test"); } public static void Log(string message) { Console.WriteLine("log: {0}", message); }

Composing, then running a method which has a dependency.

 

Notes:

http://www.programgood.net/2014/10/24/70483FunQuestions.aspx going through Action and Func

http://www.pluralsight.com/courses/csharp-fundamentals-2
Functional bit

| | # 
# Tuesday, 21 October 2014
( c# | Functional )

Building abstractions using functions

Build own primitives.. classes last module… methods/functions this module

Higher order functions

Take 1 or more fns as an input, or return fns

internal static class Program2 { private static void Main(string[] args) { var numbers = new[] { 3, 5, 7, 9, 11, 13, 15 }; foreach (var prime in numbers.FindPrimes()) { Console.WriteLine(prime); } } private static IEnumerable<int> FindPrimes(this IEnumerable<int> values) { //iterate //test if prime //return a difference sequence of ints var result = new List<int>(); foreach (var number in values) { if (IsPrime(number)) { result.Add(number); } } return result; } private static bool IsPrime(int number) { bool isPrime = true; for (long i = 2; i < number - 1; i++) { if (number % i == 0) isPrime = false; } return isPrime; } }

Extension method on IEnumerable<int>

internal static class Program2 { private static void Main(string[] args) { var numbers = new[] { 3, 5, 7, 9, 11, 13, 15 }; // Passing in the IsPrime function into Find foreach (var prime in numbers.Find(IsPrime)) { Console.WriteLine(prime); } } // Find is a higher order function, as it takes another function as a parameter // composable with other functions private static IEnumerable<int> Find(this IEnumerable<int> values, Func<int, bool> test) { //iterate //test if prime //return a difference sequence of ints var result = new List<int>(); foreach (var number in values) { //if (IsPrime(number)) { if (test(number)) { result.Add(number); } } return result; } private static bool IsPrime(int number) { bool isPrime = true; for (long i = 2; i < number - 1; i++) { if (number % i == 0) isPrime = false; } return isPrime; } }

Find is a Higher Order Function.

Lazyness

Lazy evaluation – allows you to write an expression that’s not executed until the last possible moment.  And only if we need the result (program forces us to execute).

  • Avoid expensive calculations that we don’t need
  • Data structures of an infinite size
private static void Main(string[] args) { var numbers = new[] { 3, 5, 7, 9, 11, 13, 15 }; // Passing in the IsPrime function into Find foreach (var prime in numbers.Find(IsPrime).Take(2)) { Console.WriteLine(prime); } } // Find is a higher order function, as it takes another function as a parameter // composable with other functions private static IEnumerable<int> Find(this IEnumerable<int> values, Func<int, bool> test) { //iterate //test if prime //return a difference sequence of ints var result = new List<int>(); foreach (var number in values) { Console.WriteLine("Testing {0}", number); if (test(number)) { result.Add(number); } } return result; }

image
Didn’t expect this. 

image
Swap out the internal list for yield return.

Generates code for IEnumerable under the hood.

Essentially pauses the execution of the method for the caller to process the current result.  When the caller needs the next result, execution will resume where it last left off.

private static void Main(string[] args) { var numbers = new[] { 3, 5, 7, 9, 11, 13, 15 }; // Passing in the IsPrime function into Find //foreach (var prime in numbers.Find(IsPrime).Take(2)) { foreach (var prime in GetRandomNumbers().Find(IsPrime).Take(2)) { Console.WriteLine(prime); } } // Interesting this function stops when 2 primes are found (as Take(2) above) static IEnumerable<int> GetRandomNumbers(){ yield return 3; yield return 6; yield return 8; yield return 9; yield return 11; yield return 13; }

asdf

private static void Main(string[] args) { var numbers = new[] { 3, 5, 7, 9, 11, 13, 15 }; // Passing in the IsPrime function into Find //foreach (var prime in numbers.Find(IsPrime).Take(2)) { foreach (var prime in GetRandomNumbers().Find(IsPrime).Take(2)) { Console.WriteLine(prime); } } static IEnumerable<int> GetRandomNumbers(){ Random rand= new Random(); // Infinite loop while (true){ yield return rand.Next(1000); } }

Nice – tries random numbers until it gets 2 primes.

An infinite sequence of integers

Timing and Retries

Higher order functions not related to querying.

public class Timekeeper { public TimeSpan Measure(Action action) { var watch = new Stopwatch(); watch.Start(); action(); return watch.Elapsed; } } internal static class Program2 { private static void Main(string[] args) { var timekeeper = new Timekeeper(); // Passing in a function to Measure var elapsed = timekeeper.Measure(() => { foreach (var prime in GetRandomNumbers().Find(IsPrime).Take(2)) { Console.WriteLine(prime); } }); Console.WriteLine(elapsed); }


Interesting! 1:48 of 3:37 in Timing and Retries

public static T WithRetry<T>(this Func<T> action) { var result = default(T); int retryCount = 0; bool succesful = false; do { try { result = action(); succesful = true; } catch (WebException ex) { retryCount++; } } while (retryCount < 3 && !succesful); return result; } private static void Main(string[] args) { var client = new WebClient(); Func<string> download = () => client.DownloadString("http://microsoft.com"); // This is a Higher Order Function, even though it doesn't look like it var data = download.WithRetry();

Interesting!

Partial Application and Currying

Partical application is adapting a function into a function which doesn’t need a paramter

public static Func<TResult> Partial<TParam1, TResult>( this Func<TParam1, TResult> func, TParam1 parameter) { return () => func(parameter); }

Currying .. (Haskall Curry).

public static Func<TParam1, Func<TResult>> Curry<TParam1, TResult> (this Func<TParam1, TResult> func) { return parameter => () => func(parameter); }

Async and Parallel

a benefit of functional..parallelism

AsParallel in TPL.

static void Main(string[] args) { var timekeeper = new Timekeeper(); var elapsed = timekeeper.Measure(() => FindLargePrimes(1, 200000)); Console.WriteLine(elapsed); } private static IList<int> FindLargePrimes(int start, int end) { var primes = Enumerable.Range(start, end - start).ToList(); return primes.Where(IsPrime).ToList(); }

and now in parallel

static void Main(string[] args) { var timekeeper = new Timekeeper(); var elapsed = timekeeper.Measure(() => FindLargePrimes(1, 200000)); Console.WriteLine(elapsed); } private static IList<int> FindLargePrimes(int start, int end) { var primes = Enumerable.Range(start, end - start).ToList(); return primes.Where(IsPrime).ToList(); } private static IList<int> FindLargePrimesInParallel(int start, int end) { var primes = Enumerable.Range(start, end - start).ToList(); return primes.AsParallel().Where(IsPrime).ToList(); }

For more control over the execution

// Expecting a Task which returns an IEnumerable<int> var task = new Task<IEnumerable<int>>( () => FindLargePrimes(3, 100) ); task.Start(); Console.WriteLine("Doing other work"); // Wait until unblocked task.Wait(); foreach (var number in task.Result) { Console.WriteLine(number); }

and more..

// Expecting a Task which returns an IEnumerable<int> var task = new Task<IEnumerable<int>>( () => FindLargePrimes(3, 100) ); // Chaining var task2 = task.ContinueWith((antecedent) => { foreach (var number in antecedent.Result) { Console.WriteLine(number); } }); task.Start(); Console.WriteLine("Doing other work"); // Wait until unblocked task2.Wait();
| | #