1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public...

63
1 public sealed class Environment public sealed class Environment { { private Environment() { } private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { { get { ... } get { ... } } } } } Best Practices In Framework Design Best Practices In Framework Design Jelle Druyts – Compuware Jelle Druyts – Compuware What's wrong with this code? What's wrong with this code?

Transcript of 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public...

Page 1: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

1

public sealed class Environmentpublic sealed class Environment{{ private Environment() { } private Environment() { }

public bool HasShutDownStartedpublic bool HasShutDownStarted {{ get { ... }get { ... } }}}}

Best Practices In Framework DesignBest Practices In Framework DesignJelle Druyts – CompuwareJelle Druyts – Compuware

What's wrong with this code?What's wrong with this code?

Page 2: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

Best Practices InBest Practices InFramework DesignFramework Design

The Art Of Building A Reusable Class LibraryThe Art Of Building A Reusable Class Library

Jelle DruytsJelle DruytsCompuware .NET ConsultantCompuware .NET Consultant

http://jelle.druyts.nethttp://jelle.druyts.net

Page 3: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

3

Your SpeakerYour Speaker

Jelle DruytsJelle Druyts

.NET ConsultantCompuware Professional Services

Framework Design & DevelopmentTechnical ArchitectMentor & TrainerTeam System Focus Group

Microsoft Consultancy ServicesFramework Design & DevelopmentWeFly247

CommunityBlog http://jelle.druyts.netMSDN Articles http://www.msdn.beVisual Studio User Group http://www.visug.be

Page 4: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

4

public sealed class Environmentpublic sealed class Environment{{ private Environment() { } private Environment() { }

public bool HasShutDownStartedpublic bool HasShutDownStarted {{ get { ... }get { ... } }}}}

Page 5: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

5

public sealed class Environmentpublic sealed class Environment{{ private Environment() { } private Environment() { }

public bool HasShutDownStartedpublic bool HasShutDownStarted {{ get { ... }get { ... } }}}}

It's an uncallable property!

Page 6: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

6

GoalsGoals

Is your APIUsable?Reusable?Versionable?

You willUnderstand that API design mattersRecognize good API designLearn the API design process

Page 7: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

7

Four Keys Of Framework DesignFour Keys Of Framework Design

The Power Of SamenessFramework Design MattersTools For CommunicationThe Pit Of Success

Page 8: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

8

The Power Of SamenessThe Power Of Sameness

Page 9: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

9Oh... down to lock!

The Power Of SamenessThe Power Of Sameness

Page 10: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

10

So that's what that "key" thingy is for...

The Power Of SamenessThe Power Of Sameness

Page 11: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

11

(Well, actually, some people could use a refresher on that signal lever...)

The Power Of SamenessThe Power Of Sameness

Page 12: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

12

General PrincipleGeneral Principle

All cars work basically the same wayYou don't read the Owner's Manual

Why should software be any different?You don't read Windows "Help and Support"

Framework usage should be obviousAcross different parts of your APIBetween different versions of your API

The Power Of SamenessThe Power Of Sameness

Page 13: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

13

Naming Conventions QuizNaming Conventions Quiz

Compile this in your head:

A: Compiler errorB: Class declaration C: Variable declarationD: Other

Now mentally compile this:

address Home;

Address home;

The Power Of SamenessThe Power Of Sameness

Page 14: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

14

Naming ConventionsNaming Conventions

All types and publicly exposed members: PascalCasingParameters: camelCasingDon't use Hungarian notation

public class CMemberDoc{ public int CompareTo(object objValue); public string lpstrName { get; }}

public class MemberDoc{ public int CompareTo(object value); public string Name { get; }}

The Power Of SamenessThe Power Of Sameness

Page 15: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

15

Prefixes & SuffixesPrefixes & Suffixes

Compile this:

Follow the patternInterfaces start with 'I'Exceptions end with ...Exception

Same for Attributes, EventArgs, Permissions

IFoo foo = new IFoo();throw new PrinterProblem();

public interface IFormattable {}public class NameAttribute : Attribute {}public class PrinterOnFireException: Exception {}

The Power Of SamenessThe Power Of Sameness

Page 16: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

16

Optimize GloballyOptimize Globally

Prefer global consistency over a local deviation

public class ArgumentNullException : ArgumentException{ public ArgumentNullException () {} public ArgumentNullException (string paramName) {} public ArgumentNullException (string paramName,

string message) {}}

throw new ArgumentNullException ("Must pass an employee name");

// System.ArgumentNullException: Value cannot be null.// Parameter name: Must pass an employee name

The Power Of SamenessThe Power Of Sameness

Page 17: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

17

The Power Of SamenessThe Power Of Sameness

Meet the developer's expectationsMake consumers of your API feel at home

Be consistentWith yourselfWith the .NET Framework

Page 18: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

18

Framework Design MattersFramework Design Matters

Page 19: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

19

SimpleSimple

