Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Thursday, 04 June 2015

Strengthen the guarantees of the methods with DirectoryInfo and FileInfo instead of strings

DirectoryInfo

public FileStore(DirectoryInfo workingDirectory)

Instead of accepting String, be more explicit.
public FileInfo GetFileInfo(int id)

Handy as can do
var file = this.GetFileInfo(id); if (!file.Exists)

FileInfo

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

Again more prescriptive of the return type of the method.. so can use
FileInfo fileInfo = fileStore.GetFileInfo(id); string fileName = fileInfo.FullName;


Caching and Logging
public void Save(int id, string message){ Log.Information("Saving message {id}", id); var file = this.GetFileInfo(id); File.WriteAllText(file.FullName, message); this.cache.AddOrUpdate(id, MessageTemplate (i,s) => message); }

public Maybe<string> Read(int id){ var file = this.GetFileInfo(id); if (!file.Exists) return new Maybe<string>(); var message = this.cache.GetOrAdd(id, _ => File.ReadAllText(file.FullName)); //var message = File.ReadAllText(file.FullName); // Never want message to be Null - that is what the previous step is for return new Maybe<string>(message); }

Caching and Logging behaviour – common additions to code.

Where to Start – Logging

| | # 
# 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/

| | # 
# 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

| | #