View
227
Download
3
Category
Preview:
Citation preview
1
The Art of Building a The Art of Building a Reusable Class LibraryReusable Class Library
Brad Abrams – Brad Abrams – BradA@Microsoft.comBradA@Microsoft.com Krzysztof Cwalina - Krzysztof Cwalina - KCWalina@Microsoft.comKCWalina@Microsoft.com Microsoft CorporationMicrosoft Corporation
2
Turn frustrated developersTurn frustrated developers
… … into happy developersinto happy developers
3
GoalsGoals
Understand that API design mattersUnderstand that API design matters
Recognize good API designRecognize good API designLots of good and bad examplesLots of good and bad examples
Learn the API design processLearn the API design process
4
Who is this precon for?Who is this precon for?
1 10 100 1,000 10,000 100,000
Number of consumers
Val
ue
of th
is c
lass
1. Developers building reusable 1. Developers building reusable library or componentlibrary or component
2. Developer building apps to 2. Developer building apps to explicitly understand the rules of explicitly understand the rules of the .NET Framework and WinFXthe .NET Framework and WinFX
5
Quote of the dayQuote of the dayI have yet to see any I have yet to see any
problem, however problem, however complicated, which, complicated, which,
when looked at the right when looked at the right way did not become still way did not become still
more complicated. more complicated. Poul Anderson Poul Anderson
Being complex is Being complex is easy, being simple easy, being simple
is hardis hard
6
Labor79%
Software10%
Hardware11%
Project Cost ModelProject Cost Model
Source: Gartner, May 2002: “The Cost and Risk of Application Development Decisions”Joseph Feiman, Tom Berg
7
Four Keys of Framework Four Keys of Framework DesignDesign
Tools for CommunicationTools for Communication
The Power of SamenessThe Power of Sameness
Framework Design Framework Design MattersMatters
The Pit of SuccessThe Pit of Success
9
When you pick up your When you pick up your rental car….rental car….
Push the seat all the way backPush the seat all the way back
Find an NPR stationFind an NPR station
Find the exitFind the exit
Read the Read the manual??manual??
14
Why you don’t read rental Why you don’t read rental car manuals car manuals
You know how to drive your carYou know how to drive your car
All cars work basically the same wayAll cars work basically the same way
Your rental car is a carYour rental car is a car
Therefore, you can drive your rental Therefore, you can drive your rental carcar
That is…That is…
15
Producers Producers and and
SamenesSameness s
Market Potential Market Potential
Standard SystemStandard System
New SystemNew System
16
Are things equally as Are things equally as obvious in your framework obvious in your framework designs? designs?
Maybe you are missing….Maybe you are missing….
17
Naming ConventionsNaming ConventionsPPascalascalCCasing – asing – Each word starts Each word starts with an with an uppercase letteruppercase letterccamelamelCCasing – asing – First word lower First word lower case, others case, others uppercaseuppercase
SCREAMING_CAPSCREAMING_CAPSS – All upper – All upper case with case with underscoresunderscores
19
““Blink” Quiz IBlink” Quiz IAt-a-glance, first impressions… what At-a-glance, first impressions… what does this likely do?does this likely do?
A: Compiler errorA: Compiler error
B: Class declaration B: Class declaration
C: Variable declarationC: Variable declaration
D: OtherD: Other
class1 MyClass;;
Change the casing to match the Change the casing to match the pattern, is it easier to tell what this pattern, is it easier to tell what this is?is?Class1 myClass;;
20
Naming ConventionsNaming Conventions
All types and publicly exposed All types and publicly exposed members are PascalCasedmembers are PascalCased
Parameters are camelCasedParameters are camelCased
public class MemberDoc{ public int CompareTo(object value) public string Name { get;}}
Section 4.1, “Naming Conventions”Section 4.1, “Naming Conventions”
21
Hungarian NotationHungarian Notation
Do not use Hungarian notation in publicly Do not use Hungarian notation in publicly exposed APIs and parameter namesexposed APIs and parameter names
public class CMyClass {public class CMyClass { int CompareTo (object objValue) {..} int CompareTo (object objValue) {..} string lpstrName {get;} string lpstrName {get;} int iValue {get;} int iValue {get;}}}
22
Hungarian Notation Hungarian Notation (continued)(continued)
The prefix codes are arbitrary and The prefix codes are arbitrary and difficult to learndifficult to learn
They make it harder to read an They make it harder to read an identifier nameidentifier name
Hungarian was developed for a time Hungarian was developed for a time when languages were loosely typed when languages were loosely typed and IDEs were not as powerfuland IDEs were not as powerful
E.g. “out” and “ref” parameters E.g. “out” and “ref” parameters information now conveyed at the call information now conveyed at the call site.site.
Interlocked.Increment(ref i)Interlocked.Increment(ref i)
23
On Abbreviations, On Abbreviations, acronym, initialism and acronym, initialism and the like…the like…Avoid them! Avoid them!
They are a classic JLT (jargon loaded They are a classic JLT (jargon loaded term)term)
OK to use them once they become OK to use them once they become wordswords
Html, Xaml, etcHtml, Xaml, etc
Don’t just spell them outDon’t just spell them outUse a meaningful nameUse a meaningful name
Abbreviations of more than 2 letters Abbreviations of more than 2 letters are cased as words, otherwise are cased as words, otherwise ALLUPPERALLUPPER
IO vs. HtmlIO vs. Html
24
While we are on naming…While we are on naming…
Good naming is hard—it takes timeGood naming is hard—it takes timeBe meaningful but briefBe meaningful but brief
Use US-EnglishUse US-EnglishColourColour vs. vs. ColorColor
Principle of least surprise Principle of least surprise
Look for prior-artLook for prior-art NumberOfElementsNumberOfElements vs. vs. CountCount
25
““Blink” Quiz IIBlink” Quiz IIDoes this compile?Does this compile?
IFoo foo = new IFoo();IFoo foo = new IFoo();
““No” because you can’t create No” because you can’t create instances of interfacesinstances of interfaces
Why do we assume IFoo is an Why do we assume IFoo is an interface?interface?
26
Suffixes and PrefixesSuffixes and Prefixes
Interfaces prefix with “I”Interfaces prefix with “I”A tribute to COMA tribute to COM
Exceptions and Attributes suffixed Exceptions and Attributes suffixed
public interface IFormattable {}
Public class NameAttribute : Attribute {}
Public class PrinterOnFireException: Exception {}
Section 4.1, “Naming Conventions”Section 4.1, “Naming Conventions”
27
Quick QuizQuick Quiz
What is wrong this 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”Section 7.3.4, “ArgumentNullException”
28
Common Exception UsageCommon Exception Usage
Developers expect all exceptions to Developers expect all exceptions to work this way…work this way…
Make your exception meet Make your exception meet expectations…expectations…
throw new throw new IOException();IOException();
throw new throw new FormatException();FormatException();
throw new throw new ArgumentException();ArgumentException();
throw new throw new InvalidOperationException();InvalidOperationException();
29
Exception Constructor Exception Constructor PatternPattern
Every exception should have at Every exception should have at least the top three constructorsleast 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”Section 7.4, “Designing Custom Exceptions”
30
Remember this type…. Remember this type….
What is wrong this 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”Section 7.3.4, “ArgumentNullException”
31
API design theater…API design theater…
The Developer The Architect
Why didn’t you follow the exception pattern?
Why didn’t you follow the exception pattern?
It doesn’t apply in this case
It doesn’t apply in this case
I see… why not?I see… why not?90% of the time
the message is not used, the param name is what is important
90% of the time the message is not used, the param name is what is important
You are optimizing locally, you are making the right
decision if developers only use your type, but if they use others as
well….
You are optimizing locally, you are making the right
decision if developers only use your type, but if they use others as
well….
32
Missing the power of Missing the power of samenesssameness
Result: Habit wins out and people Result: Habit wins out and people commonly type:commonly type:
• We end up with odd error messages such as:
• Moral: Just follow the pattern!
throw new ArgumentNullException ("the value must pass an employee name");
Unhandled Exception: System.ArgumentNullException: Value cannot be null.Parameter name: the value must pass an employee name
33
Method Overloading:Method Overloading:Abusing the Power of Abusing the Power of Sameness Sameness Overloaded: Method on the same Overloaded: Method on the same
type with the same name, but type with the same name, but different number or type of different number or type of arguments arguments
public static string ToString(int value) {}
public static string ToString(double value) {}
34
Dangers of Method Dangers of Method OverloadingOverloading
Meyer: A single operation Meyer: A single operation should do a single thing.. should do a single thing..
Bertrand Meyer
Why does this man dislike Why does this man dislike method overloading? method overloading?
Abrams: Good method Abrams: Good method overloading is a single thing overloading is a single thing – all overloads are – all overloads are semantically the samesemantically the same
35
Method OverloadingMethod OverloadingString.IndexOf(string value) {}
String.IndexOf(char[] anyOf) {}
string s = "brad abrams";s.IndexOf("ab"); // == 5s.IndexOf('ab'); // == 0
Cobol actually does allow Cobol actually does allow syntax like thissyntax like this
Moral: Don’t overload when the Moral: Don’t overload when the methods are semantically methods are semantically differentdifferentSection 5.1.1, “Method Overloading”Section 5.1.1, “Method Overloading”
36
String.IndexOf(string value) {}
String.IndexOf(char[] anyOf) {}
Convert.ToString(int value) {}
Convert.ToString(double value) {}
Method OverloadingMethod OverloadingUse overloading only when the Use overloading only when the overloads do semantically the overloads do semantically the same thingsame thing
Incorrect overload:Incorrect overload:
Correct overload:Correct overload:
Section 5.1.1, “Method Overloading”Section 5.1.1, “Method Overloading”
37
Method Overloading: Method Overloading: DefaultsDefaults
Use appropriate default valuesUse appropriate default valuesSimple method assumes default Simple method assumes default statestate
More complex methods indicate More complex methods indicate changes from the default statechanges from the default state
Use a zeroed state for the default Use a zeroed state for the default value (such as: 0, 0.0, false, null, value (such as: 0, 0.0, false, null, etc.etc.))
MethodInfo Type.GetMethod (string name); //ignoreCase = false
MethodInfo Type.GetMethod (string name, boolean ignoreCase);
Section 5.1.1, “Method Overloading”Section 5.1.1, “Method Overloading”
38
Constructors and Constructors and PropertiesPropertiesConstructor’s parameters are Constructor’s parameters are
shortcuts for setting propertiesshortcuts for setting propertiesNo difference in semantics between No difference in semantics between these code snippetsthese 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”Section 5.3, “Constructor Design”
40
Exercise: Code ReviewExercise: 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;
}
41
Exercise: Naming ConventionsExercise: Naming Conventions
What are good reasons to What are good reasons to violate naming violate naming conventions?conventions?
A.A. ““I used to work in [C++, I used to work in [C++, Java, COBOL]”Java, COBOL]”
B.B. ““Our previous version used Our previous version used SCREAMING_CAP”SCREAMING_CAP”
C.C. ““These are initials from These are initials from someone’s name, they someone’s name, they have to be all upper case”have to be all upper case”
42
Exercise: Code ReviewExercise: Code Review
public interface Convertible {}
Public class CodeReviewer : Attribute {}
Public class InputInvalidError: Exception {}
43
Exercise: Code ReviewExercise: Code Review
public static int MaxValue = 9999999;
public void Withdraw () { Withdraw (MaxValue)}
public void Withdraw (int amount) { …}
44
SummarySummary
The Power of Sameness Teaches usInfluence of expectationsInfluence of expectations
Naming conventions and common suffixes\prefixes
Habits win out over the special Habits win out over the special casescases
Common Exception pattern
With great power comes great With great power comes great responsibilityresponsibility
Method overloading
Meet developers where they areMeet developers where they areconstructors and properties pattern teaches us to
meet developers’ expectations
46
Framework Design MattersFramework Design Matters
The role of a framework designer in the The role of a framework designer in the development processdevelopment process
Krzysztof CwalinaKrzysztof CwalinaMicrosoftMicrosoft
47
The process of framework The process of framework design is very different from design is very different from
prototyping and prototyping and implementationimplementation
49
Similarly to Similarly to implementations implementations framework design must be framework design must be ……
SimpleSimple
IntegratedIntegrated
ConsistentConsistent
EvolvableEvolvable
... but the similarities are ... but the similarities are superficialsuperficial
51
Focus on Top ScenariosFocus on Top Scenarios DoDo define top usage scenarios for define top usage scenarios for
each major feature area.each major feature area. DoDo design APIs by first writing code design APIs by first writing code
samples for the main scenarios and samples for the main scenarios and then defining the object model to then defining the object model to support the code samples.support the code samples.
Do notDo not require users to explicitly require users to explicitly instantiate more than one type in the instantiate more than one type in the most basic scenarios.most basic scenarios.
Section 2.2.1, “The Principle of Scenario-Driven Design”Section 2.2.1, “The Principle of Scenario-Driven Design”
52
Example: Scenario Example: Scenario SamplesSamples
Appendix C, “Sample API Specification”Appendix C, “Sample API Specification”
53
Namespace FactoringNamespace Factoring AvoidAvoid having types designed for having types designed for
advanced scenarios in the same advanced scenarios in the same namespace as types intended for namespace as types intended for common programming tasks.common programming tasks.
DoDo ensure that each main feature ensure that each main feature area namespace contains only types area namespace contains only types that are used in the most common that are used in the most common scenarios. Types used in advanced scenarios. Types used in advanced scenarios should be placed in scenarios should be placed in subnamespaces.subnamespaces.
Section 4.1, “Types and Namespaces”Section 4.1, “Types and Namespaces”
55
NamingNaming DoDo favor readability over brevity. The favor readability over brevity. The
property name CanScrollHorizontally is property name CanScrollHorizontally is better than ScrollableX (an obscure better than ScrollableX (an obscure reference to the X-axis).reference to the X-axis).
Do notDo not use abbreviations or contractions use abbreviations or contractions as parts of identifier names. as parts of identifier names.
Do notDo not use any acronyms that are not use any acronyms that are not widely accepted, and then, only when widely accepted, and then, only when necessary. necessary.
DoDo reserve the best type names for the reserve the best type names for the most commonly used types.most commonly used types.
Section 3.2, “General Naming Conventions”Section 3.2, “General Naming Conventions”
57
ExceptionsExceptions DoDo use exception messages to use exception messages to
communicate framework usage communicate framework usage mistakes to the developer. mistakes to the developer.
Section 7.1, “Exception Throwing”Section 7.1, “Exception Throwing”
58
Example: ExceptionsExample: ExceptionsEventLog log = new EventLog();EventLog log = new EventLog();Log.WriteEntry(“Hello World”);Log.WriteEntry(“Hello World”);
59
Well-designed framework Well-designed framework must be must be explicitly explicitly
designeddesigned
60
Create API SpecificationCreate API Specification
Appendix C, “Sample API Specification”Appendix C, “Sample API Specification”
61
Review Scenario SamplesReview Scenario Samples
Solicit feedback on the scenario Solicit feedback on the scenario samplessamples
Feedback from non-expertsFeedback from non-experts
63
Well-designed framework Well-designed framework is a part of an is a part of an ecosystemecosystem
65
EditorBrowsableAttributeEditorBrowsableAttributepublic class MyComponent {public class MyComponent { [EditorBrowsable(EditorBrowsableState.Always)][EditorBrowsable(EditorBrowsableState.Always)] public void CommonlyUsedMethod() {public void CommonlyUsedMethod() { … … }}
[EditorBrowsable(EditorBrowsableState.Never)][EditorBrowsable(EditorBrowsableState.Never)] public void RarelyUsedMethod() {public void RarelyUsedMethod() { … … }}
[EditorBrowsable(EditorBrowsableState.Never)][EditorBrowsable(EditorBrowsableState.Never)] public override int GetHashCode() {public override int GetHashCode() { return base.GetHashCode();return base.GetHashCode(); }}}}
69
Debugger AttributesDebugger Attributes[DebuggerTypeProxy(typeof(LinkedListDebugger[DebuggerTypeProxy(typeof(LinkedListDebuggerView<>))]View<>))]public class LinkedList<T> {public class LinkedList<T> {……}}
internal class LinkedListDebuggerView<T> {internal class LinkedListDebuggerView<T> { public LinkedListDebuggerView(LinkedList<T> list) public LinkedListDebuggerView(LinkedList<T> list) { … }{ … } [DebuggerBrowsable(DebuggerBrowsableState.RootHid[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]den)] public T[] Items { public T[] Items { get { … }get { … } } } } }
71
CLS ComplianceCLS Compliance DoDo apply CLSCompliantAttribute to apply CLSCompliantAttribute to
framework assemblies.framework assemblies.
[assembly:CLSCompliant(true)][assembly:CLSCompliant(true)]
74
Using Common Using Common AbstractionsAbstractions DoDo use the least derived parameter use the least derived parameter
type that provides the functionality type that provides the functionality required by the member. required by the member.
DoDo use the least specialized type use the least specialized type possible as a parameter type. Most possible as a parameter type. Most members taking collections as members taking collections as parameters use IEnumerable<T> parameters use IEnumerable<T> interface.interface.
DoDo implement IEquatable<T> on implement IEquatable<T> on value types.value types.
Section 5.7, “Parameter Design” (among others)Section 5.7, “Parameter Design” (among others)
77
Type Name ConflictsType Name Conflicts
Do notDo not introduce generic type introduce generic type names such as ‘Element’, ‘Node’, names such as ‘Element’, ‘Node’, ‘Log, and ‘Message’. ‘Log, and ‘Message’.
Section 3.4.1, “Namespaces and Type Name Conflicts”Section 3.4.1, “Namespaces and Type Name Conflicts”
80
Type Name Conflicts – Type Name Conflicts – Fixed by Framework Fixed by Framework DesignerDesigner
81
Well-designed framework Well-designed framework must be must be designed to designed to
evolveevolve
82
Interfaces vs. Abstract Interfaces vs. Abstract ClassesClasses DoDo favor defining classes over favor defining classes over
interfaces. interfaces.
Section 4.3, “Choosing Between Class and Interface”Section 4.3, “Choosing Between Class and Interface”
83
Example: Adding Members Example: Adding Members to Abstractionsto Abstractionspublic abstract class Stream {public abstract class Stream { // new Stream members to support timeouts// new Stream members to support timeouts public virtual int ReadTimeout{public virtual int ReadTimeout{ get{get{ throw new throw new NotSupportedException(…);NotSupportedException(…); } } set{set{ throw new throw new NotSupportedException(…);NotSupportedException(…); } } }} public virtual bool CanTimeout {public virtual bool CanTimeout { get { return false; }get { return false; } }} // other Stream members that shipped // other Stream members that shipped previouslypreviously … …}}
84
Example: Adding Example: Adding Functionality in Functionality in SubclassesSubclassespublic class FileStream : Stream {public class FileStream : Stream { public override bool CanTimeout {public override bool CanTimeout { get { return true; }get { return true; } }} public override int ReadTimeout{public override int ReadTimeout{ get{ … }get{ … } set{ … }set{ … } }}}}
85
Example: Interface Based Example: Interface Based DesignDesign
public interface IStream {public interface IStream { … …}}
public class FileStream : IStream {public class FileStream : IStream { … …}}
86
Example: Interface Based Example: Interface Based Design – Adding TimeoutDesign – Adding Timeoutpublic interface ITimeoutEnabledStream : public interface ITimeoutEnabledStream : IStream {IStream { int ReadTimeout{ get; set; }int ReadTimeout{ get; set; }}}
public class FileStream : public class FileStream : ITimeoutEnabledStream {ITimeoutEnabledStream { public int ReadTimeout{public int ReadTimeout{ get{ … }get{ … } set{ … }set{ … } }}}}
87
Example: Interface Based Example: Interface Based Design – ProblemDesign – ProblemStreamReader reader = GetSomeReader();StreamReader reader = GetSomeReader();
// dynamic cast (BaseStream returns Stream)// dynamic cast (BaseStream returns Stream)ITimeoutEnabledStream stream = ITimeoutEnabledStream stream = reader.BaseStream as ITimeoutEnabledStream;reader.BaseStream as ITimeoutEnabledStream;
if(stream != null){if(stream != null){ stream.ReadTimout = 100;stream.ReadTimout = 100;}}
88
Example: Abstract Class is Example: Abstract Class is BetterBetter
StreamReader reader = GetSomeReader();StreamReader reader = GetSomeReader();if(reader.BaseStream.CanTimeout){if(reader.BaseStream.CanTimeout){ reader.BaseStream.ReadTimeout = 100;reader.BaseStream.ReadTimeout = 100;}}
89
Control ExtensibilityControl Extensibility Do notDo not make members virtual unless make members virtual unless
you have a good reason to do so and you have a good reason to do so and you are aware of all the costs related you are aware of all the costs related to designing, testing, and maintaining to designing, testing, and maintaining virtual members. virtual members.
Section 6.1.4, “Virtual Members”Section 6.1.4, “Virtual Members”
90
Test AbstractionsTest Abstractions
DoDo provide at least one type that is provide at least one type that is an implementation of an interface. an implementation of an interface.
DoDo provide at least one API provide at least one API consuming each interface you define consuming each interface you define (a method taking the interface as a (a method taking the interface as a parameter or a property typed as the parameter or a property typed as the interface). interface).
Section 5.6, “Interface Design”Section 5.6, “Interface Design”
92
Naming ConsistencyNaming ConsistencyBase Type Derived/Implementing Type Guideline
System.Attribute Do add the suffix Attribute to custom attribute classes, as in this example.
System.Delegate 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.
System.EventArgs Do add the suffix EventArgs
System.Exception Do add the suffix Exception
CodeAccessPermission
IPermission
Do add the suffix Permission.
Section 3.5.2, “Names of Common Types”Section 3.5.2, “Names of Common Types”
93
Common Patterns and Common Patterns and IdiomsIdioms
Attribute DesignAttribute Design
Collection UsageCollection Usage
XML UsageXML Usage
The Async PatternThe Async Pattern
Dispose PatternDispose Pattern
Sections 8 and 9, “Usage Guidelines” and “Common Design Patterns”Sections 8 and 9, “Usage Guidelines” and “Common Design Patterns”
94
Exercise: API Design ProcessExercise: API Design Process
Which of the following is the Which of the following is the best way to start API design?best way to start API design?
A)A) Sit in front of a computer and Sit in front of a computer and start coding.start coding.
B)B) Use class diagrams to discover Use class diagrams to discover main entities of the system.main entities of the system.
C)C) Create a list of most common Create a list of most common scenarios and write code scenarios and write code samples corresponding to the samples corresponding to the scenarios.scenarios.
95
Exercise: EcosystemExercise: Ecosystem
What parts of the What parts of the development environment development environment need to be considered when need to be considered when designing APIs?designing APIs?
A)A) IntellisenseIntellisense
B)B) DebuggersDebuggers
C)C) DocumentationDocumentation
D)D) All of the aboveAll of the above
96
Exercise: Simplicity and Exercise: Simplicity and UsabilityUsability
What is the main contributor What is the main contributor to framework usability?to framework usability?
A)A) How easy it is to find the right How easy it is to find the right type to use.type to use.
B)B) How easy it is to find the right How easy it is to find the right member to use.member to use.
C)C) Clear exception messages.Clear exception messages.
97
SummarySummary
Framework design does not happen Framework design does not happen magicallymagically
Best frameworks are designed Best frameworks are designed upfront by framework designersupfront by framework designers
There are several qualities of a well-There are several qualities of a well-designed framework that require designed framework that require focused framework design processfocused framework design process
99
API Design Experience:API Design Experience:The API reviewThe API review
Krzysztof CwalinaKrzysztof CwalinaBrad AbramsBrad Abrams
100
Goals for this ExerciseGoals for this Exercise
Demonstrate how the API design Demonstrate how the API design experience really goes experience really goes
Show you some common mistakes Show you some common mistakes and common fixesand common fixes
Laugh with us as we roll play this.. Laugh with us as we roll play this..
107
What we showed you… What we showed you…
Demonstrated a few examples of how Demonstrated a few examples of how the API design experience really goes the API design experience really goes
Show you some common mistakes Show you some common mistakes and common fixesand common fixes
111
You must communicate… You must communicate…
Examples of what consumers need to Examples of what consumers need to know… know…
• Will this operation block?Will this operation block?
• How do I customize this type?How do I customize this type?
• How should I use this class?How should I use this class?
112
Wouldn’t it be great… Wouldn’t it be great…
Luckily, there are Tools for CommunicatingLuckily, there are Tools for Communicating
114
Good documentation on a Good documentation on a bad API is…bad API is…
like lipstick on a pig…like lipstick on a pig…
115
Communicate via leaving Communicate via leaving artifacts artifacts
Framework Framework Design Artifacts:Design Artifacts:• TypesTypes• MethodsMethods• PropertiesProperties• EventsEvents• ConstructorsConstructors
116
Why is Archeology so Why is Archeology so hard?hard?
All we have is All we have is what they left uswhat they left us
We can’t directly We can’t directly talk to anyone that talk to anyone that built thembuilt them
Hard to find pieces Hard to find pieces of fragments that of fragments that fit togetherfit together
Bottom line: Bottom line: ancient ancient civilizations were civilizations were not intentional not intentional about what they about what they left behind left behind
Rosetta StoneRosetta Stone
117Follow a common Follow a common
vocabulary vocabulary
Don’t force consumers to Don’t force consumers to become archeologists of become archeologists of
your framework… your framework…
118
Follow a Common Follow a Common VocabularyVocabulary
Pre-School level vocabulary for Pre-School level vocabulary for EnglishEnglish
What is the common vocabulary for What is the common vocabulary for API design?API design?
119
Define: NamespaceDefine: Namespace
Organizational principle to allow Organizational principle to allow consumers to:consumers to:
Find relevant functionality quicklyFind relevant functionality quickly
Exclude less relevant functionality Exclude less relevant functionality
Not about implementation issues Not about implementation issues Security, identity, size, perf Security, identity, size, perf
Not a billboard to advertise your Not a billboard to advertise your organizationalorganizational
namespace System.IO {}
Section 4.1, “Types and Namespaces”Section 4.1, “Types and Namespaces”
120
Define: ClassDefine: Class
A conceptual model for a A conceptual model for a thingthing which which can hold state, perform actions, etccan hold state, perform actions, etc
Common API design problemsCommon API design problemsGrab bag types (lack of cohesion)Grab bag types (lack of cohesion)
Example: Example: System.Runtime.InteropServices.MarshalSystem.Runtime.InteropServices.Marshal
Modeling overly abstractModeling overly abstractExample: StreamReader vs. File Example: StreamReader vs. File
public class Object {}
Section 4.1, “Types and Namespaces”Section 4.1, “Types and Namespaces”
121
Define: StructDefine: Struct
A domain specific extension of the intrinsic A domain specific extension of the intrinsic type systemtype system
Example: Point, Complex, etcExample: Point, Complex, etc
Expert use: perf optimization when GC-Expert use: perf optimization when GC-Heap allocated objects not warrantedHeap allocated objects not warranted
Example : an EnumeratorExample : an Enumerator
Common API design problems:Common API design problems:Overuse to avoid GCOveruse to avoid GC
instance size over 16 bytesinstance size over 16 bytes
Are not immutableAre not immutable
public struct Int32 : IComparable,public struct Int32 : IComparable, IFormattable {} IFormattable {}
Section 4.2, “Choosing between class and struct”Section 4.2, “Choosing between class and struct”
122
Quick Quiz Quick Quiz What is wrong with this type?What is wrong with this type?
public sealed class Environment {public sealed class Environment {private Environment () { }private Environment () { }
public bool HasShutDownStarted { public bool HasShutDownStarted { get {} get {}
}}}}
Section 4.5, “Static Class DesignSection 4.5, “Static Class Design
123
Define: Static ClassDefine: Static ClassContainer for a set of highly related Container for a set of highly related static members. Commonly used for:static members. Commonly used for:
Full OO encapsulation not warrantedFull OO encapsulation not warrantedExample: System.MathExample: System.Math
Convenience methods for a more Convenience methods for a more complex designcomplex design
Example: System.IO.FileExample: System.IO.File
Common API design problemsCommon API design problems
Doing it “by hand” and getting it wrong Doing it “by hand” and getting it wrong
Loose cohesion Loose cohesion
Section 4.5, “Static Class DesignSection 4.5, “Static Class Design
124
Static Classes: Under the Static Classes: Under the CoversCoverspublic static class Environment {
public static string CommandLine {
get {..} }}
public abstract sealed class Environment { public static void Exit(int exitCode)
{..} public static string CommandLine { get {..} }}
125
Define: ExceptionsDefine: Exceptions
Encapsulation of error details used in a Encapsulation of error details used in a structured exception handling systemstructured exception handling system
Common API Design MistakesCommon API Design MistakesUsing error codes rather the exceptionsUsing error codes rather the exceptions
Creating far too many exceptionsCreating far too many exceptionsOnly create new exceptions if callers will handle them Only create new exceptions if callers will handle them differentlydifferently
Section 7, “Exception”Section 7, “Exception”
public class FileNotFoundException : IOException
126
Define: EnumDefine: Enum
Container for Container for named constantsnamed constants
public enum Colors public enum Colors { { Red = 0, Red = 0, Green = 1, Green = 1, Blue = 2 Blue = 2}}
Common API Design MistakesCommon API Design MistakesAccepting the default valuesAccepting the default values
Using “magic” constants insteadUsing “magic” constants instead
SetColor(Colors.Red);SetColor(Colors.Red);SetColor(1);SetColor(1);
Section 4.8, “Enum DesignSection 4.8, “Enum Design
127
Enums: Under the CoversEnums: Under the Covers
Enum values default to 0..NEnum values default to 0..N
public enum Compression {public enum Compression { Zip, SuperZip, NoneZip, SuperZip, None }}
public struct Compression : Enum {public struct Compression : Enum { public int value__;public int value__; public const Compression Zip = 0; public const Compression Zip = 0; public const Compression SuperZip = 1;public const Compression SuperZip = 1; public const Compression None = 2;public const Compression None = 2;}}
128
Define: Flags EnumsDefine: Flags EnumsCombinable Combinable enumenum
FlagsAttibutFlagsAttibutee
powers of 2powers of 2
[Flags] [Flags] public enum AttributeTargets public enum AttributeTargets { { Assembly = 0x0001, Assembly = 0x0001, Module = 0x0002, Module = 0x0002, Class = 0x0004, Class = 0x0004, Struct = 0x0008, Struct = 0x0008, Type = Class | Struct, Type = Class | Struct,}}
Use plural namesUse plural namesAttributeTargetAttributeTargetss rather than rather than AttributeTargetAttributeTarget
Provide named constants for Provide named constants for common flagscommon flags
129
Flag Enums: Common Flag Enums: Common MistakesMistakes
Only use Flag enums when they Only use Flag enums when they represent a single conceptrepresent a single concept
AttributeTargets is good example AttributeTargets is good example
The Reflection BindingFlags is an The Reflection BindingFlags is an example of what example of what notnot to do to do
Contains many different concepts in a single Contains many different concepts in a single value (visibility, static-ness, member kind, value (visibility, static-ness, member kind, etc.etc.))
Should not be suffixed in “Flags”Should not be suffixed in “Flags”
130
Define: ConstructorDefine: Constructor
Facility to capture state for an Facility to capture state for an instance at time of instantiation instance at time of instantiation
Common API design problemCommon API design problemDoing too much work in the constructorDoing too much work in the constructor
public class Employee {public class Employee { public Employee (string name) {} public Employee (string name) {}}}
Section 5.3, “Constructor Design”Section 5.3, “Constructor Design”
131
Constructors areConstructors are
Do minimal work in Do minimal work in the constructorthe constructor
Be Lazy! Be Lazy!
Only capture the Only capture the parametersparameters
public class XmlFile {public class XmlFile { string fileName; string fileName; Stream data; Stream data; public XmlFile(string fileName) { public XmlFile(string fileName) { this.data = DownloadData(fileName); this.data = DownloadData(fileName); }}}}
public XmlFile(string fileName) {public XmlFile(string fileName) { this.fileName = fileName; this.fileName = fileName; } }
lazylazy
132
Define: MethodsDefine: Methods
Used to expose actions or operationsUsed to expose actions or operations
Common API Design ProblemCommon API Design ProblemUsing properties where methods should Using properties where methods should be usedbe used
public sealed class String {public sealed class String { public string Insert (string value, public string Insert (string value,
int position) int position)}}
Section 5.1, “General Member Design”Section 5.1, “General Member Design”
133
Properties versus MethodsProperties versus Methods
Use a Property:Use a Property:If the member logical attribute of the If the member logical attribute of the typetype
Use a method: Use a method: If the operation is a conversion, such as If the operation is a conversion, such as ToString()ToString()
If the getter has an observable side If the getter has an observable side effecteffect
If order of execution is importantIf order of execution is important
If the method might not return If the method might not return immediatelyimmediately
If the member returns an arrayIf the member returns an array
134
EmployeeList l = FillList();EmployeeList l = FillList();for (int i = 0; i < l.Length; i++) for (int i = 0; i < l.Length; i++) {{ if (l.All[i] == x){...}if (l.All[i] == x){...}}} if (l.GetAll()[i]== x) {...}if (l.GetAll()[i]== x) {...}
public Employee[] All {get{}}public Employee[] All {get{}}
public Employee[] GetAll() {}public Employee[] GetAll() {}
Moral: Use method if the operation is expensive Moral: Use method if the operation is expensive
Calling CodeCalling Code creates 2n+1 copies of creates 2n+1 copies of the arraysthe arrays
Properties and returning Properties and returning arraysarrays
Section 5.1, “General Member Design”Section 5.1, “General Member Design”
135
Define: FieldsDefine: FieldsUseful for exposing implementation Useful for exposing implementation details thereby constraining your details thereby constraining your ability to evolve the frameworkability to evolve the framework
Or, just use properties… Or, just use properties…
Section 4.5, “Field Design”Section 4.5, “Field Design”
public String FileName;public String FileName;
private String fileName;private String fileName;public String FileName{public String FileName{ get { return fileName; } get { return fileName; } set { fileName = value; } set { fileName = value; }}}
136
Const versus ReadonlyConst versus Readonlyconstconst
Compile-time Compile-time evaluationevaluation
Stable across Stable across versionsversions
readonlyreadonlyRun-time Run-time evaluationevaluation
Unstable across Unstable across versionsversionsclass Math {class Math {
public const double Pi = 3.14;public const double Pi = 3.14;}}
class Color {class Color { public static readonly Color Red = new public static readonly Color Red = new Color(...);Color(...); public static readonly Color Blue = new public static readonly Color Blue = new Color(...);Color(...); public static readonly Color Green = new public static readonly Color Green = new Color(...);Color(...);}}
137
Define: PropertiesDefine: Properties
Logical backing field. Useful to Logical backing field. Useful to encapsulate access to state allowing encapsulate access to state allowing a degree of flexibility in a degree of flexibility in implementationimplementation
Common API Design ProblemCommon API Design ProblemProperty vs. Method confusionProperty vs. Method confusion
public class ArrayList {public class ArrayList { public int Count {get{}} public int Count {get{}}}}
Section 5.2, “Property Design”Section 5.2, “Property Design”
138
PropertiesPropertiesUse read only properties where Use read only properties where appropriateappropriate
Do not use write-only propertiesDo not use write-only properties
Property getters should be simple Property getters should be simple and therefore unlikely to throw and therefore unlikely to throw exceptionsexceptions
Properties should not have Properties should not have dependencies on each otherdependencies on each other
Setting one property should not affect Setting one property should not affect other propertiesother properties
Properties should be settable in any Properties should be settable in any orderorder
139
public delegate void EventHandler(object sender,public delegate void EventHandler(object sender, EventArgs e);EventArgs e);
public class Button: Control {public class Button: Control { public event EventHandler Click; public event EventHandler Click;
protected void OnClick(EventArgs e) {protected void OnClick(EventArgs e) { if (Click != null) if (Click != null) Click(this, e);Click(this, e); } }}}
Define: EventsDefine: Events
Expose callback operationExpose callback operation
Event Event
HandlerHandler
EventEvent
Raise Raise
MethodMethod
Section 5.4, “Event Design”Section 5.4, “Event Design”
140
Common Design Problem Common Design Problem with Events with Events
Using bad terminologyUsing bad terminologyEvents are not “fired” or “triggered”, Events are not “fired” or “triggered”, they are “raised”they are “raised”
Not using verbsNot using verbsE.g.E.g.: Click, Paint, DrawItem, DropDown: Click, Paint, DrawItem, DropDown
Not using strongly typed EventArgs Not using strongly typed EventArgs to allow for extensibility to allow for extensibility public class MouseEventArgs :public class MouseEventArgs : EventArgs { } EventArgs { }
Section 5.4, “Event Design”Section 5.4, “Event Design”
141
Static MembersStatic MembersStatics are the .NET equivalent of Statics are the .NET equivalent of global variables or global functionsglobal variables or global functions
Not object orientedNot object oriented
Same evils as globalSame evils as global
But can be very usefulBut can be very useful System.Math– Full modeling not requiredSystem.Math– Full modeling not required
public class Int32 {public class Int32 { public static int Parse (string value) {..}public static int Parse (string value) {..}}}
int i = Int32.Parse ("42");int i = Int32.Parse ("42");
143
Exercise: NamespacesExercise: Namespaces
What is a good reason to split What is a good reason to split some related functionality some related functionality across two namespaces?across two namespaces?
A.A. Two different orgs create Two different orgs create themthem
B.B. They are in two different They are in two different assembliesassemblies
C.C. One is the 90% usage case One is the 90% usage case the other in the 10% usage the other in the 10% usage casecase
144
Exercise: class or struct? Exercise: class or struct?
public public ??? ??? DataValues {DataValues { decimal d1; decimal d1; decimal d2; decimal d2; decimal d3; decimal d3; decimal d4; decimal d4; public void SetValue (decimal d) {} public void SetValue (decimal d) {}}}
145
Exercise: ExceptionsExercise: Exceptions
What are good reasons to What are good reasons to create a new exception create a new exception type?type?
A.A. I get paid by number of I get paid by number of typestypes
B.B. The underlying system call The underlying system call returns two different valuesreturns two different values
C.C. Users handle the two cases Users handle the two cases differentlydifferently
146
Exercise: EnumsExercise: Enums
Code review: Code review:
public enum Fruits { Banana, Apple, Peach, Blueberry}
147
SummarySummary
Don’t force your consumers to be Don’t force your consumers to be archeologists digging for how to use archeologists digging for how to use your frameworkyour framework
Every element in your design has a Every element in your design has a specific meaning – Know them and specific meaning – Know them and use them correctlyuse them correctly
Avoid the common mistakesAvoid the common mistakesMake brand new mistakes Make brand new mistakes
149
API Design Experience:API Design Experience:Designing From Scratch Designing From Scratch
Krzysztof CwalinaKrzysztof CwalinaBrad AbramsBrad Abrams
150
Goals for this ExerciseGoals for this Exercise
Demonstrate how the API design Demonstrate how the API design experience really goes experience really goes
Show you some common mistakes Show you some common mistakes and common fixesand common fixes
How to identify a complex designHow to identify a complex design
How to use scenarios to fix the designHow to use scenarios to fix the design
Laugh at with us as we roll play this.. Laugh at with us as we roll play this..
151
Assignment:
Design Design a Serial a Serial Port Port APIAPI
Assignment:
Design Design a Serial a Serial Port Port APIAPI
152
SerialPort
SerialCommunicationsPipeline
«implementation class»Ports
«metaclass»PortsBase
CommunicationPipe
ZeroWayCommunicationPipe OneWayCommunicationPipe
N_WayCommunicationPipe
ByteUnpacker
«metaclass»AbstractUnpacker
DoubleUnpacker
BytePacker
«metaclass»AbstractPacker
DoublePacker
«metaclass»PackerBase
AdopterRoot
AsyncAdopterRoot
BufferedReadAdopterRoot
BufferAdopterRoot
BufferedWriteAdopterRoot
TranscatedAdopterRoot
153
if(value != handshake) {if(value != handshake) {// in the DCB, handshake affects the fRtsControl, fOutxCtsFlow, and fInX, fOutX // in the DCB, handshake affects the fRtsControl, fOutxCtsFlow, and fInX, fOutX fields,fields,// so we must save everything in that closure before making any changes.// so we must save everything in that closure before making any changes.Handshake handshakeOld = handshake;Handshake handshakeOld = handshake;int fInOutXOld = GetDcbFlag(NativeMethods.FINX);int fInOutXOld = GetDcbFlag(NativeMethods.FINX);int fOutxCtsFlowOld = GetDcbFlag(NativeMethods.FOUTXCTSFLOW);int fOutxCtsFlowOld = GetDcbFlag(NativeMethods.FOUTXCTSFLOW);int fRtsControlOld = GetDcbFlag(NativeMethods.FRTSCONTROL);int fRtsControlOld = GetDcbFlag(NativeMethods.FRTSCONTROL);handshake = value;handshake = value;int fInXOutXFlag = (handshake == Handshake.XOnXOff || handshake == int fInXOutXFlag = (handshake == Handshake.XOnXOff || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0;Handshake.RequestToSendXOnXOff) ? 1 : 0;SetDcbFlag(NativeMethods.FINX, fInXOutXFlag);SetDcbFlag(NativeMethods.FINX, fInXOutXFlag);SetDcbFlag(NativeMethods.FOUTX, fInXOutXFlag);SetDcbFlag(NativeMethods.FOUTX, fInXOutXFlag);SetDcbFlag(NativeMethods.FOUTXCTSFLOW, (handshake == Handshake.RequestToSend ||SetDcbFlag(NativeMethods.FOUTXCTSFLOW, (handshake == Handshake.RequestToSend || handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0);handshake == Handshake.RequestToSendXOnXOff) ? 1 : 0);if ((handshake == Handshake.RequestToSend ||if ((handshake == Handshake.RequestToSend || handshake == Handshake.RequestToSendXOnXOff)){handshake == Handshake.RequestToSendXOnXOff)){SetDcbFlag(NativeMethods.FRTSCONTROL) }SetDcbFlag(NativeMethods.FRTSCONTROL) }} } if (SetCommState(_handle, ref dcb) == false) {if (SetCommState(_handle, ref dcb) == false) { handshake = handshakeOld;handshake = handshakeOld; SetDcbFlag(NativeMethods.FINX, fInOutXOld);SetDcbFlag(NativeMethods.FINX, fInOutXOld); SetDcbFlag(NativeMethods.FOUTX, fInOutXOld);SetDcbFlag(NativeMethods.FOUTX, fInOutXOld); SetDcbFlag(NativeMethods.FOUTXCTSFLOW, fOutxCtsFlowOld);SetDcbFlag(NativeMethods.FOUTXCTSFLOW, fOutxCtsFlowOld); SetDcbFlag(NativeMethods.FRTSCONTROL, fRtsControlOld);SetDcbFlag(NativeMethods.FRTSCONTROL, fRtsControlOld); InternalResources.WinIOError();InternalResources.WinIOError();} }} }
154
string num = “234-567-8901”;string num = “234-567-8901”;using (SerialPort mySerialPort = new SerialPort(“COM1”, 14400)) using (SerialPort mySerialPort = new SerialPort(“COM1”, 14400)) {{
mySerialPort.DtrEnable = true;mySerialPort.DtrEnable = true;mySerialPort.Open();mySerialPort.Open();mySerialPort.Write(“ATDT” + num + Environment.NewLine);mySerialPort.Write(“ATDT” + num + Environment.NewLine);mySerialPort.Close();mySerialPort.Close();
}}
Dim Incoming as StringDim Incoming as StringUsing (Dim sp As New SerialPort (“COM1”, 14400))Using (Dim sp As New SerialPort (“COM1”, 14400))
Incoming = sp.Read()Incoming = sp.Read()End UsingEnd Using
155
public sealed class SerialPort : Component {public sealed class SerialPort : Component {public int InfiniteTimeOut = -1;public int InfiniteTimeOut = -1;public int BaudRate { get; set; }public int BaudRate { get; set; }public int PortName { get; set; }public int PortName { get; set; }public int DataBits { get; set; }public int DataBits { get; set; }public StopBits StopBits { get; set; }public StopBits StopBits { get; set; }public Encoding Encoding { get; set; }public Encoding Encoding { get; set; }public int ReadTimeout { get; set; }public int ReadTimeout { get; set; }public int WriteTimeout { get; set; }public int WriteTimeout { get; set; }public Stream BaseStream { get; }public Stream BaseStream { get; }public int ReceivedBytesThreshold { get; set; }public int ReceivedBytesThreshold { get; set; }public bool CDHolding { get; }public bool CDHolding { get; }public bool CtsHolding { get; }public bool CtsHolding { get; }public bool DsrHolding { get; }public bool DsrHolding { get; }public SerialPort ();public SerialPort ();public SerialPort (string port);public SerialPort (string port);public SerialPort (string port, int baudRate);public SerialPort (string port, int baudRate);public void Open();public void Open();public void Close();public void Close();public int ReadChar();public int ReadChar();public void Write(string value);public void Write(string value);public event SerialPinChangedEventHandler PinChangedEvent;public event SerialPinChangedEventHandler PinChangedEvent;public event SerialErrorEventHandler ErrorEvent;public event SerialErrorEventHandler ErrorEvent;
}}
157
What we showed you…What we showed you…
How to identify a complex designHow to identify a complex design
How to use scenarios to fix the How to use scenarios to fix the designdesign
159
The Pit of SuccessThe Pit of Success: in stark : in stark contrast to a summit, a peak, or contrast to a summit, a peak, or
a journey across a desert to a journey across a desert to find victory through many trialsfind victory through many trials
and surprises, we want our and surprises, we want our customers to customers to simply fall into simply fall into
winning practiceswinning practices by using our by using our platform and frameworks. To platform and frameworks. To
the extent that the extent that we make it easy we make it easy to get into trouble we failto get into trouble we fail..
- Rico Mariani- Rico Mariani
160
Is using your framework correctly Is using your framework correctly like…like…
Climbing a mountain?Climbing a mountain?
161
Is using your framework correctly Is using your framework correctly like…like…
Scaling a Scaling a peak?peak?
162
Is using your framework correctly Is using your framework correctly like…like…
Running across a desert?Running across a desert?
163
Is using your framework correctly Is using your framework correctly like…like…
Falling into a Falling into a pit?pit?
164
Enable the Pit of Success Enable the Pit of Success byby
Avoiding the Avoiding the perilous perilous summit of summit of complexity… complexity…
And the desert And the desert of confusionof confusion
165
Make the Make the simple simple things things simple simple and the and the
hard hard things things
possiblepossible
166
Exceptions and Exceptions and the Pit of Successthe Pit of Success
““Cleaner, more elegant, and wrong.” Cleaner, more elegant, and wrong.” Raymond Chen Raymond Chen ((http://blogs.msdn.com/oldnewthing/)http://blogs.msdn.com/oldnewthing/)
167
When to throw an When to throw an Exception?Exception?
Exceptions rather than error codesExceptions rather than error codesRobust: failures get noticedRobust: failures get noticed
Your method is defined to do Your method is defined to do something…something…
If it succeeds in performing its purpose, If it succeeds in performing its purpose, returnreturn
If it fails to do what it was written to do, If it fails to do what it was written to do, throw an exceptionthrow an exception
Section 7, “Exceptions”Section 7, “Exceptions”
168
What Exception to What Exception to throw?throw?Use or subclass existing exceptions Use or subclass existing exceptions
if at all possibleif at all possible
Only create separate classes if you Only create separate classes if you think developers will handle the think developers will handle the exception differentlyexception 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 Section 7.1, “Exception ThrowingThrowing””
169
Throwing an ExceptionThrowing an Exception
Do not just map error codes onto a Do not just map error codes onto a single exception with an error code single exception with an error code property (property (e.g.e.g., the WMIException), the WMIException)
Use separate exception typesUse separate exception types
Error MessagesError MessagesConsider localization Consider localization
Use a complete sentence (end in a Use a complete sentence (end in a period)period)
Don’t expose privacy related information Don’t expose privacy related information (such as file paths)(such as file paths)
Section 7.1, “Exception Section 7.1, “Exception ThrowingThrowing””
170
PerformancePerformance
Minimize the number of exceptions you Minimize the number of exceptions you throw in your API’s success code-pathsthrow in your API’s success code-paths
You don’t pay for exceptions until you You don’t pay for exceptions until you throw in managed codethrow in managed code
Throwing exceptions degrades Throwing exceptions degrades performanceperformance
Perf counters tell you exactly how many Perf counters tell you exactly how many exceptions your application is throwingexceptions your application is throwing
Only an issue when using exceptions as a Only an issue when using exceptions as a means of control flowmeans of control flow
Consider providing a way to avoid an Consider providing a way to avoid an exception being thrownexception being thrown
Section 7.1, “Exception Section 7.1, “Exception ThrowingThrowing””
171
Performance (continued)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”);}
172
Managing Resources Managing Resources during Exception Handlingduring Exception Handling
You should use try..finally 10 times as You should use try..finally 10 times as often as try..catchoften as try..catch
Catches eat exceptions making it hard to Catches eat exceptions making it hard to debugdebug
Finally allows you to clean up, but let the Finally allows you to clean up, but let the exception continueexception continue
Section 7.2, “Choosing the Right Exception”Section 7.2, “Choosing the Right Exception”
173
Managing Resources Managing Resources during Exception during Exception HandlingHandling
You may catch exceptions to re-throw them You may catch exceptions to re-throw them with a clearer namewith a clearer name
Typical at an “API” boundaryTypical at an “API” boundary
Always nest the underlying exceptionAlways nest the underlying exceptionCatch-and-rethrow has many of the benefits Catch-and-rethrow has many of the benefits as try..finallyas try..finally
But, be aware of debugging issues with catch..throw But, be aware of debugging issues with catch..throw new() and catch..throw;new() and catch..throw;Generally, cleanup code should go in finalizerGenerally, cleanup code should go in finalizer
try {. . .}catch (DivisionByZeroException e) { // do clean up work throw new BetterException (message, e);}
174
Catching ExceptionsCatching Exceptions
Do not catch and eat exceptionsDo not catch and eat exceptionsExceptions should be handled only where there Exceptions should be handled only where there is enough context to do the right thingis enough context to do the right thing
That generally means exceptions should be That generally means exceptions should be caught as high in the application as possiblecaught as high in the application as possible
Mistake – catch the exception, report the Mistake – catch the exception, report the error and rethrow it. error and rethrow it.
Only catch where you can handle itOnly catch where you can handle it
Mistake – catch the exception, turn it into a Mistake – catch the exception, turn it into a bool pass/fail and return the bool bool pass/fail and return the bool
Section 7.2, “Choosing the Right Exception”Section 7.2, “Choosing the Right Exception”
175
Catching ExceptionsCatching Exceptions
Consider including a try/catch at the Consider including a try/catch at the top of a thread’s stack if the error can top of a thread’s stack if the error can be handled properlybe handled properly
Unhandled exceptions at the top of the Unhandled exceptions at the top of the main thread will terminate the appmain thread will terminate the app
In 2.0, unhandled exceptions at the top In 2.0, unhandled exceptions at the top of the stack on any thread will terminate of the stack on any thread will terminate the appthe app
But avoid catch blocks in finalizersBut avoid catch blocks in finalizers
Be aware: In many cases it is Be aware: In many cases it is “appropriate” to let the app terminate “appropriate” to let the app terminate
176
Catching ExceptionsCatching Exceptions
Be aware of (but ignore) exceptions Be aware of (but ignore) exceptions that don’t inherit from that don’t inherit from System.ExceptionSystem.Exception
Allowed in V1.0\V1.1, addressed in V2.0Allowed in V1.0\V1.1, addressed in V2.0
See UnhandledException event See UnhandledException event on AppDomainon AppDomain
178
How do I How do I read all read all the lines the lines from a from a file?file?
How do I How do I read all read all the lines the lines from a from a file?file?
179
VS7 EraVS7 Era “IO” seems like a
reasonable place to start
“IO” seems like a
reasonable place to start
180
Why did they make it
inaccessible
Backup, and try again…
Why did they make it
inaccessible
Backup, and try again…
183
Ok good, synchronous
and asynchronous operations.. What the heck is that?
Ok good, synchronous
and asynchronous operations.. What the heck is that?
189
The pit of success wayThe pit of success way
developers fall developers fall into doing into doing things the things the right wayright way
191
Ah, a string[] I know just what to do with that…
Ah, a string[] I know just what to do with that…
193
Enable the Pit of Success Enable the Pit of Success byby
And the And the desert of desert of confusionconfusion
Avoiding the Avoiding the perilous summit perilous summit of complexity…of complexity…
195
Addition Through Addition Through SubtractionSubtractionAdd value by subtracting Add value by subtracting
featuresfeatures
And the corollary:And the corollary:Remove value by adding featuresRemove value by adding features
More features != More ValueMore features != More Value
Section 2.2.2, “The Law of Low Barrier to Entry”Section 2.2.2, “The Law of Low Barrier to Entry”
196
Addition Through Addition Through Subtraction Subtraction By ExampleBy Example
CLR does not support multiple CLR does not support multiple inheritanceinheritance
No Set class in System.CollectionsNo Set class in System.Collections
No String.OpenFile() method No String.OpenFile() method
What can you cut from your API to What can you cut from your API to make it more valuable?make it more valuable?
197
Addition Through Addition Through SubtractionSubtraction
and and Danger of over-design Danger of over-design
198
API Design Theater IIAPI Design Theater II
The Main Character:The Main Character:Bright young developerBright young developer
The Setting:The Setting:Her first big projectHer first big project
The Setup:The Setup:Create a class that Create a class that models a carmodels a car
Actions required: Start Actions required: Start and Driveand Drive
199
Design Pass One: Meets Design Pass One: Meets Requirements Requirements
Pass one: meets requirementsPass one: meets requirements
204
V.Next: Worse YetV.Next: Worse Yet
Now we want to add Color and Model, Now we want to add Color and Model, and we know exactly howand we know exactly how
But it is much harder because the But it is much harder because the design is ½ done and mostly wrongdesign is ½ done and mostly wrong
205
The moralThe moral
Do as little as possible now (but Do as little as possible now (but no less) to ensure room for no less) to ensure room for extensibility in the futureextensibility in the future
206
Some Specifics Guidelines Some Specifics Guidelines on Designing for on Designing for Extensibility Extensibility
207
Abstract and Base classesAbstract and Base classes
Prefer broad, shallow hierarchiesPrefer broad, shallow hierarchiesLess than or equal to 2 additional levels – Less than or equal to 2 additional levels – Rough rule!Rough rule!
Contracts and responsibilities are difficult Contracts and responsibilities are difficult to maintain and explain in deep complex to maintain and explain in deep complex hierarchieshierarchies
Consider making base classes not Consider making base classes not constructible (i.e. use Abstract classes)constructible (i.e. use Abstract classes)
Make it clear what the class is forMake it clear what the class is for
Provide a protected constructor for subclasses Provide a protected constructor for subclasses to callto call
System.Exception should not have had a public System.Exception should not have had a public constructorconstructor
208
Virtual Method ExampleVirtual 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";
}
}
209
Virtual MethodsVirtual Methods
What is printed out?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());
210
Virtual MethodsVirtual Methods
They all output “Hello from Derived”. They all output “Hello from Derived”. Why?Why?
Method call virtualizes at runtimeMethod call virtualizes at runtime
The static type doesn’t matterThe static type doesn’t matter
This is the danger and power of This is the danger and power of virtual methodsvirtual methods
Danger: Owner of base classes cannot Danger: Owner of base classes cannot control what subclasses docontrol what subclasses do
Power: Base class does not have to Power: Base class does not have to change as new subclasses are createdchange as new subclasses are created
211
OverridingOverriding
Don’t change the Don’t change the semantics of semantics of membermember
Follow the contract Follow the contract defined on the base defined on the base classclass
All Virtual members should define a All Virtual members should define a contractcontract
Don’t require clients to have Don’t require clients to have knowledge of your overridingknowledge of your overriding
Should you call the base?Should you call the base?
212
Virtual and non-virtualVirtual and non-virtual
Use non-virtual members unless you Use non-virtual members unless you have specifically designed for have specifically designed for specializationspecialization
Have a concrete scenario in mindHave a concrete scenario in mind
Write the code!Write the code!
Think before you virtualize membersThink before you virtualize membersReferences to base types must work References to base types must work with derived types without knowing the with derived types without knowing the difference difference
Must continue to call in the same order Must continue to call in the same order and frequencyand frequency
Cannot increase or decrease range of Cannot increase or decrease range of inputs or outputinputs or output
See the Liskov Substitution PrincipleSee the Liskov Substitution Principle
213
Interfaces versus Base Interfaces versus Base ClassesClasses
Favor using base classes over Favor using base classes over interfacesinterfaces
Base classes version better in generalBase classes version better in generalAllows adding membersAllows adding members
Members can be added with aMembers can be added with a default implementationdefault implementation
Avoids incompatibilities common in ActiveXAvoids incompatibilities common in ActiveX
Interfaces are good for versioning Interfaces are good for versioning behavior (changing semantics)behavior (changing semantics)
214
Interface UsageInterface Usage
Interfaces are useful!Interfaces are useful!Solves the multiple root problemSolves the multiple root problem
The smaller, more focused the The smaller, more focused the interface the betterinterface the better
1-2 members are best1-2 members are bestBut interfaces can be defined in But interfaces can be defined in terms of other simpler interfacesterms of other simpler interfacesExamples: IComparable, IFormattableExamples: IComparable, IFormattable
public interface IComparable { int CompareTo(object obj);}
215
The great The great proof of proof of
madness is madness is the the
disproportion disproportion of one's of one's
designs to designs to one's means.one's means.
Napoleon BonaparteNapoleon Bonaparte
217
Exercise: Why Exceptions?Exercise: Why Exceptions?
Which of the following are Which of the following are good reasons to use error good reasons to use error codes rather than codes rather than exceptions?exceptions?
A)A) To avoid the base level To avoid the base level overhead exceptions add to overhead exceptions add to the systemthe system
B)B) I have always used error codesI have always used error codes
C)C) It is easier to ignore errors It is easier to ignore errors when dealing with error codeswhen dealing with error codes
D)D) Error codes are easier to Error codes are easier to localize than exceptionslocalize than exceptions
218
Exercise: Creating your Exercise: Creating your own Exceptionsown Exceptions
What is wrong with this What is wrong with this picture?picture?
PrinterOutOfRedTonerExceptionPrinterOutOfRedTonerExceptionPrinterOutOfBlackAndWhiteTonerExceptionPrinterOutOfBlackAndWhiteTonerExceptionPrinterOutOfBlueTonerExceptionPrinterOutOfBlueTonerExceptionPrinterOutOfGreenTonerExceptionPrinterOutOfGreenTonerExceptionPrinterOnFireExceptionPrinterOnFireExceptionPrinterOutOfPaperInTrayOneExceptionPrinterOutOfPaperInTrayOneExceptionPrinterOutOfPaperInTrayTwoExceptionPrinterOutOfPaperInTrayTwoExceptionPrinterOutOfPaperInTrayThreeExceptionPrinterOutOfPaperInTrayThreeExceptionPrinterOutOfPaperInTrayFourExceptionPrinterOutOfPaperInTrayFourExceptionPrinterOutOfPaperInTrayFiveExceptionPrinterOutOfPaperInTrayFiveException
219
Exercise: Handling Exercise: Handling ExceptionsExceptions
Where is the best place to Where is the best place to handle exceptions?handle exceptions?
1.1. Close to where it is thrownClose to where it is thrown
2.2. At the top level, where you At the top level, where you have the most context to have the most context to handlehandle
3.3. No where, exceptions are No where, exceptions are scaryscary
4.4. Early and oftenEarly and often
220
Exercise: Handling Exercise: Handling ExceptionsExceptions
What is the main exception What is the main exception handling problem with this handling problem with this code?code?
try { CallAMethod(); CallAnotherMethod();} catch (Exception ) {}CallAThirdMethod();
221
Exercise: Virtual MethodsExercise: Virtual Methods
Mark the following Mark the following statements true or falsestatements true or false
1.1. (True/False) Implementations (True/False) Implementations of virtual methods can be of virtual methods can be effectively replaced by effectively replaced by subclassessubclasses
2.2. (True/False) The Runtime (True/False) The Runtime insures that overridden insures that overridden methods call their base methods call their base implementations implementations
3.3. (True/False) Make as many (True/False) Make as many members virtual as possible to members virtual as possible to allow for easy extensibility and allow for easy extensibility and versioningversioning
222
SummarySummaryAllow developers to fall into Allow developers to fall into the pit of success using your the pit of success using your framework by avoiding framework by avoiding
The Perilous Summit of The Perilous Summit of complexitycomplexity
Have the right things get noticedHave the right things get noticed
Create the right levels of Create the right levels of abstractionabstraction
The Desert of ConfusionThe Desert of ConfusionAdd value by removing featuresAdd value by removing features
Danger of over designDanger of over design
Simple contracts are betterSimple contracts are better
223
API Design Experience:API Design Experience:Design your Own…Design your Own…
Krzysztof CwalinaKrzysztof CwalinaBrad AbramsBrad Abrams
224
Design E-Mail ComponentDesign E-Mail Component
RequirementsRequirementsSend simple text messagesSend simple text messages
Send messages with attachmentsSend messages with attachments
Simplicity is the main objectiveSimplicity is the main objective
225
Logistics Logistics
Work in pairsWork in pairs
Write the design on a piece of paper Write the design on a piece of paper or on your laptopor on your laptop
If you want feedbackIf you want feedbackSend the design to Send the design to kcwalina@microsoft.com or …kcwalina@microsoft.com or …
Write your email above the design and Write your email above the design and leave the paper on your chair.leave the paper on your chair.
You have 20 minutesYou have 20 minutes
226
Design ProcessDesign Process
Remember Design ProcessRemember Design ProcessSamplesSamples
API SpecificationAPI Specification
227
Example: Scenario Example: Scenario SamplesSamples
Appendix C, “Sample API Specification”Appendix C, “Sample API Specification”
228
Example: API SpecificationExample: API Specification
Appendix C, “Sample API Specification”Appendix C, “Sample API Specification”
229
Design Experience Design Experience SummarySummaryDesign an e-mail componentDesign an e-mail component
Send simple text messagesSend simple text messagesSend messages with attachmentsSend messages with attachmentsSimplicity is the main objectiveSimplicity is the main objective
Work in pairsWork in pairsWrite on a piece of paper or your Write on a piece of paper or your laptoplaptop
Scenario SamplesScenario SamplesAPI SpecificationAPI Specification
If you want feedbackIf you want feedbackemail us at kcwalina@microsoft.com email us at kcwalina@microsoft.com Write your email above the design and Write your email above the design and leave the paper on your chair.leave the paper on your chair.
231
Four Keys of Framework Four Keys of Framework DesignDesign
Tools for CommunicationTools for Communication
The Power of SamenessThe Power of Sameness
Framework Design Framework Design MattersMatters
The Pit of SuccessThe Pit of Success
232
The Power of Sameness
Influence of expectationsInfluence of expectationsNaming conventions and common suffixes\
prefixes
Habits win out over the special Habits win out over the special casescases
Common Exception pattern
With great power comes great With great power comes great responsibilityresponsibility
Method overloading
Meet developers where they areMeet developers where they areconstructors and properties pattern teaches us
to meet developers’ expectations
233
Framework Design Framework Design MattersMatters
Framework design does not happen Framework design does not happen magicallymagically
Best frameworks are designed Best frameworks are designed upfront by framework designersupfront by framework designers
There are several qualities of a well-There are several qualities of a well-designed framework that require designed framework that require focused framework design processfocused framework design process
234
Tools for CommunicationTools for Communication
Don’t force your consumers to be Don’t force your consumers to be archeologists digging for how to use archeologists digging for how to use your frameworkyour framework
Every element in your design has a Every element in your design has a specific meaning – Know them and specific meaning – Know them and use them correctlyuse them correctly
Avoid the common mistakesAvoid the common mistakesMake brand new mistakes Make brand new mistakes
235
The Pit Of SuccessThe Pit Of SuccessAllow developers to fall into Allow developers to fall into the pit of success using your the pit of success using your framework by avoiding framework by avoiding
The Perilous Summit of The Perilous Summit of complexitycomplexity
Have the right things get noticedHave the right things get noticed
Create the right levels of Create the right levels of abstractionabstraction
The Desert of ConfusionThe Desert of ConfusionAdd value by removing featuresAdd value by removing features
Danger of over designDanger of over design
Simple contracts are betterSimple contracts are better
236
Feedback…Feedback…
We want your feedback, please take We want your feedback, please take time to fill out the survey…time to fill out the survey…
And… please blog…And… please blog…
237
ResourcesResourcesFramework Design Guidelines:Conventions, Idioms, and Patterns for Reusable .NET LibrariesKrzysztof Cwalina, Brad Abrams
Signing now or at the bookstore Wed 1:15-1:45
http://www.gotdotnet.com/team/fxcop/http://www.gotdotnet.com/team/fxcop/
Brad AbramsBrad Abramsbrada@microsoft.combrada@microsoft.com
http://blogs.msdn.com/bradahttp://blogs.msdn.com/brada
Krzysztof Cwalinakcwalina@microsoft.com
http://blogs.msdn.com/kcwalina
Recommended