gavi's picture
From gavi rss RSS  subscribe Subscribe

Brad Abrams - Framework Design Guidelines 



The Art of Building a Reusable Class Library

 

 
 
Tags:  Reusable  Class  Library  framework  design 
Views:  2779
Downloads:  30
Published:  July 31, 2007
 
1
download

Share plick with friends Share
save to favorite
Report Abuse Report Abuse
 
Related Plicks
CakePHP – Highly Recommended Framework for PHP web application developmenl

CakePHP – Highly Recommended Framework for PHP web application developmenl

From: sufalamtech
Views: 252 Comments: 0
We are Web Application Development Company offering Custom Software Applications Development, Web Designing Firm, Open Source Customization and iPhone Application Development in various technologies: PHP, CakePHP, .Internet , J2EE, Linux or Java tec (more)

 
Reusability Guidelines

Reusability Guidelines

From: hillmarket
Views: 3119 Comments: 0

 
Apache Jakarta Commons: Reusable Java(TM) Components

Apache Jakarta Commons: Reusable Java(TM) Components

From: anon-389210
Views: 204 Comments: 0
Apache Jakarta Commons: Reusable Java(TM) Components ,spanish library childrens books, boston university library data base, sixth form library induction, library of congress on line
 
SECh1214

SECh1214

From: anon-145033
Views: 182 Comments: 0
SECh1214
 
Zend Framework By Sanjay Aggarwal

Zend Framework By Sanjay Aggarwal

From: OSSCube
Views: 933 Comments: 0
Sanjay Aggarwal from OSSCube presents on Zend Framework at OSSCamp, organized by OSSCube - A Global open Source enterprise for Open Source Solutions

To know how we can help your business grow, lever (more)

 
Infusion for the birds

Infusion for the birds

From: ccasas
Views: 38 Comments: 0

 
See all 
 
More from this user
Microsoft Office Business Scorecard Manager 2005

Microsoft Office Business Scorecard Manager 2005

From: gavi
Views: 3183
Comments: 0

Google Earth

Google Earth

From: gavi
Views: 4476
Comments: 1

Comparing J2EE with .NET

Comparing J2EE with .NET

From: gavi
Views: 3658
Comments: 0

flash

flash

From: gavi
Views: 1783
Comments: 0

Evolution Of Soa - Gartner

Evolution Of Soa - Gartner

From: gavi
Views: 3664
Comments: 0

 
See all 
 
 
 URL:          AddThis Social Bookmark Button
Embed Thin Player: (fits in most blogs)
Embed Full Player :
 
 

Name

Email (will NOT be shown to other users)

 

 
 
Comments: (watch)
 
 
Notes:
 
