Functional Programming in C# NCrafts 21-22 May, Paris 2015 @tjaskula
What is functional programming ? • Functions as building blocks • Function returns values only based on the passed input • Recursion • HOF (Higher Order Functions) • Creation of anonymous functions, in-line, lambda expressions • Closures • Immutability
What REALY is FP ? “Natural way of telling the computer what it should do, by describing properties of a given problem in a concise language”
Programmers responsibility in FP ? Specify functions to describe a given set of problems
Object Oriented Programming • Encapsulation • Combining data and behavior into classes and objects • Modeling Real-World
Relationship FP to OOP • No silver bullet • Programmer needs to understand different techniques
Why to talk about ? • Concurrency programming models • Writing software it’s a complex process • Managing side effects
Part 1 – Make it simple Composing dependencies
The OOP way IoC container granted from the start. Developers argue about which framework to chose and not the problem to solve.
public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } catch (Exception e) { // log } }
New requirements Log, Security, Audit, Cache…Cross Cutting Concerns
public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; private readonly UnitOfWork _unitOfWork; private readonly EnrollementNotificationService _notificationService; private readonly ILogger _logger; private readonly AuthorizationService _authorizationService; private readonly CalendarService _calendarService; private readonly ServiceFoo _serviceFoo; private readonly ServiceBlah _serviceBlah; private readonly FactoryFoo _facoFactoryFoo; private readonly FactoryBlah _factoryBlah; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository, UnitOfWork unitOfWork, EnrollementNotificationService notificationService, ILogger logger, AuthorizationService authorizationService, CalendarService calendarService, ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah ) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; _unitOfWork = unitOfWork; _notificationService = notificationService; _logger = logger; _authorizationService = authorizationService; _calendarService = calendarService; _serviceFoo = serviceFoo; _serviceBlah = serviceBlah; _facoFactoryFoo = facoFactoryFoo; _factoryBlah = factoryBlah; } } public void Handles(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { _unitOfWork.BeginTransaction(); student.TryEnrollIn(@class); @class.TryEnroll(student);
…or better… AOP to the rescue
[Logable] [Authorizable] [Cachable] [ExceptionPolicy] [Blablable] public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Handles(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } catch (Exception e) { // log } }
Yes, but container can do more !
AOP with interception var calculator = new Calculator(); var calculatorProxy = Intercept.ThroughProxy<ICalculator>(calculator, new InterfaceInterceptor(), new[] { new LogBehavior() });
but one must : • know Dynamic Proxy pattern • know the difference of Instance and Type Interceptors • know Interception behaviors • not forget VIRTUAL keyword on methods • wire up IoC container correctly
Really ?!!! Is this… SIMPLE ?
DI flavors IoC with conventions... Scan(x => { x.TheCallingAssembly(); x.ExcludeNamespaceContainingType<IEvent>(); x.ExcludeNamespaceContainingType<SearchModel>(); x.ExcludeNamespaceContainingType<AuthenticationService>() x.ExcludeNamespaceContainingType<DovetailController>(); x.AddAllTypesOf<IDomainMap>(); x.WithDefaultConventions();
DI flavors IoC with conventions... Scan(x => { x.TheCallingAssembly(); x.ExcludeNamespaceContainingType<IEvent>(); x.ExcludeNamespaceContainingType<SearchModel>(); x.ExcludeNamespaceContainingType<AuthenticationService>() x.ExcludeNamespaceContainingType<DovetailController>(); x.AddAllTypesOf<IDomainMap>(); x.WithDefaultConventions();
DI flavors IoC with manual configuration... var container = new UnityContainer(); container.RegisterType<IService, Service>(“Service”); container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IS Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(ne c.Resolve<ISubServiceProvider(); )); container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>();
DI flavors IoC with manual configuration... var container = new UnityContainer(); container.RegisterType<IService, Service>(“Service”); container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IS Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(ne c.Resolve<ISubServiceProvider(); )); container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>();
DI flavors IoC with XML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
DI flavors IoC with XML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
DI flavors IoC with XML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
What problem do we try to solve ? • Decoupling ? • Testing ? • Modular Design ? • Dependencies management ?
Dependencies are bad.... public class EnrollmentCommandHandler { public EnrollmentCommandHandler(StudentRepository studentReposit ClassRepository classReposit StudentArchiveRepository stu UnitOfWork unitOfWork, EnrollementNotificationServi ILogger logger, AuthorizationService authori CalendarService calendarServ ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah
Cyclic dependencies are evil.... public class EnrollmentCommandHandler { public EnrollmentCommandHandler(StudentRepository studentReposit ClassRepository classReposit StudentArchiveRepository stu UnitOfWork unitOfWork, EnrollementNotificationServi ILogger logger, AuthorizationService authori CalendarService calendarServ ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah
public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Code we have....
public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Code that matters…
The rest is Plumbing code
Functional way int Multiply(int a, int b) { return a * b; } Partial application Func<int, int> multiplyBy10 = b => Multiply(10, b);
Functional way int a = 3; int b = a + 7; int c = b * 10; Composition Func<int, int> calcCFromA = a => CalcC(CalcB(a)); int CalcCFromA(int a) { return (a + 7) * 10; } int CalcCFromA(int a) { return CalcC(CalcB(a)); } let calcCFromA = calcB >> calcC
public class EnrollmentCommandHandler { private readonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Refactor this…
public void Enroll(StudentRepository studentRepository, ClassRepository classRepository, StudentEnrollCommand command) { var student = studentRepository.GetById(command.StudentId); var @class = classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } to this…
var studentRepository = new StudentRepository(); var classRepository = new ClassRepository(); var pipeline = c => handlers.Enroll(studentRepository, classRepository, c); Bootstrap in one place…
_handlers.Dispatch(new StudentEnrollCommand(1)); = pipeline(new StudentEnrollCommand(1)); Handle in another…
var studentRepository = new StudentRepository(); var classRepository = new ClassRepository(); var pipeline = c => handlers.Log(c, c1 => handlers.Enroll(studentRepository, classRepository, c1)); Want to log ?
var studentRepository = new StudentRepository(); var classRepository = new ClassRepository(); var studentEnrollPipeline = c => handlers.Audit(c, c1 => handlers.Log(c1, c2 => handlers.Enroll(studentRepository,classRepository, c2)); Audit ?
var lifeTime = new LifeTime(); var studentRepositoryFactory = () => new StudentRepository(); var classRepositoryFactory = () => new ClassRepository(); var studentEnrollPipeline = c => handlers.Audit(c, c1 => handlers.Log(c1, c2 => handlers.Enroll(lifeTime.PerThread(studentRepositoryFactory), lifeTime.PerThread(classRepositoryFactory), c2)); Lifetime management ?
Why to do it ? • 99% of time you don’t have a problem for IoC container • IoC makes easier things you shouldn’t be doing anyway • Feel the pain and think
To many dependencies ? • You have another serious problem
Is this… SIMPLE ? Is is just pure C# code
Part 2 – Control complexity Composition strikes again…but in different shape
Writing a program using functions How to order sequence of functions ? ParseCopyright(string text) { return text + “©” } ParseAppendix(string text) { return text.Remove(“APPENDIX”); }
Solution By composing them ParseCopyright(ParseAppendix(text));
But this can fail ParseAppendix function may throw an exception
Solution Return two kind of things from ParseAppendix function string string Instead of Let’s allow string string Error or
But function can return one thing And only one thing
Solution Put in in the box string ParseResult
What happens to this now ? ParseCopyright(ParseAppendix(text)); string ParseResultParseAppendix ParseCopyright
is success Solution Let’s have a special “link”/”connect”/”compose” function string ParseResultParseAppendix ParseCopyrightstring Error Connect
What we have seen is a… M***D
Demo
Composition Composition is the key to controlling complexity in software. “In our study of program design, we have seen that expert programmers control the complexity of their designs with the same general techniques used by designers of all complex systems. They combine primitive elements to form compound objects, they abstract compound objects to form higher-level building blocks, and they preserve modularity by adopting appropriate large-scale views of system structure.”
Should I do functional programming in C# ?
To take away • Be stupid! Don’t waste your brain on complicated code • Don’t waste your time to understand Rube Goldberg machines • Simplicity. Write only the code that matters. • Readability • Less bugs
Questions ?
Thanks

Functional programming in C#

  • 1.
    Functional Programming inC# NCrafts 21-22 May, Paris 2015 @tjaskula
  • 2.
    What is functionalprogramming ? • Functions as building blocks • Function returns values only based on the passed input • Recursion • HOF (Higher Order Functions) • Creation of anonymous functions, in-line, lambda expressions • Closures • Immutability
  • 3.
    What REALY isFP ? “Natural way of telling the computer what it should do, by describing properties of a given problem in a concise language”
  • 4.
    Programmers responsibility inFP ? Specify functions to describe a given set of problems
  • 5.
    Object Oriented Programming •Encapsulation • Combining data and behavior into classes and objects • Modeling Real-World
  • 6.
    Relationship FP toOOP • No silver bullet • Programmer needs to understand different techniques
  • 7.
    Why to talkabout ? • Concurrency programming models • Writing software it’s a complex process • Managing side effects
  • 8.
    Part 1 –Make it simple Composing dependencies
  • 9.
    The OOP way IoCcontainer granted from the start. Developers argue about which framework to chose and not the problem to solve.
  • 10.
    public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } catch (Exception e) { // log } }
  • 11.
    New requirements Log, Security,Audit, Cache…Cross Cutting Concerns
  • 12.
    public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; private readonly UnitOfWork _unitOfWork; private readonly EnrollementNotificationService _notificationService; private readonly ILogger _logger; private readonly AuthorizationService _authorizationService; private readonly CalendarService _calendarService; private readonly ServiceFoo _serviceFoo; private readonly ServiceBlah _serviceBlah; private readonly FactoryFoo _facoFactoryFoo; private readonly FactoryBlah _factoryBlah; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository, UnitOfWork unitOfWork, EnrollementNotificationService notificationService, ILogger logger, AuthorizationService authorizationService, CalendarService calendarService, ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah ) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; _unitOfWork = unitOfWork; _notificationService = notificationService; _logger = logger; _authorizationService = authorizationService; _calendarService = calendarService; _serviceFoo = serviceFoo; _serviceBlah = serviceBlah; _facoFactoryFoo = facoFactoryFoo; _factoryBlah = factoryBlah; } } public void Handles(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { _unitOfWork.BeginTransaction(); student.TryEnrollIn(@class); @class.TryEnroll(student);
  • 13.
    …or better… AOPto the rescue
  • 14.
    [Logable] [Authorizable] [Cachable] [ExceptionPolicy] [Blablable] public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Handles(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); try { student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } catch (Exception e) { // log } }
  • 15.
    Yes, but containercan do more !
  • 16.
    AOP with interception varcalculator = new Calculator(); var calculatorProxy = Intercept.ThroughProxy<ICalculator>(calculator, new InterfaceInterceptor(), new[] { new LogBehavior() });
  • 17.
    but one must: • know Dynamic Proxy pattern • know the difference of Instance and Type Interceptors • know Interception behaviors • not forget VIRTUAL keyword on methods • wire up IoC container correctly
  • 18.
    Really ?!!! Isthis… SIMPLE ?
  • 20.
    DI flavors IoC withconventions... Scan(x => { x.TheCallingAssembly(); x.ExcludeNamespaceContainingType<IEvent>(); x.ExcludeNamespaceContainingType<SearchModel>(); x.ExcludeNamespaceContainingType<AuthenticationService>() x.ExcludeNamespaceContainingType<DovetailController>(); x.AddAllTypesOf<IDomainMap>(); x.WithDefaultConventions();
  • 21.
    DI flavors IoC withconventions... Scan(x => { x.TheCallingAssembly(); x.ExcludeNamespaceContainingType<IEvent>(); x.ExcludeNamespaceContainingType<SearchModel>(); x.ExcludeNamespaceContainingType<AuthenticationService>() x.ExcludeNamespaceContainingType<DovetailController>(); x.AddAllTypesOf<IDomainMap>(); x.WithDefaultConventions();
  • 22.
    DI flavors IoC withmanual configuration... var container = new UnityContainer(); container.RegisterType<IService, Service>(“Service”); container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IS Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(ne c.Resolve<ISubServiceProvider(); )); container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>();
  • 23.
    DI flavors IoC withmanual configuration... var container = new UnityContainer(); container.RegisterType<IService, Service>(“Service”); container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IS Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(ne c.Resolve<ISubServiceProvider(); )); container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>();
  • 24.
    DI flavors IoC withXML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
  • 25.
    DI flavors IoC withXML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
  • 26.
    DI flavors IoC withXML configuration... <unity> <typeAliases> <typeAlias alias="string" type="System.String, mscorlib" /> <typeAlias alias="ILogger" type="UnitySamples.ILogger, UnitySamples" /> <typeAlias alias="ConsoleLogger" type="UnitySamples.ConsoleLogger, UnitySamples" /> <typeAlias alias="DebugLogger" type="UnitySamples.DebugLogger, UnitySamples" /> <typeAlias alias="IContext" type="UnitySamples.IContext, UnitySamples" /> <typeAlias alias="UnityContext" type="UnitySamples.UnityContext, UnitySamples" /> <typeAlias alias="CustomerTasks" type="UnitySamples.CustomerTasks, UnitySamples" /> </typeAliases> <containers> <container> <types> <type type="ILogger" mapTo="ConsoleLogger" name="defaultLogger"/> <type type="ILogger" mapTo="DebugLogger" name="debugLogger"/> <type type="IContext" mapTo="UnityContext"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practi <constructor> <param name="logger" parameterType="ILogger">
  • 27.
    What problem dowe try to solve ? • Decoupling ? • Testing ? • Modular Design ? • Dependencies management ?
  • 28.
    Dependencies are bad.... publicclass EnrollmentCommandHandler { public EnrollmentCommandHandler(StudentRepository studentReposit ClassRepository classReposit StudentArchiveRepository stu UnitOfWork unitOfWork, EnrollementNotificationServi ILogger logger, AuthorizationService authori CalendarService calendarServ ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah
  • 29.
    Cyclic dependencies areevil.... public class EnrollmentCommandHandler { public EnrollmentCommandHandler(StudentRepository studentReposit ClassRepository classReposit StudentArchiveRepository stu UnitOfWork unitOfWork, EnrollementNotificationServi ILogger logger, AuthorizationService authori CalendarService calendarServ ServiceFoo serviceFoo, ServiceBlah serviceBlah, FactoryFoo facoFactoryFoo, FactoryBlah factoryBlah
  • 30.
    public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Code we have....
  • 31.
    public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Code that matters…
  • 32.
    The rest isPlumbing code
  • 33.
    Functional way int Multiply(inta, int b) { return a * b; } Partial application Func<int, int> multiplyBy10 = b => Multiply(10, b);
  • 34.
    Functional way inta = 3; int b = a + 7; int c = b * 10; Composition Func<int, int> calcCFromA = a => CalcC(CalcB(a)); int CalcCFromA(int a) { return (a + 7) * 10; } int CalcCFromA(int a) { return CalcC(CalcB(a)); } let calcCFromA = calcB >> calcC
  • 35.
    public class EnrollmentCommandHandler { privatereadonly StudentRepository _studentRepository; private readonly ClassRepository _classRepository; private readonly StudentArchiveRepository _studentArchiveRepository; public EnrollmentCommandHandler(StudentRepository studentRepository, ClassRepository classRepository, StudentArchiveRepository studentArchiveRepository) { _studentRepository = studentRepository; _classRepository = classRepository; _studentArchiveRepository = studentArchiveRepository; } public void Enroll(StudentEnrollCommand command) { var student = _studentRepository.GetById(command.StudentId); var @class = _classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } } Refactor this…
  • 36.
    public void Enroll(StudentRepositorystudentRepository, ClassRepository classRepository, StudentEnrollCommand command) { var student = studentRepository.GetById(command.StudentId); var @class = classRepository.GetById(command.ClassId); student.TryEnrollIn(@class); @class.TryEnroll(student); student.Enroll(@class); @class.Enroll(student); } to this…
  • 37.
    var studentRepository =new StudentRepository(); var classRepository = new ClassRepository(); var pipeline = c => handlers.Enroll(studentRepository, classRepository, c); Bootstrap in one place…
  • 38.
  • 39.
    var studentRepository =new StudentRepository(); var classRepository = new ClassRepository(); var pipeline = c => handlers.Log(c, c1 => handlers.Enroll(studentRepository, classRepository, c1)); Want to log ?
  • 40.
    var studentRepository =new StudentRepository(); var classRepository = new ClassRepository(); var studentEnrollPipeline = c => handlers.Audit(c, c1 => handlers.Log(c1, c2 => handlers.Enroll(studentRepository,classRepository, c2)); Audit ?
  • 41.
    var lifeTime =new LifeTime(); var studentRepositoryFactory = () => new StudentRepository(); var classRepositoryFactory = () => new ClassRepository(); var studentEnrollPipeline = c => handlers.Audit(c, c1 => handlers.Log(c1, c2 => handlers.Enroll(lifeTime.PerThread(studentRepositoryFactory), lifeTime.PerThread(classRepositoryFactory), c2)); Lifetime management ?
  • 42.
    Why to doit ? • 99% of time you don’t have a problem for IoC container • IoC makes easier things you shouldn’t be doing anyway • Feel the pain and think
  • 43.
    To many dependencies? • You have another serious problem
  • 44.
    Is this… SIMPLE ? Isis just pure C# code
  • 45.
    Part 2 –Control complexity Composition strikes again…but in different shape
  • 46.
    Writing a programusing functions How to order sequence of functions ? ParseCopyright(string text) { return text + “©” } ParseAppendix(string text) { return text.Remove(“APPENDIX”); }
  • 47.
  • 48.
    But this canfail ParseAppendix function may throw an exception
  • 49.
    Solution Return two kindof things from ParseAppendix function string string Instead of Let’s allow string string Error or
  • 50.
    But function canreturn one thing And only one thing
  • 51.
    Solution Put in inthe box string ParseResult
  • 52.
    What happens tothis now ? ParseCopyright(ParseAppendix(text)); string ParseResultParseAppendix ParseCopyright
  • 53.
    is success Solution Let’s havea special “link”/”connect”/”compose” function string ParseResultParseAppendix ParseCopyrightstring Error Connect
  • 54.
    What we haveseen is a… M***D
  • 55.
  • 58.
    Composition Composition is thekey to controlling complexity in software. “In our study of program design, we have seen that expert programmers control the complexity of their designs with the same general techniques used by designers of all complex systems. They combine primitive elements to form compound objects, they abstract compound objects to form higher-level building blocks, and they preserve modularity by adopting appropriate large-scale views of system structure.”
  • 59.
    Should I dofunctional programming in C# ?
  • 60.
    To take away •Be stupid! Don’t waste your brain on complicated code • Don’t waste your time to understand Rube Goldberg machines • Simplicity. Write only the code that matters. • Readability • Less bugs
  • 61.
  • 62.

Editor's Notes

  • #3 Functional programmers use functions as building blocks to create new functions. There are other language elements available to them but the function is the main construct that the architecture is built from Referential transparency or pure functions. In OOP program state often influences the return of the function
  • #4 What the problem you’re solving and not describing the precise way of the solution
  • #5 Then computer can decide on best evaluation order Parallization opportunities If certain functions can be evaluated at all
  • #7 Programmer needs to understand different techniques and make decisions for and against them based on the problem to solve at hand
  • #8 Very hard to achieve with imperative program accessing shared state. Store data in one place for read and writes (needs LOCKS) when accessible by many functions Complex process can be controlled by composition Side effects cannot be removed completely but can be reduced significantly
  • #10 We don't even question if IoC container is needed because nowadays this is considered granted. We argue between containers and theirs features rather than a correct application design.
  • #19 Can I explain it to junior developer ? Do you want to not hire developers because we don't have 2 years of teaching a framework ?
  • #20 How many developpers do you know that knows Rube Goldberg machine ? What to do if there is a bug in a framework ? You send an email to the group and pray
  • #45 Can I explain it to junior developer ?
  • #47 How can we say what is to be executed first? How can we form an ordered sequence of functions
  • #48 How can we say what is to be executed first? How can we form an ordered sequence of functions
  • #53 And, we don't want to change every function we could connect with ParseAppendix to consume a ParseResult .
  • #54 That way, we can, behind the scenes, adapt the output of one function to feed the following one. This algorithm must be written only once per "boxing type" (different box, different adapting algorithm)
  • #57 A Monad is a pattern for doing function composition with ‘amplified’ types. You can think of an amplified type as a generic type with a single type parameter. IEnumerable<T> is a very good example. Monads provide techniques for removing repetitive and awkward code and can allow us to significantly simplify many programming problems.
  • #59 Composition is the key to controlling complexity in software.