Focus on top scenariosNamespace factoringNamingUse exceptions

A well-designed framework must be...A well-designed framework must be...

new EventLog().WriteEntry("Hello World");

// ArgumentException: Source property was not set// before writing to the event log

Page 20: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

20

Explicitly DesignedExplicitly Designed

Create an API specificationReview scenario samplesReview API design

A well-designed framework must be...A well-designed framework must be...

Page 21: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

21

Part Of An EcosystemPart Of An Ecosystem

IntelliSenseProperties WindowCLS ComplianceDebugger

A well-designed framework must be...A well-designed framework must be...

[DebuggerTypeProxy(typeof(HashtableDebugView))][DebuggerDisplay("Count = {Count}")]public class Hashtable { ... }

Page 22: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

22

IntegratedIntegrated

Use common abstractionsWatch out for common type name conflicts

A well-designed framework must be...A well-designed framework must be...

Page 23: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

23

Designed To EvolveDesigned To Evolve

Favor abstract classes over interfacesEasier for versioning (e.g. adding members)

Control extensibilityVirtual members are difficult to version

Test your abstractionsImplement interfacesConsume interfaces

A well-designed framework must be...A well-designed framework must be...

Page 24: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

24

ConsistentConsistent

Naming ConsistencyCommon patterns and idioms

AttributesCollectionsAsync PatternDispose Pattern...

A well-designed framework must be...A well-designed framework must be...

The Power Of SamenessThe Power Of Sameness

Page 25: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

25

Framework Design MattersFramework Design Matters

A well-designed framework must beSimpleExplicitly designedPart of an ecosystemIntegratedDesigned to evolveConsistent

...to be able to survive

Page 26: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

26

Tools For CommunicationTools For Communication

Page 27: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

27

Wouldn't it be great… Wouldn't it be great…

Luckily, there are Tools for CommunicatingLuckily, there are Tools for Communicating

Page 28: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

28

Why CommunicateWhy Communicate

Focus on developer, not yourselfYour developers can't read your mindDocumentation alone is not enough

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?

Tools For CommunicationTools For Communication

Page 29: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

29

You Leave ArtifactsYou Leave Artifacts

Framework Framework Design Artifacts:Design Artifacts:

NamespacesNamespaces

TypesTypes

MethodsMethods

PropertiesProperties

EventsEvents

FieldsFields

ConstructorsConstructors

......

Tools For CommunicationTools For Communication

Page 30: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

30

NamespacesNamespaces

Organizational principle to allow consumers to

Find relevant functionality quicklyExclude less relevant functionality

Not about implementation issues Security, identity, size, performance

Guideline: 1-to-1 link with assembly nameNot required though

Tools For CommunicationTools For Communication

Page 31: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

31

ClassesClasses

A conceptual model for a thing which can hold state, perform actions, ...Common API design problems

Grab bag types (lack of cohesion)System.Runtime.InteropServices.Marshal

Modeling overly abstractStreamReader vs. File

Tools For CommunicationTools For Communication

Page 32: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

32

ExceptionsExceptions

Encapsulation of error details used in a structured exception handling systemThrown when code fails to perform what it was written to doCommon API design problems

Using error codes rather than exceptionsDefining far too many exceptionsExposing privacy related information (e.g. file paths)

Tools For CommunicationTools For Communication

Page 33: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

33

EnumsEnums

Container for named constantsSingular for regular enums

BorderStyle.Fixed3D

Plural for combinable "Flags"AnchorStyles.Left | AnchorStyles.Right

Common API design problemsNot specifying the enum valuesUsing "magic" constants insteadAdding "Enum" to the name

Contrary to Exception, Attribute, EventArgs, ...

Tools For CommunicationTools For Communication

Page 34: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

34

ConstructorsConstructors

Facility to capture state for an instance at time of instantiation Common API design problem

Doing too much work in the constructorBe lazy, only capture state

public class XmlFile{ private string data; public XmlFile(string fileName) { this.data = DownloadData(fileName); }}

Tools For CommunicationTools For Communication

Page 35: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

35

MethodsMethods

Expose actions or operationsCommon API design problem

Using properties where methods should be used

Tools For CommunicationTools For Communication

Page 36: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

36

PropertiesProperties

Logical backing fields that encapsulate access to stateProperty getters

Should be simple and unlikely to throw exceptionsUse read only properties where appropriate

Property settersSetting one should not affect other propertiesShould be settable in any order

Common API design problemProperty vs. Method confusion

Tools For CommunicationTools For Communication

Page 37: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

37

Properties vs. MethodsProperties vs. Methods

Use a Property ifThe member is a logical attribute

Use a Method ifThe operation is a conversion, such as ToString()The getter has an observable side effectThe order of execution is importantThe method might not return immediatelyThe member returns an array

Tools For CommunicationTools For Communication

Page 38: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

38

FieldsFields

Represent variables associated with an object or classUseful for exposing implementation details, thereby constraining your ability to evolve the frameworkIn other words