Slide 1: The Art of Building a Reusable Class Library Brad Abrams – BradA@Microsoft.com Krzysztof Cwalina - KCWalina@Microsoft.com Microsoft Corporation 1
Slide 2: Turn frustrated developers … into happy developers 2
Slide 3: Goals Understand that API design matters Recognize good API design Lots of good and bad examples Learn the API design process 3
Slide 4: Who is this precon for? Value of this class 1. Developers building reusable library or component 1 10 100 1,000 10,000 100,000 Number of consumers 2. Developer building apps to explicitly understand the rules of the .NET Framework and WinFX 4
Slide 5: Quote of the day I have yet to see any problem, however complicated, which, when looked at the right way did not become still more complicated. Poul Anderson Being complex is easy, being simple is hard 5
Slide 6: Project Cost Model Labor 79% Software 10% Hardware 11% Source: Gartner, May 2002: “The Cost and Risk of Application Development Decisions” Joseph Feiman, Tom Berg 6
Slide 7: Four Keys of Framework Design The Power of Sameness Framework Design Matters Tools for Communication The Pit of Success 7
Slide 8: The Power of Sameness Brad Abrams 8
Slide 9: When you pick up your rental car…. Push the seat all the way back Find an NPR station Find the exit Read the manual?? 9
Slide 10: Oh, down to lock… 10
Slide 11: How to use a key… 11
Slide 12: Oh, you push the PRESS button… 12
Slide 13: Who actually needs this data? 13
Slide 14: 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… 14
Slide 15: Producers and Sameness New System Market Potential Standard System 15
Slide 16: Are things equally as obvious in your framework designs? Maybe you are missing…. 16
Slide 17: Naming Conventions PascalCasing – Each word starts with an uppercase letter camelCasing – First word lower case, others uppercase SCREAMING_CAP S – All upper case with underscores 17
Slide 18: “Blink” Quiz I class1 MyClass; Blink : The Power of Thinking Without Thinking 18
Slide 19: “Blink” Quiz I At-a-glance, first impressions… what does this likely do? A: Compiler error class1 MyClass; B: Class declaration C: Variable declaration D: Other Change the casing to match the pattern, is it easier to tell what this is? Class1 myClass; 19
Slide 20: 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;} } Section 4.1, “Naming Conventions” 20
Slide 21: 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;} } 21
Slide 22: Hungarian Notation (continued) The prefix codes are arbitrary and difficult to learn They make it harder to read an identifier name Hungarian was developed for a time when languages were loosely typed and IDEs were not as powerful E.g. “out” and “ref” parameters information now conveyed at the call site. Interlocked.Increment(ref i) 22
Slide 23: 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 23
Slide 24: 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 24
Slide 25: “Blink” Quiz II Does this compile? IFoo foo = new IFoo(); “No” because you can’t create instances of interfaces Why do we assume IFoo is an interface? 25
Slide 26: Suffixes and Prefixes Interfaces prefix with “I” A tribute to COM Exceptions and Attributes suffixed public interface IFormattable {} Public class NameAttribute : Attribute {} Public class PrinterOnFireException: Exception {} Section 4.1, “Naming Conventions” 26
Slide 27: Quick Quiz What is wrong this this type? public class ArgumentNullException : ArgumentException { public ArgumentNullException () {} public ArgumentNullException (string paramName) {} public ArgumentNullException (string paramName, string message) {} } Section 7.3.4, “ArgumentNullException” 27
Slide 28: Common Exception Usage throw new IOException(); throw new FormatException(); throw new ArgumentException(); throw new InvalidOperationException(); Developers expect all exceptions to work this way… Make your exception meet expectations… 28
Slide 29: Exception Constructor Pattern Every exception should have at least the top three constructors public class XxxException : YyyException { public XxxException () {} public XxxException (string message) {} public XxxException (string message, Exception inner) {} protected XxxException ( SerializationInfo info, StreamingContext context) {} } Section 7.4, “Designing Custom Exceptions” 29
Slide 30: Remember this type…. What is wrong this this type? public class ArgumentNullException : ArgumentException { public ArgumentNullException () {} public ArgumentNullException (string paramName) {} public ArgumentNullException (string paramName, string message) {} } Section 7.3.4, “ArgumentNullException” 30
Slide 31: API design theater… You are optimizing locally, you are I see… why making the right 90% doesn’t time It of the not? decision if Why developers only use the message is not didn’t apply in used, case param you follow type, but if this the your name is what is the exception others as they use pattern? important well…. The Developer The Architect 31
Slide 32: Missing the power of sameness Result: Habit wins out and people commonly type: throw new ArgumentNullException ("the value must pass an employee name"); • We end up with odd error messages such as: Unhandled Exception: System.ArgumentNullException: Value cannot be null. Parameter name: the value must pass an employee name • Moral: Just follow the pattern! 32
Slide 33: Method Overloading: Abusing the Power of Sameness Overloaded: Method on the same type with the same name, but different number or type of arguments public static string ToString(int value) {} public static string ToString(double value) {} 33
Slide 34: Dangers of Method Overloading Why does this man dislike method overloading? Meyer: A single operation should do a single thing.. Abrams: Good method overloading is a single thing – all overloads are semantically the same 34 Bertrand Meyer
Slide 35: Method Overloading String.IndexOf(string value) {} String.IndexOf(char[] anyOf) {} string s = "brad abrams"; s.IndexOf("ab"); // == 5 s.IndexOf('ab'); // == 0 Cobol actually does allow syntax like this Moral: Don’t overload when the methods are semantically different Section 5.1.1, “Method Overloading” 35
Slide 36: Method Overloading Use overloading only when the overloads do semantically the same thing Incorrect overload: String.IndexOf(string value) {} String.IndexOf(char[] anyOf) {} Correct overload: Convert.ToString(int value) {} Convert.ToString(double value) {} Section 5.1.1, “Method Overloading” 36
Slide 37: Method Overloading: Defaults Use appropriate default values Simple method assumes default state More complex methods indicate changes from the default state MethodInfo Type.GetMethod (string name); //ignoreCase = false MethodInfo Type.GetMethod (string name, boolean ignoreCase); Use a zeroed state for the default value (such as: 0, 0.0, false, null, etc.) Section 5.1.1, “Method Overloading” 37
Slide 38: Constructors and Properties Constructor’s parameters are shortcuts for setting properties No difference in semantics between these code snippets EventLog log = new EventLog(); log.MachineName = “kcwalina0”; log.Log = “Security”; EventLog log = new EventLog(“Security”); log.MachineName = “kcwalina0”; EventLog log = new EventLog(“Security”,”kcwalina0”); Section 5.3, “Constructor Design” 38
Slide 39: Exercises… 39
Slide 40: Exercise: Code Review public class HtmlEncoding { public const string DEFAULT_NAME = "Html3.2"; public HtmlEncoding (int iCount) {..} public string Tagname {get {..}} public bool UseIoCompletionPort {get {..}} protected void _coreSetValue (double value) {..} private IntPtr ptrValue; } 40
Slide 41: Exercise: Naming Conventions What are good reasons to violate naming conventions? B. “I used to work in [C++, Java, COBOL]” C. “Our previous version used SCREAMING_CAP” D. “These are initials from someone’s name, they have to be all upper case” 41
Slide 42: Exercise: Code Review public interface Convertible {} Public class CodeReviewer : Attribute {} Public class InputInvalidError: Exception {} 42
Slide 43: Exercise: Code Review public static int MaxValue = 9999999; public void Withdraw () { Withdraw (MaxValue) } public void Withdraw (int amount) { … } 43
Slide 44: Summary The Power of Sameness Teaches us Influence of expectations Naming conventions and common suffixes\prefixes Habits win out over the special cases Common Exception pattern With great power comes great responsibility Method overloading Meet developers where they are constructors and properties pattern teaches us to meet developers’ expectations 44
Slide 45: Questions? 45
Slide 46: Framework Design Matters The role of a framework designer in the development process Krzysztof Cwalina Microsoft 46
Slide 47: The process of framework design is very different from prototyping and implementation 47
Slide 48: Developers focus on a different level 48
Slide 49: Similarly to implementations framework design must be … Simple Integrated Consistent Evolvable ... but the similarities are superficial 49
Slide 50: Well-designed framework must be simple 50
Slide 51: Focus on Top Scenarios Do define top usage scenarios for each major feature area. Do design APIs by first writing code samples for the main scenarios and then defining the object model to support the code samples. Do not require users to explicitly instantiate more than one type in the most basic scenarios. Section 2.2.1, “The Principle of Scenario-Driven Design” 51
Slide 52: Example: Scenario Samples Appendix C, “Sample API Specification” 52
Slide 53: Namespace Factoring Avoid having types designed for advanced scenarios in the same namespace as types intended for common programming tasks. Do ensure that each main feature area namespace contains only types that are used in the most common scenarios. Types used in advanced scenarios should be placed in subnamespaces. Section 4.1, “Types and Namespaces” 53
Slide 54: Example: Namespace Factoring 54
Slide 55: Naming Do favor readability over brevity. The property name CanScrollHorizontally is better than ScrollableX (an obscure reference to the X-axis). Do not use abbreviations or contractions as parts of identifier names. Do not use any acronyms that are not widely accepted, and then, only when necessary. Do reserve the best type names for the most commonly used types. Section 3.2, “General Naming Conventions” 55
Slide 56: Example : Naming 56
Slide 57: Exceptions Do use exception messages to communicate framework usage mistakes to the developer. Section 7.1, “Exception Throwing” 57
Slide 58: Example: Exceptions EventLog log = new EventLog(); Log.WriteEntry(“Hello World”); 58
Slide 59: Well-designed framework must be explicitly designed 59
Slide 60: Create API Specification Appendix C, “Sample API Specification” 60
Slide 61: Review Scenario Samples Solicit feedback on the scenario samples Feedback from non-experts 61
Slide 62: Review API Design 62
Slide 63: Well-designed framework is a part of an ecosystem 63
Slide 64: Intellisense 64
Slide 65: EditorBrowsableAttribute public class MyComponent { [EditorBrowsable(EditorBrowsableState.Always)] public void CommonlyUsedMethod() { … } [EditorBrowsable(EditorBrowsableState.Never)] public void RarelyUsedMethod() { … } [EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() { return base.GetHashCode(); } } 65
Slide 66: Naming Related Members 66
Slide 67: Naming Related Members Fixed 67
Slide 68: Debugger 68
Slide 69: Debugger Attributes [DebuggerTypeProxy(typeof(LinkedListDebuggerView<>))] public class LinkedList<T> { … } internal class LinkedListDebuggerView<T> { public LinkedListDebuggerView(LinkedList<T> list) { … } [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items { get { … } } } 69
Slide 70: Debugger Attributes Result 70
Slide 71: CLS Compliance Do apply CLSCompliantAttribute to framework assemblies. [assembly:CLSCompliant(true)] 71
Slide 72: Example: CLS Compliance 72
Slide 73: Well-designed framework must be integrated 73
Slide 74: Using Common Abstractions Do use the least derived parameter type that provides the functionality required by the member. Do use the least specialized type possible as a parameter type. Most members taking collections as parameters use IEnumerable<T> interface. Do implement IEquatable<T> on value types. Section 5.7, “Parameter Design” (among others) 74
Slide 75: Collection Abstractions 75
Slide 76: Collection Abstractions Fixed 76
Slide 77: Type Name Conflicts Do not introduce generic type names such as ‘Element’, ‘Node’, ‘Log, and ‘Message’. Section 3.4.1, “Namespaces and Type Name Conflicts” 77
Slide 78: Example: Type Name Conflicts 78
Slide 79: Type Name Conflicts – Fixed by User 79
Slide 80: Type Name Conflicts – Fixed by Framework Designer 80
Slide 81: Well-designed framework must be designed to evolve 81
Slide 82: Interfaces vs. Abstract Classes Do favor defining classes over interfaces. Section 4.3, “Choosing Between Class and Interface” 82
Slide 83: Example: Adding Members to Abstractions public abstract class Stream { // new Stream members to support timeouts public virtual int ReadTimeout{ get{ throw new NotSupportedException(…); } set{ throw new NotSupportedException(…); } } public virtual bool CanTimeout { get { return false; } } // other Stream members that shipped previously … } 83
Slide 84: Example: Adding Functionality in Subclasses public class FileStream : Stream { public override bool CanTimeout { get { return true; } } public override int ReadTimeout{ get{ … } set{ … } } } 84
Slide 85: Example: Interface Based Design public interface IStream { … } public class FileStream : IStream { … } 85
Slide 86: Example: Interface Based Design – Adding Timeout public interface ITimeoutEnabledStream : IStream { int ReadTimeout{ get; set; } } public class FileStream : ITimeoutEnabledStream { public int ReadTimeout{ get{ … } set{ … } } } 86
Slide 87: Example: Interface Based Design – Problem StreamReader reader = GetSomeReader(); // dynamic cast (BaseStream returns Stream) ITimeoutEnabledStream stream = reader.BaseStream as ITimeoutEnabledStream; if(stream != null){ stream.ReadTimout = 100; } 87
Slide 88: Example: Abstract Class is Better StreamReader reader = GetSomeReader(); if(reader.BaseStream.CanTimeout){ reader.BaseStream.ReadTimeout = 100; } 88
Slide 89: Control Extensibility Do not make members virtual unless you have a good reason to do so and you are aware of all the costs related to designing, testing, and maintaining virtual members. Section 6.1.4, “Virtual Members” 89
Slide 90: Test Abstractions Do provide at least one type that is an implementation of an interface. Do provide at least one API consuming each interface you define (a method taking the interface as a parameter or a property typed as the interface). Section 5.6, “Interface Design” 90
Slide 91: Well-designed framework must be consistent 91
Slide 92: Naming Consistency Base Type System.Attribute System.Delegate Derived/Implementing Type Guideline Do add the suffix Attribute to custom attribute classes, as in this example. Do add the suffix EventHandler to names of delegates that are used in events. Do add the suffix Callback to names of delegates other than those used as event handlers. Do add the suffix EventArgs Do add the suffix Exception Do add the suffix Permission. System.EventArgs System.Exception CodeAccessPermission IPermission Section 3.5.2, “Names of Common Types” 92
Slide 93: Common Patterns and Idioms Attribute Design Collection Usage XML Usage The Async Pattern Dispose Pattern Sections 8 and 9, “Usage Guidelines” and “Common Design Patterns” 93
Slide 94: Exercise: API Design Process Which of the following is the best way to start API design? A) B) C) Sit in front of a computer and start coding. Use class diagrams to discover main entities of the system. Create a list of most common scenarios and write code samples corresponding to the scenarios. 94
Slide 95: Exercise: Ecosystem What parts of the development environment need to be considered when designing APIs? A) B) C) D) Intellisense Debuggers Documentation All of the above 95
Slide 96: Exercise: Simplicity and Usability What is the main contributor to framework usability? A) B) C) How easy it is to find the right type to use. How easy it is to find the right member to use. Clear exception messages. 96
Slide 97: Summary Framework design does not happen magically Best frameworks are designed upfront by framework designers There are several qualities of a welldesigned framework that require focused framework design process 97
Slide 98: Questions? 98
Slide 99: API Design Experience: The API review Krzysztof Cwalina Brad Abrams 99
Slide 100: Goals for this Exercise Demonstrate how the API design experience really goes Show you some common mistakes and common fixes Laugh with us as we roll play this.. 100
Slide 101: Comment [KC1]:Why interface rather than a b 101
Slide 102: Comment [KC1]:Why sealed? 102
Slide 103: Comment [KC1]:Shou value type? 103
Slide 104: Comment [KC1]:Mak static class? 104
Slide 105: Comment [KC2]:Why an exception? 105
Slide 106: 106
Slide 107: What we showed you… Demonstrated a few examples of how the API design experience really goes Show you some common mistakes and common fixes 107
Slide 108: Tools for Communication Brad Abrams 108
Slide 109: Focus on developer, not yourself 109
Slide 110: Your developers can’t read your mind 110
Slide 111: You must communicate… Examples of what consumers need to know… • Will this operation block? • How do I customize this type? • How should I use this class? 111
Slide 112: Wouldn’t it be great… Luckily, there are Tools for Communicating 112
Slide 113: Documentation alone is not enough 113
Slide 114: Good documentation on a bad API is… like lipstick on a pig… 114
Slide 115: Communicate via leaving artifacts Framework Design Artifacts: • Types • Methods • Properties • Events • Constructors 115
Slide 116: Why is Archeology so hard? All we have is what they left us We can’t directly talk to anyone that built them Hard to find pieces of fragments that fit together Bottom line: ancient civilizations were not intentional about what they left behind Rosetta Stone 116
Slide 117: Don’t force consumers to become archeologists of your framework… Follow a common vocabulary 117
Slide 118: Follow a Common Vocabulary Pre-School level vocabulary for English What is the common vocabulary for API design? 118
Slide 119: Define: Namespace namespace System.IO {} Organizational principle to allow consumers to: Find relevant functionality quickly Exclude less relevant functionality Not about implementation issues Security, identity, size, perf Not a billboard to advertise your organizational Section 4.1, “Types and Namespaces” 119
Slide 120: Define: Class public class Object {} A conceptual model for a thing which can hold state, perform actions, etc Common API design problems Grab bag types (lack of cohesion) Example: System.Runtime.InteropServices.Marshal Modeling overly abstract Example: StreamReader vs. File Section 4.1, “Types and Namespaces” 120
Slide 121: Define: Struct public struct Int32 : IComparable, IFormattable {} A domain specific extension of the intrinsic type system Example: Point, Complex, etc Expert use: perf optimization when GC-Heap allocated objects not warranted Example : an Enumerator Common API design problems: Overuse to avoid GC instance size over 16 bytes Are not immutable Section 4.2, “Choosing between class and struct” 121
Slide 122: Quick Quiz What is wrong with this type? public sealed class Environment { private Environment () { } public bool HasShutDownStarted { get {} } } Section 4.5, “Static Class Design 122
Slide 123: Define: Static Class Container for a set of highly related static members. Commonly used for: Full OO encapsulation not warranted Example: System.Math Convenience methods for a more complex design Example: System.IO.File Common API design problems Doing it “by hand” and getting it wrong Loose cohesion Section 4.5, “Static Class Design 123
Slide 124: Static Classes: Under the Covers public static class Environment { public static string CommandLine { get {..} } } public abstract sealed class Environment { public static void Exit(int exitCode) {..} public static string CommandLine { get {..} } } 124
Slide 125: Define: Exceptions public class FileNotFoundException : IOException Encapsulation of error details used in a structured exception handling system Common API Design Mistakes Using error codes rather the exceptions Creating far too many exceptions Only create new exceptions if callers will handle them differently Section 7, “Exception” 125
Slide 126: Define: Enum Container for named constants public enum Colors { Red = 0, Green = 1, Blue = 2 } Common API Design Mistakes Accepting the default values Using “magic” constants instead SetColor(Colors.Red); SetColor(1); Section 4.8, “Enum Design 126
Slide 127: Enums: Under the Covers Enum values default to 0..N public enum Compression Zip, SuperZip, None } { public struct Compression : public int value__; public const Compression public const Compression public const Compression } Enum { Zip = 0; SuperZip = 1; None = 2; 127
Slide 128: Define: Flags Enums Combinable enum FlagsAttibute powers of 2 [Flags] public enum AttributeTargets { Assembly = 0x0001, Module = 0x0002, Class = 0x0004, Struct = 0x0008, Type = Class | Struct, } Use plural names AttributeTargets rather than AttributeTarget Provide named constants for common flags 128
Slide 129: Flag Enums: Common Mistakes Only use Flag enums when they represent a single concept AttributeTargets is good example The Reflection BindingFlags is an example of what not to do Contains many different concepts in a single value (visibility, static-ness, member kind, etc.) Should not be suffixed in “Flags” 129
Slide 130: Define: Constructor public class Employee { public Employee (string name) {} } Facility to capture state for an instance at time of instantiation Common API design problem Doing too much work in the constructor Section 5.3, “Constructor Design” 130
Slide 131: Constructors are lazy public class XmlFile { string fileName; Stream data; public XmlFile(string fileName) { this.data = DownloadData(fileName); } public XmlFile(string fileName) { this.fileName = fileName; } } Do minimal work in the constructor Be Lazy! Only capture the parameters 131
Slide 132: Define: Methods public sealed class String { public string Insert (string value, int position) } Used to expose actions or operations Common API Design Problem Using properties where methods should be used Section 5.1, “General Member Design” 132
Slide 133: 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 observable side effect If order of execution is important If the method might not return immediately If the member returns an array 133
Slide 134: Properties and returning arrays public Employee[] All {get{}} public Employee[] GetAll() {} Calling Code creates 2n+1 copies of the arrays 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 Section 5.1, “General Member Design” 134
Slide 135: Define: Fields Useful for exposing implementation details thereby constraining your ability to evolve the framework Or, just use properties…  public String FileName; private String fileName; public String FileName{ get { return fileName; } set { fileName = value; } } Section 4.5, “Field Design” 135
Slide 136: Const versus Readonly const Compile-time evaluation Stable across versions Math { readonly Run-time evaluation Unstable across versions class public const double Pi = 3.14; } class Color { public static Color(...); public static Color(...); public static Color(...); readonly Color Red readonly Color Blue = new = new readonly Color Green = new 136
Slide 137: Define: Properties public class ArrayList { public int Count {get{}} } Logical backing field. Useful to encapsulate access to state allowing a degree of flexibility in implementation Common API Design Problem Property vs. Method confusion Section 5.2, “Property Design” 137
Slide 138: Properties Use read only properties where appropriate Do not use write-only properties 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 138
Slide 139: Define: Events public delegate void EventHandler(object sender, dler EventArgs e); Han public class Button: Control { public event EventHandler Click; vent E vent E protected void OnClick(EventArgs e) { if (Click != null) thod e Me Click(this, e); Rais } } Expose callback operation Section 5.4, “Event Design” 139
Slide 140: Common Design Problem with Events Using bad terminology Events are not “fired” or “triggered”, they are “raised” Not using verbs E.g.: Click, Paint, DrawItem, DropDown Not using strongly typed EventArgs to allow for extensibility public class MouseEventArgs : EventArgs { } Section 5.4, “Event Design” 140
Slide 141: Static Members Statics are the .NET equivalent of global variables or global functions Not object oriented Same evils as global But can be very useful System.Math– Full modeling not required public class Int32 { public static int Parse (string value) {..} } int i = Int32.Parse ("42"); 141
Slide 142: Exercises… 142
Slide 143: Exercise: Namespaces What is a good reason to split some related functionality across two namespaces? B. Two different orgs create them C. They are in two different assemblies D. One is the 90% usage case the other in the 10% usage case 143
Slide 144: Exercise: class or struct? public ??? DataValues { decimal d1; decimal d2; decimal d3; decimal d4; public void SetValue (decimal d) {} } 144
Slide 145: Exercise: Exceptions What are good reasons to create a new exception type? B. I get paid by number of types C. The underlying system call returns two different values D. Users handle the two cases differently 145
Slide 146: Exercise: Enums Code review: public enum Fruits { Banana, Apple, Peach, Blueberry } 146
Slide 147: Summary Don’t force your consumers to be archeologists digging for how to use your framework Every element in your design has a specific meaning – Know them and use them correctly Avoid the common mistakes Make brand new mistakes 147
Slide 148: Questions 148
Slide 149: API Design Experience: Designing From Scratch Krzysztof Cwalina Brad Abrams 149
Slide 150: Goals for this Exercise Demonstrate how the API design experience really goes Show you some common mistakes and common fixes How to identify a complex design How to use scenarios to fix the design Laugh at with us as we roll play this.. 150
Slide 151: Assignment: Design a Serial Port 151
Slide 152: «metaclass» PackerBase CommunicationPipe «metaclass» PortsBase ZeroWayCommunicationPipe «metaclass» AbstractUnpacker «implementation class» Ports OneWayCommunicationPipe N_WayCommunicationPipe SerialPort ByteUnpacker DoubleUnpacker SerialCommunicationsPipeline AdopterRoot «metaclass» AbstractPacker TranscatedAdopterRoot AsyncAdopterRoot BufferAdopterRoot BytePacker DoublePacker BufferedReadAdopterRoot BufferedWriteAdopterRoot 152
Slide 153: if(value != handshake) { // in the DCB, handshake affects the fRtsControl, fOutxCtsFlow, and fInX, fOutX fields, // so we must save everything in that closure before making any changes. Handshake handshakeOld = handshake; int fInOutXOld = GetDcbFlag(NativeMethods.FINX); int fOutxCtsFlowOld = GetDcbFlag(NativeMethods.FOUTXCTSFLOW); int fRtsControlOld = GetDcbFlag(NativeMethods.FRTSCONTROL); handshake = value; int fInXOutXFlag = (handshake == Handshake.XOnXOff || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0; SetDcbFlag(NativeMethods.FINX, fInXOutXFlag); SetDcbFlag(NativeMethods.FOUTX, fInXOutXFlag); SetDcbFlag(NativeMethods.FOUTXCTSFLOW, (handshake == Handshake.RequestToSend || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0); if ((handshake == Handshake.RequestToSend || handshake == Handshake.RequestToSendXOnXOff)){ SetDcbFlag(NativeMethods.FRTSCONTROL) } } if (SetCommState(_handle, ref dcb) == false) { handshake = handshakeOld; SetDcbFlag(NativeMethods.FINX, fInOutXOld); SetDcbFlag(NativeMethods.FOUTX, fInOutXOld); SetDcbFlag(NativeMethods.FOUTXCTSFLOW, fOutxCtsFlowOld); SetDcbFlag(NativeMethods.FRTSCONTROL, fRtsControlOld); InternalResources.WinIOError(); }} 153
Slide 154: string num = “234-567-8901”; using (SerialPort mySerialPort = new SerialPort(“COM1”, 14400)) { mySerialPort.DtrEnable = true; mySerialPort.Open(); mySerialPort.Write(“ATDT” + num + Environment.NewLine); mySerialPort.Close(); } Dim Incoming as String Using (Dim sp As New SerialPort (“COM1”, 14400)) Incoming = sp.Read() End Using 154
Slide 155: public sealed class SerialPort : Component { public int InfiniteTimeOut = -1; public int BaudRate { get; set; } public int PortName { get; set; } public int DataBits { get; set; } public StopBits StopBits { get; set; } public Encoding Encoding { get; set; } public int ReadTimeout { get; set; } public int WriteTimeout { get; set; } public Stream BaseStream { get; } public int ReceivedBytesThreshold { get; set; } public bool CDHolding { get; } public bool CtsHolding { get; } public bool DsrHolding { get; } public SerialPort (); public SerialPort (string port); public SerialPort (string port, int baudRate); public void Open(); public void Close(); public int ReadChar(); public void Write(string value); public event SerialPinChangedEventHandler PinChangedEvent; public event SerialErrorEventHandler ErrorEvent; } 155
Slide 156: 156
Slide 157: What we showed you… How to identify a complex design How to use scenarios to fix the design 157
Slide 158: The Pit of Success Brad Abrams 158
Slide 159: 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 159
Slide 160: Is using your framework correctly like… Climbing a mountain? 160
Slide 161: Is using your framework correctly like… Scaling a peak? 161
Slide 162: Is using your framework correctly like… Running across a desert? 162
Slide 163: Is using your framework correctly like… Falling into a pit? 163
Slide 164: Enable the Pit of Success by Avoiding the perilous summit of complexity… And the desert of confusion 164
Slide 165: Make the simple things simple and the hard things possible 165
Slide 166: Exceptions and the Pit of Success “Cleaner, more elegant, and wrong.” Raymond Chen (http://blogs.msdn.com/oldnewthing/) 166
Slide 167: When to throw an Exception? Exceptions rather than error codes Robust: failures get noticed Your method is defined to do something… If it succeeds in performing its purpose, return If it fails to do what it was written to do, throw an exception Section 7, “Exceptions” 167
Slide 168: What Exception to throw? Use or subclass existing exceptions if at all possible Only create separate classes if you think developers will handle the exception differently try { //some operation } catch (FileNotFoundException fe) { //do some set of work } catch (DriveNotFoundException be) { //do some other set of work } Section 7.1, “Exception Throwing” 168
Slide 169: Throwing an Exception Do not just map error codes onto a single exception with an error code property (e.g., the WMIException) Use separate exception types Error Messages Consider localization Use a complete sentence (end in a period) Don’t expose privacy related information (such as file paths) Section 7.1, “Exception Throwing” 169
Slide 170: Performance Minimize the number of exceptions you throw in your API’s success code-paths You don’t pay for exceptions until you throw in managed code Throwing exceptions degrades performance Perf counters tell you exactly how many exceptions your application is throwing Only an issue when using exceptions as a means of control flow Consider providing a way to avoid an exception being thrown Section 7.1, “Exception Throwing” 170
Slide 171: Performance (continued) int i; try { i = Int32.Parse(“123”); } catch (FormatException ) { Console.WriteLine (“Invalid”); } int i; if (!Int32.TryParse (“123”, out i)) { Console.Writeline(“Invalid”); } 171
Slide 172: Managing Resources during Exception Handling You should use try..finally 10 times as often as try..catch Catches eat exceptions making it hard to debug Finally allows you to clean up, but let the exception continue Section 7.2, “Choosing the Right Exception” 172
Slide 173: Managing Resources during Exception Handling try { ... } catch (DivisionByZeroException e) { // do clean up work throw new BetterException (message, e); } You may catch exceptions to re-throw them with a clearer name Typical at an “API” boundary Always nest the underlying exception Catch-and-rethrow has many of the benefits as try..finally But, be aware of debugging issues with catch..throw new() and catch..throw; Generally, cleanup code should go in finalizer 173
Slide 174: Catching Exceptions Do not catch and eat exceptions Exceptions should be handled only where there is enough context to do the right thing That generally means exceptions should be caught as high in the application as possible Mistake – catch the exception, report the error and rethrow it. Only catch where you can handle it Mistake – catch the exception, turn it into a bool pass/fail and return the bool Section 7.2, “Choosing the Right Exception” 174
Slide 175: Catching Exceptions Consider including a try/catch at the top of a thread’s stack if the error can be handled properly Unhandled exceptions at the top of the main thread will terminate the app In 2.0, unhandled exceptions at the top of the stack on any thread will terminate the app But avoid catch blocks in finalizers Be aware: In many cases it is “appropriate” to let the app terminate 175
Slide 176: Catching Exceptions Be aware of (but ignore) exceptions that don’t inherit from System.Exception Allowed in V1.0\V1.1, addressed in V2.0 See UnhandledException event on AppDomain 176
Slide 177: The perilous summit of complexity by example 177
Slide 178: How do I read all the lines from a file? 178
Slide 179: VS7 Era “IO” seems like a reasonable place to start 179
Slide 180: Why did they make it inaccessible Backup, and try again… 180
Slide 181: Open.. Looks like a good first step… 181
Slide 182: Hmm… OK, what do I do with a FileStream ? 182
Slide 183: Ok good, synchronous and asynchronous operations.. What the heck is that? 183
Slide 184: I think I am in the wrong place.. 184
Slide 185: Back up, let’s try a different type 185
Slide 186: Ahh, ReadLine(), this looks more promising.. 186
Slide 187: OK, How do you find the end? 187
Slide 188: Thanks goodness there was a sample 188
Slide 189: The pit of success way developers fall into doing things the right way 189
Slide 190: Just what I need… 190
Slide 191: Ah, a string[] I know just what to do with that… 191
Slide 192: How simple! 192
Slide 193: Enable the Pit of Success by Avoiding the perilous summit of complexity… And the desert of confusion 193
Slide 194: Addition Through Subtraction 10 5 15 194
Slide 195: Addition Through Subtraction Add value by subtracting features And the corollary: Remove value by adding features More features != More Value Section 2.2.2, “The Law of Low Barrier to Entry” 195
Slide 196: Addition Through Subtraction By Example CLR does not support multiple inheritance No Set class in System.Collections No String.OpenFile() method What can you cut from your API to make it more valuable? 196
Slide 197: Addition Through Subtraction and Danger of over-design 197
Slide 198: API Design Theater II 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 198
Slide 199: Design Pass One: Meets Requirements Pass one: meets requirements 199
Slide 200: Design Pass Two: More than Enough 200
Slide 201: Design Pass Three: Way too much 201
Slide 202: Time to Ship… Time to cut… 202
Slide 203: What we ship: Too much and not enough… 203
Slide 204: 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 ½ done and mostly wrong 204
Slide 205: The moral Do as little as possible now (but no less) to ensure room for extensibility in the future 205
Slide 206: Some Specifics Guidelines on Designing for Extensibility 206
Slide 207: 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 (i.e. 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 207
Slide 208: 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"; } } 208
Slide 209: 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()); 209
Slide 210: 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 210
Slide 211: Overriding 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? 211
Slide 212: Virtual and non-virtual Use non-virtual members unless you have specifically designed for specialization Have a concrete scenario in mind Write the code! Think before you virtualize members References to base types must work with derived types without knowing the difference Must continue to call in the same order and frequency Cannot increase or decrease range of inputs or output See the Liskov Substitution Principle 212
Slide 213: Interfaces versus Base Classes Favor using base classes over interfaces Base classes version better in general Allows adding members Members can be added with a default implementation Avoids incompatibilities common in ActiveX Interfaces are good for versioning behavior (changing semantics) 213
Slide 214: Interface Usage public interface IComparable { int CompareTo(object obj); } Interfaces are useful! Solves the multiple root problem The smaller, more focused the interface the better 1-2 members are best But interfaces can be defined in terms of other simpler interfaces Examples: IComparable, IFormattable 214
Slide 215: The great proof of madness is the disproportion of one's designs to one's means. Napoleon Bonaparte 215
Slide 216: Exercises… 216
Slide 217: Exercise: Why Exceptions? Which of the following are good reasons to use error codes rather than exceptions? A) B) C) D) To avoid the base level overhead exceptions add to the system I have always used error codes It is easier to ignore errors when dealing with error codes Error codes are easier to localize than exceptions 217
Slide 218: Exercise: Creating your own Exceptions What is wrong with this picture? PrinterOutOfRedTonerException PrinterOutOfBlackAndWhiteTonerException PrinterOutOfBlueTonerException PrinterOutOfGreenTonerException PrinterOnFireException PrinterOutOfPaperInTrayOneException PrinterOutOfPaperInTrayTwoException PrinterOutOfPaperInTrayThreeException PrinterOutOfPaperInTrayFourException PrinterOutOfPaperInTrayFiveException 218
Slide 219: Exercise: Handling Exceptions Where is the best place to handle exceptions?     Close to where it is thrown At the top level, where you have the most context to handle No where, exceptions are scary Early and often 219
Slide 220: Exercise: Handling Exceptions What is the main exception handling problem with this code? try { CallAMethod(); CallAnotherMethod(); } catch (Exception ) {} CallAThirdMethod(); 220
Slide 221: Exercise: Virtual Methods Mark the following statements true or false    (True/False) Implementations of virtual methods can be effectively replaced by subclasses (True/False) The Runtime insures that overridden methods call their base implementations (True/False) Make as many members virtual as possible to allow for easy extensibility and versioning 221
Slide 222: Summary Allow developers to fall into the pit of success using your framework by avoiding The Perilous Summit of complexity Have the right things get noticed Create the right levels of abstraction The Desert of Confusion Add value by removing features Danger of over design Simple contracts are better 222
Slide 223: API Design Experience: Design your Own… Krzysztof Cwalina Brad Abrams 223
Slide 224: Design E-Mail Component Requirements Send simple text messages Send messages with attachments Simplicity is the main objective 224
Slide 225: Logistics Work in pairs Write the design on a piece of paper or on your laptop If you want feedback Send the design to kcwalina@microsoft.com or … Write your email above the design and leave the paper on your chair. You have 20 minutes 225
Slide 226: Design Process Remember Design Process Samples API Specification 226
Slide 227: Example: Scenario Samples Appendix C, “Sample API Specification” 227
Slide 228: Example: API Specification Appendix C, “Sample API Specification” 228
Slide 229: Design Experience Summary Design an e-mail component Send simple text messages Send messages with attachments Simplicity is the main objective Work in pairs Write on a piece of paper or your laptop Scenario Samples API Specification If you want feedback email us at kcwalina@microsoft.com Write your email above the design and leave the paper on your chair. 229
Slide 230: In Closing… Brad Abrams Krzysztof Cwalina 230
Slide 231: Four Keys of Framework Design The Power of Sameness Framework Design Matters Tools for Communication The Pit of Success 231
Slide 232: The Power of Sameness Influence of expectations Naming conventions and common suffixes\prefixes Habits win out over the special cases Common Exception pattern With great power comes great responsibility Method overloading Meet developers where they are constructors and properties pattern teaches us to meet developers’ expectations 232
Slide 233: Framework Design Matters Framework design does not happen magically Best frameworks are designed upfront by framework designers There are several qualities of a welldesigned framework that require focused framework design process 233
Slide 234: Tools for Communication Don’t force your consumers to be archeologists digging for how to use your framework Every element in your design has a specific meaning – Know them and use them correctly Avoid the common mistakes Make brand new mistakes 234
Slide 235: The Pit Of Success Allow developers to fall into the pit of success using your framework by avoiding The Perilous Summit of complexity Have the right things get noticed Create the right levels of abstraction The Desert of Confusion Add value by removing features Danger of over design Simple contracts are better 235
Slide 236: Feedback… We want your feedback, please take time to fill out the survey… And… please blog… 236
Slide 237: Resources Framework Design Guidelines: Krzysztof Cwalina, Brad Abrams Conventions, Idioms, and Patterns for Reusable .NET Lib Signing now or at the bookstore Wed 1:15-1:45 http://www.gotdotnet.com/team/fxcop/ Brad Abrams brada@microsoft.com http://blogs.msdn.com/brada Krzysztof Cwalina kcwalina@microsoft.com http://blogs.msdn.com/kcwalina 237

   
Time on Slide Time on Plick
Slides per Visit Slide Views Views by Location