functional programming in c#
TRANSCRIPT
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”
Object Oriented Programming
• Encapsulation• Combining data and behavior into classes and objects• Modeling Real-World
Why to talk about ?
• Concurrency programming models• Writing software it’s a complex process• Managing side effects
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 }}
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);
student.Enroll(@class); @class.Enroll(student); _notificationService.Notify(student); _unitOfWork.Commit(); } catch (Exception e) { _logger.LogError(e); } }
[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 } }
AOP with interceptionvar 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
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();x.With<DomainEntityAliaser>();
});
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();x.With<DomainEntityAliaser>();
});
DI flavors
IoC with manual configuration...
var container = new UnityContainer();container.RegisterType<IService, Service>(“Service”);container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IService), “Service”)));
Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(new Service( c.Resolve<ISubServiceProvider(); ));
container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>(); container.RegisterType<IService, Service>();
DI flavors
IoC with manual configuration...
var container = new UnityContainer();container.RegisterType<IService, Service>(“Service”);container.RegisterType<IService,ServiceDecorator>( new InjectionConstructor(new ResolvedParameter(typeof(IService), “Service”)));
Func<IUnityContainer, object> factoryFunc = c => new ServiceDecorator(new Service( c.Resolve<ISubServiceProvider(); ));
container.AddNewExtension<DecoratorContainerExtension>(); container.RegisterType<IService, ServiceDecorator>(); container.RegisterType<IService, Service>();
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.Practices.Unity.Configuration"> <constructor> <param name="logger" parameterType="ILogger"> <dependency name="debugLogger"/> </param> </constructor> </typeConfig> </type> <type type="CustomerTasks"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="context" parameterType="IContext"> <dependency/> </param> </constructor> </typeConfig> </type> </types> </container> </containers> </unity>
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.Practices.Unity.Configuration"> <constructor> <param name="logger" parameterType="ILogger"> <dependency name="debugLogger"/> </param> </constructor> </typeConfig> </type> <type type="CustomerTasks"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="context" parameterType="IContext"> <dependency/> </param> </constructor> </typeConfig> </type> </types> </container> </containers> </unity>
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.Practices.Unity.Configuration"> <constructor> <param name="logger" parameterType="ILogger"> <dependency name="debugLogger"/> </param> </constructor> </typeConfig> </type> <type type="CustomerTasks"> <typeConfig extensionType="Microsoft.Practices.Unity.Configuration.TypeInjectionElement, Microsoft.Practices.Unity.Configuration"> <constructor> <param name="context" parameterType="IContext"> <dependency/> </param> </constructor> </typeConfig> </type> </types> </container> </containers> </unity>
APPROVEDby
System Administr
ator
What problem do we try to solve ?
• Decoupling ?• Testing ?• Modular Design ?• Dependencies management ?
Dependencies are bad....
public class EnrollmentCommandHandler { 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;
Cyclic dependencies are evil....
public class EnrollmentCommandHandler { 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;
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…
Functional way
int Multiply(int a, int b){
return a * b;}
Partial application
Func<int, int> multiplyBy10 = b => Multiply(10, b);
Functional wayint 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
Writing a program using functions
How to order sequence of functions ?
ParseCopyright(string text) { return text + “©” }ParseAppendix(string text) { return text.Remove(“APPENDIX”); }
Solution
Return two kind of things from ParseAppendix function
string string
Instead of Let’s allow
string
string
Error
or
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
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.”
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