Never expose fieldsAlways use properties

Tools For CommunicationTools For Communication

public class XmlFile{ private string data; public string Data { get { return data; } }}public class XmlFile

{ public string Data;}

Page 39: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

39

Events Events

Used to inform a subscriber that something happenedAlways follow the Event Pattern

Naming guidelines for Delegate, Event, EventArgs, the method that raises the event, ...

Common API design problemsUsing bad terminology: raised, not fired or triggeredNot using verbs, e.g.: Click, Paint, DrawItemNot using strongly typed EventArgs

Tools For CommunicationTools For Communication

Page 40: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

40

Generics (.NET 2.0)Generics (.NET 2.0)

Perform the same functionality for a variety of data types

Generic types are substituted at runtime

Use descriptive names prefixed with TUnless a single letter is self-explanatory

Common API design problemsMisusing generics by casting back to e.g. object or to an interface

Use constraints on generic type parameter

Tools For CommunicationTools For Communication

public class Comparer<T> where T : IComparable

public class Dictionary<TKey, TValue>

Page 41: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

41

Tools For CommunicationTools For Communication

Developers can't read your mindDocumentation alone is not enoughYou communicate by leaving artifacts

Different artifacts have different meanings

Follow the guidelines and patterns

Page 42: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

42

The Pit Of SuccessThe Pit Of Success

Page 43: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

43

The Pit Of SuccessThe Pit Of Success

In stark contrast to a summit, a peak, In stark contrast to a summit, a peak, or a journey across a desert to or a journey across a desert to find find

victory through many trialsvictory through many trials and and surprises, we want our customers surprises, we want our customers

to to simply fall into winning practicessimply fall into winning practices by using our platform and by using our platform and

frameworks. To the extent that frameworks. To the extent that if if we make it easy to get into trouble, we make it easy to get into trouble,

we failwe fail..- Rico Mariani- Rico Mariani

Page 44: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

44

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?

Page 45: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

45

Visual Studio 2003 EraVisual Studio 2003 Era

“IO” seems like a

reasonable place to start

“IO” seems like a

reasonable place to start

Page 46: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

46

Why did they make it

inaccessible

Backup, and try again…

Why did they make it

inaccessible

Backup, and try again…

Page 47: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

47

Open.. Looks like a good first step…

Open.. Looks like a good first step…

Page 48: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

48

Hmm… OK, what do I do with a FileStream

?

Hmm… OK, what do I do with a FileStream

?

Page 49: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

49

Ok good, synchronous

and asynchronous operations.. What the heck is that?

Ok good, synchronous

and asynchronous operations.. What the heck is that?

Page 50: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

50

I think I am in the wrong place..

I think I am in the wrong place..

Page 51: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

51

Back up, let’s try a different typeBack up, let’s try a different type

Page 52: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

52

Ahh, ReadLine(), this looks

more promising..

Ahh, ReadLine(), this looks

more promising..

Page 53: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

53

OK, how do you find the end?

OK, how do you find the end?

Page 54: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

54

Thanks goodness

there was a sample

Thanks goodness

there was a sample

Page 55: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

55

The Pit Of Success WayThe Pit Of Success Way

Developers fall into doing things the right way

Page 56: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

56

Just what I need…

Just what I need…

Visual Studio 2005 EraVisual Studio 2005 Era

Page 57: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

57

Ah, a string[] I know

just what to do with that…

Ah, a string[] I know

just what to do with that…

Page 58: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

58

How simple!How

simple!

Page 59: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

59

The Pit Of SuccessThe Pit Of Success

Make the simple things simple and the hard things possibleAvoid leading consumers down the wrong path

Guide them into just "doing the right thing"

Add value by subtracting featuresAdding features can remove value!

Don't over-designSimple contracts are usually better

Page 60: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

60

Key PointsKey Points

The Power Of SamenessMeet the developer's expectations

Framework Design MattersCarefully design an API so it can survive

Tools For CommunicationDifferent artifacts have different meanings

The Pit Of SuccessDevelopers fall into doing the right thing

Page 61: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

61

Framework Design Guidelines:Conventions, Idioms, and Patterns for Reusable .NET LibrariesBrad Abrams' Blog:

http://blogs.msdn.com/brada

Krzysztof Cwalina's Blog:http://blogs.msdn.com/kcwalina

FxCophttp://www.gotdotnet.com/team/fxcop/

Microsoft Visual Studio Team Systemhttp://msdn.microsoft.com/vstudio/teamsystem/

Compuware DevPartnerhttp://www.compuware.com/products/devpartner/

Page 62: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

62

Thank You!Thank You!

Thanks for your attention

I'll be happy to answer all your questions

Right after the sessionCompuware BoothCommunity Booth: Ask-The-Experts VISUG Booth

Page 63: 1 public sealed class Environment { private Environment() { } public bool HasShutDownStarted public bool HasShutDownStarted { get {... } get {... } } }

63