This document summarizes 10 years of experience with framework design guidelines from Microsoft. It discusses core principles of framework design that have remained the same over 10 years, such as layering dependencies and managing types. It also outlines new advances like test-driven development, dependency injection, and tools for dependency management and framework design. The document concludes by emphasizing that framework design principles have stayed consistent while new techniques have emerged to help implement those principles.
12. Properties public class ArrayList { public int Count {get;}} Property getters should be simple and therefore unlikely to throw exceptions Properties should not have dependencies on each other Setting one property should not affect other properties Properties should be settable in any order
13. Properties versus Methods Use a Property: If the member logical attribute of the type Use a method: If the operation is a conversion,such as ToString() If the getter has an observableside effect If order of execution is important If the method might not return immediately If the member returns an array
14. Properties and returning arrays public Employee[] All {get{}} public Employee[] GetAll() {} Calling Code EmployeeList l = FillList(); for (int i = 0; i < l.Length; i++){ if (l.All[i] == x){...} } if (l.GetAll()[i]== x) {...} Moral: Use method if the operation is expensive
16. Extension Methods namespace MyCompany.StringManipulation { public static class StringExtensions{ public static bool IsNullOrEmpty(this string s){ return String.IsNullOrEmpty(s); } } } … using MyCompany.StringManipulation; string message= “hello world”; if(message.IsNullOrEmpty()){ Console.WriteLine(“EMPTY”); }
17. Extension methods marry the usability offered by object-oriented APIs with the flexibility of functional APIs.
18. CONSIDER using extension methods to "add" methods to interfaces public interface IFoo{ void Bar(string x, bool y); void Bar(string x); } public static class IFooExtensions{ public static void Bar(this IFoo foo, string x){ foo.Bar(x,false); } } … IFoo foo = …; foo.Bar(“Hi!”);
19. CONSIDER using extension methods to manage dependencies Uri uri = “ftp://some.ftp.uri”.ToUri(); // higher level assembly (not mscorlib) namespace System.Net { public static class StringExtensions{ public static Uri ToUri(this string s){ … } } }
20. AVOID frivolously defining extension methods, especially on types you don’t own Might add clutter Choose namespaces for sponsor types carefully Remember that not all languages support extension methods Users will have to use static method call syntax
21. AVOID defining extension methods on System.Object // C# declaration of the extension method public static class SomeExtensions{ static void SomeMethod(this object o){…} } ‘ VB will try to find the method at runtime ‘ … but extension methods are resolved at ‘ compile time. Dim o As Object = … o.SomeMethod() ‘ THIS WILL THROW ‘ VB users will have to call the method using the regular static method call syntax. SomeExtensions.SomeMethod(o)
24. Framework Design Theater The Main Character: Bright young developer The Setting: Her first big project The Setup: Create a class that models a car Actions required: Start and Drive
30. V.Next: Worse Yet Now we want to add Color and Model, and we know exactly how But it is much harder because the design is half done and mostly wrong
31. The moral Do as little as possible now (but no less) to ensure room for extensibility in the future
32. Abstract and Base classes Prefer broad, shallow hierarchies Less than or equal to 2 additional levels – Rough rule! Contracts and responsibilities are difficult to maintain and explain in deep complex hierarchies Consider making base classes not constructible (that is, use abstract classes) Make it clear what the class is for Provide a protected constructor for subclasses to call System.Exception should not have had a public constructor
33. Virtual Method Example public class TheBase : Object { public override string ToString() { return “Hello from the Base"; } } public class Derived : TheBase { public override string ToString() { return “Hello from Derived"; } }
34. Virtual Methods What is printed out? Derived d = new Derived();Console.WriteLine (d.ToString()); TheBase tb = d;Console.WriteLine (tb.ToString()); Object o = tb;Console.WriteLine (o.ToString());
35. Virtual Methods They all output “Hello from Derived”. Why? Method call virtualizes at runtime The static type doesn’t matter This is the danger and power of virtual methods Danger: Owner of base classes cannot control what subclasses do Power: Base class does not have to change as new subclasses are created
36. Overriding: Follow the Contract Don’t change the semantics of member Follow the contract defined on the base class All Virtual members should define a contract Don’t require clients to have knowledge of your overriding Should you call the base?
37. Virtual and non-virtual Use non-virtual members unless you have specifically designed for specialization Have a concrete scenario in mind Write the code! Follow the Liskov Substitution Principle References to base types must work with derived types without knowing the difference Must continue to call in the sameorder and frequency Cannot increase or decrease range of inputs or output Barbara Liskov
38. Interface Usage public interface IComparable { int CompareTo(object obj);} No common implementation (the ActiveX problem) Challenging to version over releases The smaller, more focused the interface the better 1-2 members are best But interfaces can be defined in terms of other simpler interfaces
39. The great proof of madness is the disproportion of one's designs to one's means.Napoleon Bonaparte
41. Type Dependency Management Careful dependency management is the necessary ingredient to successful evolution of frameworks. Without it, frameworks quickly deteriorate and are forced out of relevance prematurely.
45. CONSIDER placing library types higher on the dependency stack Definition: Library types are types that are not passed between components Examples EventLog, Debug, Easy to Evolve Leave old in, add new one Beware of duplication!
46. DOkeep primitives policy free (i.e. simple) Definition: Primitive types are types that are passed between components and have very restricted extensibility (i.e. no subtype can override any members) Examples Int32, String, Uri. Hard to Evolve Little need to Evolve Typically in lower layers
47. DO NOTcreate abstractions unless you know what you are doing Definition: Abstractions are interfaces or classes with unsealed members that are passed between components. Examples Stream, IComponent Hard to Evolve Unfortunately, pressure to evolve
51. The Pit of Success: in stark contrast to a summit, a peak, or a journey across a desert to find victory through many trials and surprises, we want our customers to simply fall into winning practices by using our platform and frameworks. To the extent that we make it easy to get into trouble we fail.- Rico Mariani
52. Is using your framework correctly like… Climbing a mountain? 50
53. Is using your framework correctly like… Scaling a peak? 51
54. Is using your framework correctly like… Running across a desert? 52
55. Is using your framework correctly like… Falling into a pit?
56. Make using your framework as easy as falling into a pit – then you have achived great productivity
60. Inversion of Control // your better API public abstract class TraceListener { public abstract void Trace(string message); } public class Tracer { TraceListener listener; public Tracer(TraceListener listener){ this.listener = listener; } public void Trace(string message){ listener.Trace(message); } }
61. Dependency Injection // your customer’s program that is easier to test Tracer tracer = new Tracer(new FileListener()); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … }
62. Dependency Injection Containers // customer’s program that is even easier to test Tracer tracer = container.Resolve<Tracer>(); public void ProcessOrder(Order order){ tracer.Trace(order.Id); … } Check outDI Containers (a.k.a. IoC Containers):autofac, Castle Windsor, PicoContainer.NET, Spring.NET, StructureMap, Unity, and others.
70. Why you don’t read rental car manuals ??? You know how to drive your car All cars work basically the same way Your rental car is a car Therefore, you can drive your rental car That is… The Power of Sameness
71. Naming Conventions PascalCasing – Each word starts with an uppercase letter camelCasing – First word lower case, others uppercase SCREAMING_CAPS – All upper case with underscores
72. Naming Conventions All types and publicly exposed members are PascalCased Parameters are camelCased public class MemberDoc { public int CompareTo(object value) public string Name { get;} }
73. Hungarian Notation Do not use Hungarian notation in publicly exposed APIs and parameter names public class CMyClass { int CompareTo (object objValue) {..} string lpstrName {get;} int iValue {get;} }
74. On Abbreviations, acronym, initialism and the like… Avoid them! They are a classic JLT (jargon loaded term) OK to use them once they become words Html, Xaml, etc Don’t just spell them out Use a meaningful name Abbreviations of more than 2 letters are cased as words, otherwise ALLUPPER IO vs. Html
75. While we are on naming… Good naming is hard—it takes time Be meaningful but brief Use US-English Colour vs. Color Principle of least surprise Look for prior-art NumberOfElements vs. Count
76. FxCop – Keeping the "power of sameness" http://blogs.msdn.com/fxcop
79. Dependency Management Tools http://code.msdn.microsoft.com/fxarch Define Components <Group ID=“Component1”> <Bin Name=“MyCompany.FeatureA.dll”/> <Bin Name=“MyCompany.FeatureB.dll”/> </Group> Define Rules <Allow From=“Component1" To=“WPF"/> <Deny To=“XMLDOM”> Run and Get Output: From group Component1: MyCompany.FeatureA.dll should not depend on: SomeOtherComponent SomeOtherComponent.dll Also check out NDepend – a tool for visualizing dependencies.
80. Summary 10 years of Framework design.. Core Principles of Framework design have stayed the same There are some significant new advances Check out the new book! Brad Abrams http://blogs.msdn.com/brada Twitter: @brada