2.38k likes | 2.51k Views
The Art of Building a Reusable Class Library. Brad Abrams – BradA@Microsoft.com Krzysztof Cwalina - KCWalina@Microsoft.com Microsoft Corporation. Turn frustrated developers. … into happy developers. Goals. Understand that API design matters Recognize good API design
E N D
The Art of Building a Reusable Class Library Brad Abrams – BradA@Microsoft.comKrzysztof Cwalina - KCWalina@Microsoft.com Microsoft Corporation
Turn frustrated developers … into happy developers
Goals • Understand that API design matters • Recognize good API design • Lots of good and bad examples • Learn the API design process
Who is this precon for? 1. Developers building reusable library or component 2. Developer building apps to explicitly understand the rules of the .NET Framework and WinFX
Being complex is easy, being simple is hard 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
Project Cost Model Source: Gartner, May 2002: “The Cost and Risk of Application Development Decisions”Joseph Feiman, Tom Berg
Four Keys of Framework Design • Tools for Communication The Power of Sameness Framework Design Matters The Pit of Success
The Power of Sameness Brad Abrams
Read the manual?? When you pick up your rental car…. • Push the seat all the way back • Find an NPR station • Find the exit
Why you don’t read rental car manuals • You know how to drive your car • All cars work basically the same way • Your rental car is a car • Therefore, you can drive your rental car • That is… The Power of Sameness
New System Producers and Sameness Market Potential Standard System
Are things equally as obvious in your framework designs? Maybe you are missing…. The Power of Sameness
Naming Conventions PascalCasing – Each word starts with an uppercase letter camelCasing – First word lower case, others uppercase SCREAMING_CAPS – All upper case with underscores
“Blink” Quiz I class1MyClass; Blink : The Power of Thinking Without Thinking
“Blink” Quiz I • At-a-glance, first impressions… what does this likely do? • A: Compiler error • B: Class declaration • C: Variable declaration • D: Other class1MyClass; Change the casing to match the pattern, is it easier to tell what this is? Class1myClass;
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”
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;} }
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)
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
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
“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? The Power of Sameness
Section 4.1, “Naming Conventions” 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 7.3.4, “ArgumentNullException” Quick Quiz • What is wrong this this type? public class ArgumentNullException : ArgumentException { public ArgumentNullException () {} public ArgumentNullException (string paramName) {} public ArgumentNullException (string paramName, string message) {}}
Common Exception Usage throw new IOException(); • Developers expect all exceptions to work this way… • Make your exception meet expectations… throw new FormatException(); throw new ArgumentException(); throw new InvalidOperationException();
Section 7.4, “Designing Custom Exceptions” 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.3.4, “ArgumentNullException” 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) {}}
You are optimizing locally, you are making the right decision if developers only use your type, but if they use others as well…. API design theater… I see… why not? 90% of the time the message is not used, the param name is what is important It doesn’t apply in this case Why didn’t you follow the exception pattern? The Architect The Developer
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! throw new ArgumentNullException ("Name", "the value must pass an employee name");
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 stringToString(double value) {}
Bertrand Meyer Dangers of Method Overloading • Meyer: A single operation should do a single thing.. Why does this man dislike method overloading? Abrams: Good method overloading is a single thing – all overloads are semantically the same
Section 5.1.1, “Method Overloading” Method Overloading String.IndexOf(string value) {} String.IndexOf(char[] anyOf) {} string s = "brad abrams";s.IndexOf("ab"); // == 5s.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” Method Overloading • Use overloading only when the overloads do semantically the same thing • Incorrect overload: • Correct overload: String.IndexOf(string value) {} String.IndexOf(char[] anyOf) {} Convert.ToString(int value) {} Convert.ToString(double value) {}
Section 5.1.1, “Method Overloading” Method Overloading: Defaults • Use appropriate default values • Simple method assumes default state • More complex methods indicate changes from the default state • Use a zeroed state for the default value (such as: 0, 0.0, false, null, etc.) MethodInfo Type.GetMethod (string name); //ignoreCase = false MethodInfo Type.GetMethod (string name, boolean ignoreCase);
Section 5.3, “Constructor Design” 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”);
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; }
Exercise: Naming Conventions What are good reasons to violate naming conventions? • “I used to work in [C++, Java, COBOL]” • “Our previous version used SCREAMING_CAP” • “These are initials from someone’s name, they have to be all upper case”
Exercise: Code Review public interface Convertible {} Public class CodeReviewer : Attribute {} Public class InputInvalidError: Exception {}
Exercise: Code Review public static int MaxValue = 9999999; public void Withdraw () { Withdraw (MaxValue)} public void Withdraw (int amount) { …}
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
Framework Design Matters The role of a framework designer in the development process Krzysztof Cwalina Microsoft
The process of framework design is very different from prototyping and implementation
Similarly to implementations framework design must be … • Simple • Integrated • Consistent • Evolvable ... but the similarities are superficial