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)
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 technologies. (less)
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
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