Introduction to Spec#

4,878 views

Published on

Published in: Technology
1 Comment
1 Like
Statistics
Notes
No Downloads
Views
Total views
4,878
On SlideShare
0
From Embeds
0
Number of Embeds
68
Actions
Shares
0
Downloads
1
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide
  • Introduction to Spec#

    1. 1. Proof that your software works Presentation created for Spec# v1.0.20411 as released on 11 April 2008
    2. 2. <ul><li>new Person() </li></ul><ul><li>{ </li></ul><ul><li>Fullname = “Pieter Joost van de Sande” , </li></ul><ul><li>CompanyName = “Sogyo” , </li></ul><ul><li>JobTitle = “sr. IT consultant & speaker” , </li></ul><ul><li>SubTitle = “Microsoft C# MVP: Architecture” </li></ul><ul><li>BlogUri = “http://born2code.net” </li></ul><ul><li>Email = &quot;pj@born2code.net&quot; </li></ul><ul><li>}; </li></ul>
    3. 3. <ul><li>Pronounced as “Spec Sharp” </li></ul><ul><li>Microsoft Research project </li></ul><ul><li>Superset of C# 2.0 </li></ul><ul><li>It’s all about contracts </li></ul><ul><li>Current version v1.0.2041 </li></ul><ul><li>Supports </li></ul><ul><ul><li>Visual Studio 2005 </li></ul></ul><ul><ul><li>Visual Studio 2008 </li></ul></ul>
    4. 4. <ul><li>A contract between callers and implementation </li></ul><ul><ul><li>What the implementation can expect from the caller </li></ul></ul><ul><ul><li>What the caller can expect from the implementation </li></ul></ul><ul><li>You don't break contract, that's illegal! </li></ul>
    5. 5. <ul><li>Inslide example </li></ul>
    6. 6. <ul><li>Divide(int x, int y) </li></ul><ul><li>Method signature </li></ul>
    7. 7. <ul><li>int Divide(int x, int y) </li></ul><ul><li>Method signature </li></ul>
    8. 8. <ul><li>public int Divide(int x, int y) </li></ul><ul><li>Method signature </li></ul><ul><li>Visibility </li></ul>
    9. 9. <ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul>
    10. 10. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul>
    11. 11. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul>
    12. 12. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul>
    13. 13. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul>
    14. 14. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    15. 15. <ul><li>Let's have a look </li></ul>
    16. 16. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    17. 17. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What then can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    18. 18. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    19. 19. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    20. 20. <ul><li>/// <summary> Divides <i>x</i> by <i>y</i>. </summary> </li></ul><ul><li>/// <param name=&quot;x&quot;>The value to divide.</param> </li></ul><ul><li>/// <param name=&quot;y&quot;>The value to divide by.</param> </li></ul><ul><li>/// <exception cref=&quot;ArgumentOutOfRangeException&quot;> </li></ul><ul><li>/// Occurs if <i>y</i> is zero. </exception> </li></ul><ul><li>/// <returns>The result of dividing </li></ul><ul><li>/// <i>x</i> by <i>y</i>.</returns> </li></ul><ul><li>public int Divide(int x, int y) </li></ul><ul><li>{ </li></ul><ul><li>if (y == 0) </li></ul><ul><li>throw new ArgumentOutOfRangeException(&quot;y&quot;); </li></ul><ul><li>return x / y; </li></ul><ul><li>} </li></ul><ul><li>Method signature </li></ul><ul><li>Method body </li></ul><ul><li>Documentation </li></ul><ul><li>What we expect </li></ul><ul><li>What they can expect </li></ul><ul><li>Check pre conditions </li></ul><ul><li>Document pre conditions </li></ul>
    21. 23. <ul><li>Null reference </li></ul>
    22. 24. <ul><li>Assumption! </li></ul><ul><ul><li>We assume that variable is not a null reference. </li></ul></ul><ul><ul><li>We don't read documentation </li></ul></ul><ul><ul><li>We trust argument input </li></ul></ul>
    23. 25. <ul><li>Vision behind Spec# </li></ul>
    24. 26. <ul><li>“ program development would be improved if more assumptions were recorded and enforced.” </li></ul>- Mike Barnett, K. Rustan M. Leino, and Wolfram Schulte in Manuscript KRML 136, 12 October 2004
    25. 27. <ul><li>The Spec# team defines a programming language as a tool </li></ul><ul><li>Why the *$%^ must we switch from code, to help file, .doc file to <anything that's !code> ? </li></ul>
    26. 28. <ul><li>Demo </li></ul>
    27. 29. <ul><li>How Spec# works </li></ul>
    28. 36. <ul><li>Can be used within C# </li></ul>
    29. 39. <ul><li>Emits run-time checks for: </li></ul><ul><ul><li>Contracts </li></ul></ul><ul><ul><li>Invariant </li></ul></ul><ul><li>Records the contracts as metadata for consumption by downstream tools </li></ul>
    30. 40. <ul><li>Demo </li></ul>
    31. 43. <ul><li>It’s called Boogie </li></ul><ul><li>A component that generates logical verification conditions from a Spec# program. </li></ul><ul><li>Read MSIL + Meta to create BoogiePL </li></ul><ul><li>Language independent </li></ul>
    32. 47. <ul><li>Minimal version of the .NET Base Class Library with specifications </li></ul>
    33. 50. <ul><li>Glues everything </li></ul>
    34. 52. <ul><li>Inslide examples </li></ul>
    35. 53. <ul><li>String![]! </li></ul>
    36. 54. <ul><li>Many errors in modern programs manifest themselves as null-reference errors </li></ul><ul><li>Spec# tries to eradicate all null reference errors </li></ul><ul><li>In C#, each reference type T includes the value null </li></ul><ul><li>In Spec#, type T! contains only references to objects of type T (not null ). </li></ul><ul><li>int []! xs; </li></ul><ul><li>declares an array called xs which cannot be null </li></ul>
    37. 55. <ul><li>public class Program </li></ul><ul><li>{ </li></ul><ul><li>public static void Main( string [] args) </li></ul><ul><li>{ </li></ul><ul><li>foreach ( string arg in args) // Possible null reference </li></ul><ul><li>{ </li></ul><ul><li>Console.WriteLine(arg); // Possible null reference </li></ul><ul><li>} </li></ul><ul><li>Console.ReadLine(); </li></ul><ul><li> } </li></ul><ul><li>} </li></ul>
    38. 56. <ul><li>If you decide that it's the caller's responsibility to make sure the argument is not null, Spec# allows you to record this decision concisely using an exclamation point. </li></ul><ul><li>Spec# will also enforce the decision at call sites returning Error: null is not a valid argument if a null value is passed to a method that requires a non null parameter. </li></ul>
    39. 57. <ul><li>public class Program </li></ul><ul><li>{ </li></ul><ul><li>public static void Main(string ! [] ! args) </li></ul><ul><li>{ </li></ul><ul><li>foreach ( string arg in args) </li></ul><ul><li>{ </li></ul><ul><li>Console.WriteLine(arg); </li></ul><ul><li>} </li></ul><ul><li>Console.ReadLine(); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>args [i] != null args != null
    40. 58. From Visual Studio, right-click Properties on the project, then Configuration Properties, and set ReferenceTypesAreNonNullByDefault to true Without /nn /nn Possibly-null T T T? Non-null T T! T
    41. 59. public class Foo : Bar { private T _t; public Foo() { _t = new T(); } public override void DoSometing() { _t.Do(); } } Bar b = new Foo();
    42. 60. public class Foo : Bar { private T _t; public Foo() { _t = new T(); } public override void DoSometing() { _t.Do(); } } Bar b = new Foo(); Hint! Hint!
    43. 61. public class Foo : Bar { private T _t; public Foo() : base() { _t = new T(); } public override void DoSometing() { _t.Do(); } } Bar b = new Foo(); public abstract class Bar { public Bar() { DoSomething(); } public abstract void DoSomething(); }
    44. 62. <ul><li>class C </li></ul><ul><li>{ </li></ul><ul><li>T! x; </li></ul><ul><li>public C( int k) </li></ul><ul><li>{ </li></ul><ul><li>x = new T(k); </li></ul><ul><li>x.M(); } </li></ul><ul><li>} </li></ul>Delayed receiver is not compatible with non-delayed method
    45. 63. <ul><li>class C </li></ul><ul><li>{ private T! x; </li></ul><ul><li>[NotDelayed] public C( int k) </li></ul><ul><li>{ x = new T(k); base (); x.M(); } </li></ul><ul><li>} </li></ul>Spec# allows base calls anywhere in a constructor In non-delayed constructors, all non-null fields must be initialized before calling base
    46. 64. <ul><li>ensures universe.Answer == 42; </li></ul>
    47. 65. <ul><li>static int min(int x, int y) </li></ul><ul><li>requires 0<=x&& 0<= y ; </li></ul><ul><li>ensures x<y? result == x: result == y; </li></ul><ul><li>{ </li></ul><ul><li>int m; </li></ul><ul><li>if (x < y) </li></ul><ul><li>m = x; </li></ul><ul><li>else </li></ul><ul><li>m = y; </li></ul><ul><li>return m; </li></ul><ul><li>} </li></ul>
    48. 66. <ul><li>static void Swap (int []a , int i , int j ) </li></ul><ul><li>requires 0 <= i&&i<a.Length; </li></ul><ul><li>requires 0 <= j&&j<a.Length; </li></ul><ul><li>modifies a[i], a[j]; </li></ul><ul><li>ensures a[i] == old (a[j]); </li></ul><ul><li>ensures a[j] == old (a[i]); </li></ul><ul><li>{ </li></ul><ul><li>int temp; </li></ul><ul><li>temp = a[i]; </li></ul><ul><li>a[i] = a[j]; </li></ul><ul><li>a[j] = temp; </li></ul><ul><li>} </li></ul>
    49. 67. <ul><li>==> short-circuiting implication </li></ul><ul><li><==> if and only if </li></ul><ul><li>result denotes method return value </li></ul><ul><li>old (E) denotes E evaluated in method’s pre-state </li></ul><ul><li>requires E; declares precondition </li></ul><ul><li>ensures E; declares postcondition </li></ul><ul><li>modifies w; declares what a method is allowed to modify </li></ul><ul><li>assert E; in-line assertion </li></ul>
    50. 68. <ul><li>modifies w where w is a list of: </li></ul><ul><ul><li>p.x field x of p </li></ul></ul><ul><ul><li>p.* all fields of p </li></ul></ul><ul><ul><li>p.** all fields of all peers of p </li></ul></ul><ul><ul><li>this .* default modifies clause </li></ul></ul><ul><ul><li>this .0 disables the “ this .*” default </li></ul></ul><ul><ul><li>a[i] element i of array a </li></ul></ul><ul><ul><li>a[*] all elements of array a </li></ul></ul>
    51. 69. <ul><li>invariant presentation.SlideCount > 0; </li></ul>
    52. 70. <ul><li>To specify the design of an implementation, we use an assertion involving the data in the class called an object invariant . </li></ul><ul><li>Each object’s data fields must satisfy the invariant at all stable times </li></ul>
    53. 71. <ul><li>class Counter </li></ul><ul><li>{ </li></ul><ul><li>int c; </li></ul><ul><li>invariant 0 <= c; </li></ul><ul><li>public Counter () </li></ul><ul><li>{ </li></ul><ul><li>c= 0; </li></ul><ul><li>} //invariant established & checked after construction </li></ul><ul><li>public void Inc () </li></ul><ul><li> modifies c; </li></ul><ul><li> ensures c == old (c)+1; </li></ul><ul><li>{ </li></ul><ul><li> c++; //invariant checked after every increment </li></ul><ul><li>} </li></ul>
    54. 72. <ul><li>ensure everything.Worksfine; </li></ul>
    55. 73. <ul><li>Null reference cannot happen </li></ul><ul><li>Argument out of range is something that only exists in the past </li></ul><ul><li>Preconditions are always satisfied </li></ul><ul><li>Post conditions are always satisfied </li></ul>
    56. 74. <ul><li>Spec# doesn't force you but it is a tool </li></ul><ul><li>It works better if you have small concrete methods </li></ul><ul><li>Preconditions can contain errors </li></ul><ul><li>Post conditions can contain errors </li></ul><ul><li>It's like TDD's: &quot;who's testing your tests?&quot; </li></ul>
    57. 75. <ul><li>static int GCD(int a, int b) </li></ul><ul><li>requires a > 0 && b > 0; </li></ul><ul><li>ensuresresult > 0 && a % result == 0 && b % result == 0; </li></ul><ul><li>ensuresforall{int k in (1..a+b), a % k ==0 && b % k == 0; k <= result }; </li></ul><ul><li>{ </li></ul><ul><li>int i = 1; int res = 1; </li></ul><ul><li>while (i < a+b) </li></ul><ul><li>invariant i <= a+b; </li></ul><ul><li>invariant res > 0 && a % res == 0 && b % res == 0; </li></ul><ul><li>invariantforall { int k in (1..i), a % k == 0 && b % k == 0; k <= res}; </li></ul><ul><li>{ </li></ul><ul><li>i++; </li></ul><ul><li>if (a % i == 0 && b % i == 0) </li></ul><ul><li>{ </li></ul><ul><li>res = i; </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>return res; </li></ul><ul><li>} </li></ul>
    58. 76. <ul><li>Spec# teams advice: </li></ul><ul><ul><li>everything that you would check at runtime </li></ul></ul><ul><li>For a pacemaker or a rocket, you specify more then for a mail client </li></ul>
    59. 77. <ul><li>Spec# and performance </li></ul>
    60. 78. <ul><li>Your nowaday code should also contain checks </li></ul><ul><li>If you have proven X at compile time, you can remove all checks of X. </li></ul><ul><li>Code with specification can be optimized! </li></ul><ul><ul><li>Pure methods and multithreading are friends </li></ul></ul><ul><ul><li>int with invariant >= 0 can become a uint </li></ul></ul><ul><ul><li>virtual methods shouldn't have null checks on not null types </li></ul></ul>
    61. 79. <ul><li>All the things that didn't fit in the timespan of this presentation </li></ul>
    62. 80. <ul><li>Immutable types cannot be changed. </li></ul><ul><li>[Immutable] </li></ul><ul><li>public class Foo </li></ul><ul><li>{ </li></ul><ul><li>// … </li></ul><ul><li>} </li></ul>
    63. 81. <ul><li>Methods are pure if they have no 'side-effect' </li></ul><ul><ul><li>Great for optimization </li></ul></ul><ul><ul><li>Purity is checked </li></ul></ul>
    64. 82. <ul><li>With the assume keyword you can say 'ignore' negative checks at compile time </li></ul>
    65. 83. <ul><li>Exceptions can be marked so the caller MUST handle them, like in Java. </li></ul>
    66. 84. <ul><li>Model-Based Test Development [7] </li></ul>
    67. 85. <ul><li>Since the late 60’s people are searching for solutions to proof correctness of software </li></ul><ul><ul><li>A Program Verifier, 1969 [1] </li></ul></ul><ul><ul><li>In Proceedings of the international conference on Reliable software, 1975 [2] </li></ul></ul><ul><ul><li>GYPSY, 1977 [4] </li></ul></ul><ul><ul><li>Eiffel, 1986 [5] </li></ul></ul><ul><li>We find contract definitions also in other abstraction levels, like Object Constraint Language (OCL) [6] </li></ul>
    68. 86. <ul><li>Days are different since Spec# </li></ul>
    69. 87. <ul><li>rumor: Design by Contract will come to .NET but not as Spec# </li></ul><ul><li>Performance can raise since contracts give more information </li></ul><ul><li>It can help with object modeling </li></ul><ul><ul><li>UML + OCL = Spec# interface only? </li></ul></ul>
    70. 88. <ul><li>Really, I already knew it when I created this slide </li></ul>
    71. 89. <ul><li>Really, I already knew it when I created this slide </li></ul>Questions?
    72. 90. <ul><li>You can define contracts with your customer </li></ul>
    73. 91. <ul><li>Discussion </li></ul>
    74. 92. <ul><li>Discussion </li></ul>
    75. 93. <ul><li>Pieter Joost van de Sande [C# MVP] </li></ul><ul><li>[email_address] </li></ul><ul><li>Latest presentations: </li></ul><ul><ul><li>Coding Dilemma’s: Architecture </li></ul></ul><ul><ul><li>ATA : TechEd, Barcelona </li></ul></ul><ul><ul><li>AOP with Post# </li></ul></ul><ul><ul><li>Domain Driven Design, 101 </li></ul></ul><ul><ul><li>[…] </li></ul></ul>Free for non-commercial talks http://born2code.net
    76. 94. <ul><li>[7] Using Spec Explorer for Model-Based Test Development - http://dotnet.sys-con.com/node/163765 [2005] </li></ul>

    ×