0
Mixing functional and object oriented approaches to programming in C# Mark Needham
A bit of context
ThoughtWorks delivery projects
Web applications with somewhat complicated domains
5-15 developers on a team
Projects running for 6-12 months
All this means that we want to write code which is…
Easy to understand
Easy to change
Which leads us to what this talk is all about…
Organisation of code <ul><li>‘ The Lush Landscape of Languages’ - The ThoughtWorks Anthology </li></ul><ul><li>Rebecca Par...
How might functional programming help us with that?
First class functions
“ A programming language is said to support first class functions  if functions can be created during the execution of a p...
Immutability
Lazy evaluation
Recursion
Pattern matching
This is all very cool but…
Object Oriented design still has its place
Encapsulation
Abstraction
So how do these two paradigms work together?
Programming in the small/medium/large <ul><li>http://weblogs.asp.net/podwysocki/archive/2009/12/14/going-hybrid-implementi...
In the large…  “a high level that affects as well as crosscuts multiple classes and functions”
In the medium…  “a single API or group of related APIs in such things as classes, interfaces, modules”
In the small…  “individual function/method bodies”
Large Medium Small
Large Medium Small
LINQ
a.k.a. Functional collection parameters <ul><li>http://billsix.blogspot.com/2008/03/functional-collection-patterns-in-ruby...
“powerful abstractions over collections”
“ the use of high-order functions is  extremely useful for separating the collection's concerns from the user of the colle...
for loop becomes less useful
Don’t just use ForEach!
Code becomes more declarative
Declarative? “a statement specifies some aspect of the desired answer with no notion of how that answer is to be determine...
Requires a mental shift from imperative thinking
Transformational mindset <ul><li>Patrick Logan in the comments section </li></ul><ul><li>http://www.markhneedham.com/blog/...
Current Input ??? ??? ??? Desired Output
Going from one collection to another
var  words =  new  List<string>  { “hello”, “world” }; var  upperCaseWords =  new  List<string>(); foreach  (var word  in ...
a.k.a. map
“ hello”, “world” ???? “HELLO”, “WORLD”
“hello”, “world” Select “HELLO”, “WORLD”
var  words =  new  List<string>  { “hello”, “world” }; var  upperCaseWords =  words.Select(w => w.ToUpper());
Remove values we don’t want
var  words =  new  List<string>   {“hello”, “world”}; var  wordsWithH =  new  List<string>(); foreach  (var word  in  word...
a.k.a. filter
“ hello”, “world” ???? “hello”
“ hello”, “world” Where “hello”
var  words =  new  List<string>   {“hello”, “world”} ; var  wordsWithH =  words.Where(w => w.Contains(“h”));
Summing some values
var  values =  new  List<int> { 1,2,3 }; var  total =  0; foreach  (var value  in  values) { total += value; }
a.k.a. reduce
1, 2, 3 ??? 6
1, 2, 3 Sum 6
var  values =  new  List<int> { 1,2,3 }; var  total = val ues.Sum(v => v);
Some examples from projects
Getting the first value that matches a criteria
Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) ???? Foo(“mark”, true)
Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) Where Foo(“mark”, true), Foo(“mike”, true) ??? Foo(“mark”, true)
Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) Where Foo(“mark”, true), Foo(“mike”, true) First Foo(“mark”, true)
var  foos =  new  List<Foo>  {   new Foo(“mark”, true),    new Foo(“dave”, false),   new Foo(“mike”, true)  }; var  firstS...
var  foos =  new  List<Foo>  {   new Foo(“mark”, true),    new Foo(“dave”, false),   new Foo(“mike”, true)  }; var  firstS...
Removing some columns from a dataset
a,b,c,d,e,f ????   “a,d,e,f”
a,b,c,d,e,f Where IEnumerable of a, d, e, f ???   “a,d,e,f”
a,b,c,d,e,f Where IEnumerable of a, d, e, f ??? String.Join  on [a, d, e, f] “a,d,e,f”
a,b,c,d,e,f Where IEnumerable of a, d, e, f ToArray() String.Join  on [a, d, e, f]  “a,d,e,f”
var  aRow =  “a, b, c, d, e, f”; var  newRow =  String.Join(“,”,   aRow   .Split(‘,’)   .Where((_, idx) => !(idx == 1 || i...
var  aRow =  “a, b, c, d, e, f”; var  rowWithColumnsRemoved =  aRow   .Split(‘,’)   .Where((_, idx) => !(idx == 1 || idx =...
Checking if any parameters are null
public class  SomeObject {   public  SomeObject(string p1, string p2,    string p3)   {   if  (p1 ==  null )    throw new ...
public class  SomeObject {   public  SomeObject(string p1, string p2,    string p3)   {   var  params = new List<string> {...
Some lessons from the wild
Dealing with the null collection
<ul><li>public   int  SumNumbers(List< int > list) </li></ul><ul><li>{ </li></ul><ul><li>if(list ==  null ) </li></ul><ul>...
<ul><li>public  IEnumerable<T> EmptyIfNull( this  IEnumerable<T> collection) </li></ul><ul><li>{ </li></ul><ul><li>if(coll...
<ul><li>public   int  SumNumbers(List< int > list) </li></ul><ul><li>{ </li></ul><ul><li>return list. </li></ul><ul><li>Em...
LINQ and the forgotten abstraction
Avoid passing lists around
<ul><li>public class  Quote </li></ul><ul><li>{ </li></ul><ul><li>public  List<Coverage> Coverages  </li></ul><ul><li>{  <...
Later on in the view…
<ul><li><% var coverages = Model.Quote.Coverages; %> </li></ul><ul><li><% if(coverages.Where( </li></ul><ul><li>c => c.Nam...
Objects as the mechanism for encapsulation
<ul><li>public class  Coverages </li></ul><ul><li>{ </li></ul><ul><li>private   readonly  List<Coverage> coverages; </li><...
LINQ is duplication too!
<ul><li>public class  Coverages </li></ul><ul><li>{ </li></ul><ul><li>public  Coverage CoverageType1 </li></ul><ul><li>{ <...
<ul><li>public class  Coverages </li></ul><ul><li>{ </li></ul><ul><li>public  Coverage CoverageType1 </li></ul><ul><li>{ <...
Don’t forget “extract method”
<ul><li>var  someFoos =  new  List<Foo>() </li></ul><ul><li>// put some foos in the list </li></ul><ul><li>someFoos.Select...
<ul><li>var  someFoos =  new  List<Foo>() </li></ul><ul><li>// put some foos in the list </li></ul><ul><li>someFoos.Select...
Naming lambda variables
Putting functions in maps
public void  SomeMethodParsing( string  input) { if  (input == “input1”)  { someMethod(input); } else if  (input == “input...
Dictionary< string , Action< string >> inputs =    new Dictionary< string , Action< string >>    { { “input1” , someMethod...
Large Medium Small
Using functions to simplify some GOF patterns
Action
Func
<ul><li>public class  SomeObject </li></ul><ul><li>{ </li></ul><ul><li>private readonly IStrategy strategy; </li></ul><ul>...
<ul><li>public class  Strategy : IStrategy </li></ul><ul><li>{ </li></ul><ul><li>public void DoSomething(string value) </l...
<ul><li>public class  SomeObject </li></ul><ul><li>{ </li></ul><ul><li>private readonly Action<string> strategy; </li></ul...
Need to ensure we don’t lose readability/understandability
The hole in the middle pattern <ul><li>Brian Hurt </li></ul><ul><li>http://enfranchisedmind.com/blog/posts/the-hole-in-the...
Common beginning and end. Only the middle differs
<ul><li>public class  ServiceCache<Service> </li></ul><ul><li>{ </li></ul><ul><li>protected  Res FromCacheOrService </li><...
<ul><li>public class  CachedService : ServiceCache<IService> </li></ul><ul><li>{ </li></ul><ul><li>public  MyResult GetMyR...
Other ideas I’m intrigued about
The option type
The nested closure
File.open(“someFile.txt”, ‘w’)  do  |out| out  <<  “add something to file” end
public class MyFile  {   public static void Open(string filePath,  Action<StreamWriter> block)   {   using(var writer = ne...
MyFile.Open(“c:ark.txt”, f =>  f.WriteLine(“some random text”));
Writing extension methods to create functional abstractions
Learning more
 
3 things to take away
The transformational mindset
Objects are still the mechanism for encapsulation
Simplify GOF design patterns by using functions
Thanks to… <ul><li>Dave Cameron (not that one!) who I worked with on the structure and general content of the talk. </li><...
Questions? <ul><li>Mark Needham </li></ul><ul><li>http://www.markhneedham.com/blog/ </li></ul><ul><li>[email_address] </li...
Upcoming SlideShare
Loading in...5
×

Mixing functional and object oriented approaches to programming in C#

2,350

Published on

A talk I did at DDD8, January 20th 2010.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,350
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
36
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • So this talk is titled ^ and it will be a summary of some of the ways we’ve made use of the functional style programming constructs introduced in C#3.0 on several projects I’ve worked on over the last year and a half.
  • Transcript of "Mixing functional and object oriented approaches to programming in C#"

    1. 1. Mixing functional and object oriented approaches to programming in C# Mark Needham
    2. 2. A bit of context
    3. 3. ThoughtWorks delivery projects
    4. 4. Web applications with somewhat complicated domains
    5. 5. 5-15 developers on a team
    6. 6. Projects running for 6-12 months
    7. 7. All this means that we want to write code which is…
    8. 8. Easy to understand
    9. 9. Easy to change
    10. 10. Which leads us to what this talk is all about…
    11. 11. Organisation of code <ul><li>‘ The Lush Landscape of Languages’ - The ThoughtWorks Anthology </li></ul><ul><li>Rebecca Parsons </li></ul>
    12. 12. How might functional programming help us with that?
    13. 13. First class functions
    14. 14. “ A programming language is said to support first class functions if functions can be created during the execution of a program, stored in data structures, passed as arguments to other functions, and returned as the values of other functions” <ul><li>Wikipedia </li></ul>
    15. 15. Immutability
    16. 16. Lazy evaluation
    17. 17. Recursion
    18. 18. Pattern matching
    19. 19. This is all very cool but…
    20. 20. Object Oriented design still has its place
    21. 21. Encapsulation
    22. 22. Abstraction
    23. 23. So how do these two paradigms work together?
    24. 24. Programming in the small/medium/large <ul><li>http://weblogs.asp.net/podwysocki/archive/2009/12/14/going-hybrid-implementing-a-shopping-cart-in-f.aspx </li></ul>
    25. 25. In the large… “a high level that affects as well as crosscuts multiple classes and functions”
    26. 26. In the medium… “a single API or group of related APIs in such things as classes, interfaces, modules”
    27. 27. In the small… “individual function/method bodies”
    28. 28. Large Medium Small
    29. 29. Large Medium Small
    30. 30. LINQ
    31. 31. a.k.a. Functional collection parameters <ul><li>http://billsix.blogspot.com/2008/03/functional-collection-patterns-in-ruby.html </li></ul>
    32. 32. “powerful abstractions over collections”
    33. 33. “ the use of high-order functions is extremely useful for separating the collection's concerns from the user of the collection”
    34. 34. for loop becomes less useful
    35. 35. Don’t just use ForEach!
    36. 36. Code becomes more declarative
    37. 37. Declarative? “a statement specifies some aspect of the desired answer with no notion of how that answer is to be determined” <ul><li>‘ The Lush Landscape of Languages’ - The ThoughtWorks Anthology </li></ul><ul><li>Rebecca Parsons </li></ul>
    38. 38. Requires a mental shift from imperative thinking
    39. 39. Transformational mindset <ul><li>Patrick Logan in the comments section </li></ul><ul><li>http://www.markhneedham.com/blog/2010/01/20/functional-collectional-parameters-some-thoughts/ </li></ul>
    40. 40. Current Input ??? ??? ??? Desired Output
    41. 41. Going from one collection to another
    42. 42. var words = new List<string> { “hello”, “world” }; var upperCaseWords = new List<string>(); foreach (var word in words) { upperCaseWords.Add(word.ToUpper()); }
    43. 43. a.k.a. map
    44. 44. “ hello”, “world” ???? “HELLO”, “WORLD”
    45. 45. “hello”, “world” Select “HELLO”, “WORLD”
    46. 46. var words = new List<string> { “hello”, “world” }; var upperCaseWords = words.Select(w => w.ToUpper());
    47. 47. Remove values we don’t want
    48. 48. var words = new List<string> {“hello”, “world”}; var wordsWithH = new List<string>(); foreach (var word in words) { if(word.Contains(“h”) wordsWithH.Add(word); }
    49. 49. a.k.a. filter
    50. 50. “ hello”, “world” ???? “hello”
    51. 51. “ hello”, “world” Where “hello”
    52. 52. var words = new List<string> {“hello”, “world”} ; var wordsWithH = words.Where(w => w.Contains(“h”));
    53. 53. Summing some values
    54. 54. var values = new List<int> { 1,2,3 }; var total = 0; foreach (var value in values) { total += value; }
    55. 55. a.k.a. reduce
    56. 56. 1, 2, 3 ??? 6
    57. 57. 1, 2, 3 Sum 6
    58. 58. var values = new List<int> { 1,2,3 }; var total = val ues.Sum(v => v);
    59. 59. Some examples from projects
    60. 60. Getting the first value that matches a criteria
    61. 61. Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) ???? Foo(“mark”, true)
    62. 62. Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) Where Foo(“mark”, true), Foo(“mike”, true) ??? Foo(“mark”, true)
    63. 63. Foo(“mark”, true), Foo(“dave”, false), Foo(“mike”, true) Where Foo(“mark”, true), Foo(“mike”, true) First Foo(“mark”, true)
    64. 64. var foos = new List<Foo> { new Foo(“mark”, true), new Foo(“dave”, false), new Foo(“mike”, true) }; var firstSpecialFoo = foos. Where(f => f.HasSpecialFlag()). First());
    65. 65. var foos = new List<Foo> { new Foo(“mark”, true), new Foo(“dave”, false), new Foo(“mike”, true) }; var firstSpecialFoo = foos.First(f => f.HasSpecialFlag());
    66. 66. Removing some columns from a dataset
    67. 67. a,b,c,d,e,f ???? “a,d,e,f”
    68. 68. a,b,c,d,e,f Where IEnumerable of a, d, e, f ??? “a,d,e,f”
    69. 69. a,b,c,d,e,f Where IEnumerable of a, d, e, f ??? String.Join on [a, d, e, f] “a,d,e,f”
    70. 70. a,b,c,d,e,f Where IEnumerable of a, d, e, f ToArray() String.Join on [a, d, e, f] “a,d,e,f”
    71. 71. var aRow = “a, b, c, d, e, f”; var newRow = String.Join(“,”, aRow .Split(‘,’) .Where((_, idx) => !(idx == 1 || idx == 2)) .ToArray());
    72. 72. var aRow = “a, b, c, d, e, f”; var rowWithColumnsRemoved = aRow .Split(‘,’) .Where((_, idx) => !(idx == 1 || idx == 2)) .ToArray()); var newRow = String.Join(“,”, rowWithColumnsRemoved);
    73. 73. Checking if any parameters are null
    74. 74. public class SomeObject { public SomeObject(string p1, string p2, string p3) { if (p1 == null ) throw new Exception(...); if (p2 == null ) throw new Exception(...); if (p3 == null ) throw new Exception(...); // rest of constructor logic } }
    75. 75. public class SomeObject { public SomeObject(string p1, string p2, string p3) { var params = new List<string> {p1, p2, p3}; if (params.Any(p => p == null) throw new Exception(...); // rest of constructor logic } }
    76. 76. Some lessons from the wild
    77. 77. Dealing with the null collection
    78. 78. <ul><li>public int SumNumbers(List< int > list) </li></ul><ul><li>{ </li></ul><ul><li>if(list == null ) </li></ul><ul><li>return 0; </li></ul><ul><li>return list.Sum(v => v); </li></ul><ul><li>} </li></ul>
    79. 79. <ul><li>public IEnumerable<T> EmptyIfNull( this IEnumerable<T> collection) </li></ul><ul><li>{ </li></ul><ul><li>if(collection == null ) </li></ul><ul><li>return new List<T>(); </li></ul><ul><li>return collection; </li></ul><ul><li>} </li></ul>Chris Ammerman in the comments section http://www.markhneedham.com/blog/2009/06/16/functional-collection-parameters-handling-the-null-collection/
    80. 80. <ul><li>public int SumNumbers(List< int > list) </li></ul><ul><li>{ </li></ul><ul><li>return list. </li></ul><ul><li>EmptyIfNull(). </li></ul><ul><li>Sum(v => v); </li></ul><ul><li>} </li></ul>
    81. 81. LINQ and the forgotten abstraction
    82. 82. Avoid passing lists around
    83. 83. <ul><li>public class Quote </li></ul><ul><li>{ </li></ul><ul><li>public List<Coverage> Coverages </li></ul><ul><li>{ </li></ul><ul><li>get; set; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    84. 84. Later on in the view…
    85. 85. <ul><li><% var coverages = Model.Quote.Coverages; %> </li></ul><ul><li><% if(coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType1”) %> </li></ul><ul><li>... </li></ul><ul><li><% if(coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType2”) %> </li></ul><ul><li>... </li></ul><ul><li><% if(coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType3”) %> </li></ul>
    86. 86. Objects as the mechanism for encapsulation
    87. 87. <ul><li>public class Coverages </li></ul><ul><li>{ </li></ul><ul><li>private readonly List<Coverage> coverages; </li></ul><ul><li>public Coverages(List<Coverage> coverages) </li></ul><ul><li>{ </li></ul><ul><li>this.coverages = new List<Coverage>(coverages); </li></ul><ul><li>} </li></ul><ul><li>public Coverage CoverageType1 </li></ul><ul><li>{ </li></ul><ul><li> get </li></ul><ul><li> { </li></ul><ul><li> return coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType1”; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    88. 88. LINQ is duplication too!
    89. 89. <ul><li>public class Coverages </li></ul><ul><li>{ </li></ul><ul><li>public Coverage CoverageType1 </li></ul><ul><li>{ </li></ul><ul><li> get </li></ul><ul><li> { </li></ul><ul><li> return coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType1”; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>public Coverage CoverageType2 </li></ul><ul><li>{ </li></ul><ul><li> get </li></ul><ul><li> { </li></ul><ul><li> return coverages.Where( </li></ul><ul><li>c => c.Name == “coverageType2”; </li></ul><ul><li> } </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    90. 90. <ul><li>public class Coverages </li></ul><ul><li>{ </li></ul><ul><li>public Coverage CoverageType1 </li></ul><ul><li>{ </li></ul><ul><li>get { return CoverageByName(“coverageType1”); } </li></ul><ul><li>} </li></ul><ul><li>public Coverage CoverageType2 </li></ul><ul><li>{ </li></ul><ul><li>get { return CoverageByName(“coverageType2”); } </li></ul><ul><li>} </li></ul><ul><li>public Coverage CoverageBy(string name) </li></ul><ul><li>{ </li></ul><ul><li>return coverages.Where(c => c.Name == name); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    91. 91. Don’t forget “extract method”
    92. 92. <ul><li>var someFoos = new List<Foo>() </li></ul><ul><li>// put some foos in the list </li></ul><ul><li>someFoos.Select(f => new NewFoo </li></ul><ul><li> { </li></ul><ul><li>Property1 = f.Property1 </li></ul><ul><li>... </li></ul><ul><li> }); </li></ul>
    93. 93. <ul><li>var someFoos = new List<Foo>() </li></ul><ul><li>// put some foos in the list </li></ul><ul><li>someFoos.Select(f => CreateNewFooFrom(f)); </li></ul>
    94. 94. Naming lambda variables
    95. 95. Putting functions in maps
    96. 96. public void SomeMethodParsing( string input) { if (input == “input1”) { someMethod(input); } else if (input == “input2”) { someOtherMethod(input); } // and so on }
    97. 97. Dictionary< string , Action< string >> inputs = new Dictionary< string , Action< string >> { { “input1” , someMethod }, { “input2” , someOtherMethod } }; public void SomeMethodParsing( string input) { var method = inputs[input]; method(input); }
    98. 98. Large Medium Small
    99. 99. Using functions to simplify some GOF patterns
    100. 100. Action
    101. 101. Func
    102. 102. <ul><li>public class SomeObject </li></ul><ul><li>{ </li></ul><ul><li>private readonly IStrategy strategy; </li></ul><ul><li>public Foo(IStrategy strategy) </li></ul><ul><li>{ </li></ul><ul><li>this.strategy = strategy; </li></ul><ul><li>} </li></ul><ul><li>public void DoSomething(string value) </li></ul><ul><li>{ </li></ul><ul><li>strategy.DoSomething(value); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    103. 103. <ul><li>public class Strategy : IStrategy </li></ul><ul><li>{ </li></ul><ul><li>public void DoSomething(string value) </li></ul><ul><li>{ </li></ul><ul><li>// do something with string </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    104. 104. <ul><li>public class SomeObject </li></ul><ul><li>{ </li></ul><ul><li>private readonly Action<string> strategy; </li></ul><ul><li>public Foo(Action<string> strategy) </li></ul><ul><li>{ </li></ul><ul><li>this. strategy = strategy; </li></ul><ul><li>} </li></ul><ul><li>public void DoSomething(string value) </li></ul><ul><li>{ </li></ul><ul><li> strategy(value); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    105. 105. Need to ensure we don’t lose readability/understandability
    106. 106. The hole in the middle pattern <ul><li>Brian Hurt </li></ul><ul><li>http://enfranchisedmind.com/blog/posts/the-hole-in-the-middle-pattern/ </li></ul>
    107. 107. Common beginning and end. Only the middle differs
    108. 108. <ul><li>public class ServiceCache<Service> </li></ul><ul><li>{ </li></ul><ul><li>protected Res FromCacheOrService </li></ul><ul><li><Req, Res>(Func<Res> serviceCall, Req request) </li></ul><ul><li>{ </li></ul><ul><li>var cachedRes = cache.RetrieveIfExists( </li></ul><ul><li>typeof(Service), typeof(Res), request); </li></ul><ul><li> if(cachedRes == null) </li></ul><ul><li> { </li></ul><ul><li>cachedRes = serviceCall(); </li></ul><ul><li>cache.Add(typeof(Service), request, cachedRes); </li></ul><ul><li> } </li></ul><ul><li>return (Res) cachedRes; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    109. 109. <ul><li>public class CachedService : ServiceCache<IService> </li></ul><ul><li>{ </li></ul><ul><li>public MyResult GetMyResult(MyRequest request) </li></ul><ul><li>{ </li></ul><ul><li>return FromCacheOrService( </li></ul><ul><li>() => service.GetMyResult(request), request); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    110. 110. Other ideas I’m intrigued about
    111. 111. The option type
    112. 112. The nested closure
    113. 113. File.open(“someFile.txt”, ‘w’) do |out| out << “add something to file” end
    114. 114. public class MyFile { public static void Open(string filePath, Action<StreamWriter> block) { using(var writer = new StreamWriter()) { block(writer ); } } }
    115. 115. MyFile.Open(“c:ark.txt”, f => f.WriteLine(“some random text”));
    116. 116. Writing extension methods to create functional abstractions
    117. 117. Learning more
    118. 119. 3 things to take away
    119. 120. The transformational mindset
    120. 121. Objects are still the mechanism for encapsulation
    121. 122. Simplify GOF design patterns by using functions
    122. 123. Thanks to… <ul><li>Dave Cameron (not that one!) who I worked with on the structure and general content of the talk. </li></ul><ul><li>Mike Wagg, Brian Blignaut, Chris Owen for reviewing the talk and giving their input. </li></ul>
    123. 124. Questions? <ul><li>Mark Needham </li></ul><ul><li>http://www.markhneedham.com/blog/ </li></ul><ul><li>[email_address] </li></ul><ul><li>Twitter: markhneedham </li></ul>
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×