62
Game Programming Style & Design Principles Nick Prühs

Game Programming 04 - Style & Design Principles

Embed Size (px)

Citation preview

Page 1: Game Programming 04 - Style & Design Principles

Game ProgrammingStyle & Design Principles

Nick Prühs

Page 2: Game Programming 04 - Style & Design Principles

Objectives

• To get an idea of good code style and structure in general

• To understand the importance of consistent naming and code

conventions

• To learn how to property design types and members

2 / 61

Page 3: Game Programming 04 - Style & Design Principles

What is “good code”?

• Straight-forward and obvious

You’ll spend far more time reading code than writing.

You’ll spend much time reading code you didn’t write.

• Loose coupling

• Well tested

• Reused code

• Efficient (?)

3 / 61

Page 4: Game Programming 04 - Style & Design Principles

How to achieve “good code”?

Source: http://xkcd.com/844/ 4 / 61

Page 5: Game Programming 04 - Style & Design Principles

How to achieve “good code”?

• Pair programming

• Code Reviews

• Client-first programming, Test-driven development

• Refactoring

• Unit Testing

• Great tools

• Static code analysis

5 / 61

Page 6: Game Programming 04 - Style & Design Principles

Naming Conventions

• Greatly increase readability and usability

• Differ from language to language

We’ll take a look at C#, but many guidelines apply to other

languages as well.

6 / 61

Page 7: Game Programming 04 - Style & Design Principles

C# Capitalization

• PascalCasing

Namespaces

Types

Member Names

• camelCasing

Method Parameter Names

7 / 61

Page 8: Game Programming 04 - Style & Design Principles

Capitalization of Acronyms

• Both characters of two-character acronyms

Example: IO

• Only first character of three-character acronyms

Example: Xml, Html

• Never for camelCased identifiers (such as parameters)

8 / 61

Page 9: Game Programming 04 - Style & Design Principles

Word Choice

• Easily readable:

HorizontalAlignment instead of AlignmentHorizontal

• Favor readability over brevity:

CanScrollHorizontally instead of ScrollableX

• No underscores

• No Hungarian notation

• No abbreviations

Abbreviations don’t work well with IDEs.

• Semantic names

GetLength instead of GetInt

9 / 61

Page 10: Game Programming 04 - Style & Design Principles

Namespace Names

<Company>.<Product>.<Feature>.<SubNamespace>

• Plural names where appropriate

Example: System.Collections

• Don’t use the same name for namespace and type

• Don’t use common names such as Element, Component

10 / 61

Page 11: Game Programming 04 - Style & Design Principles

Type Names

• Nouns for classes and structs

Example: List, Vector

• Derived classes can end with name of base class

Example: ArgumentException

• Adjectives for interfaces

• Prefix interface names with ‘I’

Example: IComparable

• Use descriptive names for type-parameters

Dictionary<TKey, TValue> instead of Dictionary<K, V>

• Singular names for non-flags enums

Color instead of Colors

11 / 61

Page 12: Game Programming 04 - Style & Design Principles

Member Names

• Verbs for methods and events

Example: AddComponent, ComponentAdded

• Nouns or adjectives for fields

Example: Duration, Invulnerable

• Nouns for properties

• Plurals for collections

Items instead of ItemList

12 / 61

Page 13: Game Programming 04 - Style & Design Principles

Boolean Trap #1

• Be positive!

Enabled = true instead of Disabled = false

CaseSensitive = true instead of CaseInsensitive = false

13 / 61

Page 14: Game Programming 04 - Style & Design Principles

Tabs vs. Spaces

• Holy war between two fractions of programmers

• Some are for tabs…

Seperation of visual representation from data

Customizable

Faster

Specifically meant for indentation

• … while others are for spaces.

Always one column

Supported by IDEs anyway

14 / 61

Page 15: Game Programming 04 - Style & Design Principles

Tabs vs. Spaces

Most important rule:

Stay consistent.

… or it might even blow up your version control.

15 / 61

Page 16: Game Programming 04 - Style & Design Principles

Tabs vs. Spaces

„That said, only a moron would use tabs to format their code.”

- Jeff Atwood

16 / 61

Page 17: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Struct

Make a type a struct instead of a class if it…

• Logically represents a single value,

• Has a valid state if all data is set to zero,

• Has an instance size < 16 bytes,

• Is Immutable, and

• Won’t have to be boxed frequently

17 / 61

Page 18: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Struct

Make a type a struct instead of a class if it…

• Logically represents a single value,

• Has a valid state if all data is set to zero,

This is the case for array initialization, for example.

• Has an instance size < 16 bytes,

• Is Immutable, and

• Won’t have to be boxed frequently

18 / 61

Page 19: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Struct

Make a type a struct instead of a class if it…

• Logically represents a single value,

• Has a valid state if all data is set to zero,

• Has an instance size < 16 bytes,

Value type assignments copy all values

• Is Immutable, and

• Won’t have to be boxed frequently

19 / 61

Page 20: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Struct

Make a type a struct instead of a class if it…

• Logically represents a single value,

• Has a valid state if all data is set to zero,

• Has an instance size < 16 bytes,

• Is Immutable, and

Passing (and returning) by value implicitly creates a copy

Value types that can be changed will be confusing!

• Won’t have to be boxed frequently

20 / 61

Page 21: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Struct

Make a type a struct instead of a class if it…

• Logically represents a single value,

• Has a valid state if all data is set to zero,

• Has an instance size < 16 bytes,

• Is Immutable, and

• Won’t have to be boxed frequently

Happens when they’re cast to a interface

Allocated on heap and garbage collected, then!

21 / 61

Page 22: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Interface

• Use interfaces for polymorphic value type hierarchies

Example: IComparable, IConvertible

• If an interface does more than exactly one thing, that’s a warning

sign.

22 / 61

Page 23: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Interface

23 / 61

Page 24: Game Programming 04 - Style & Design Principles

Type Design – Class vs. Interface

• Favor (abstract) classes over interfaces

Adding members to an interface is a breaking change!

Seperating of contract from implementation with an interface is a

myth…

… whereas doing so with an abstract class is not.

24 / 61

Page 25: Game Programming 04 - Style & Design Principles

Type Design – Enums

• Favor enums over static constants

• Provide a zero value for simple enums (e.g. None)

• Don’t use enums for open sets

• Don’t use flag enums if some combinations can be invalid

25 / 61

Page 26: Game Programming 04 - Style & Design Principles

Member Design – Property vs. Method

Make a member a method instead of a property if it…

• Is significantly slower than a field access would be,

• Is a conversion operation (such as ToString),

• Returns a different result each time it is called,

• Has an observable side effect,

• Returns a copy of an internal state, or

• Returns an array

26 / 61

Page 27: Game Programming 04 - Style & Design Principles

Member Design – Properties

• Preserve previous value if a property setter throws an exception

• Don’t throw exceptions from property getters.

Use a method in that case.

27 / 61

Page 28: Game Programming 04 - Style & Design Principles

Gotcha!

Don‘t throw exceptions from

static constructors!

28 / 61

Page 29: Game Programming 04 - Style & Design Principles

Member Design – Methods

• Shorter overloads should simply call longer ones

public int IndexOf(string s)

public int IndexOf(string s, int startIndex)

public int IndexOf(string s, int startIndex, int count)

• Use descriptive parameter names

• Avoid varying names or inconsistent ordering

• Make only the longest overload virtual

• Allow null to be passed for optional parameters

Default arguments are not CLS-compliant!

29 / 61

Page 30: Game Programming 04 - Style & Design Principles

Member Design – Extensions

Use an extension method, if ...

• It adds functionality relevant to every implementation of an interface,

or

• An instance method would introduce unwanted dependencies

30 / 61

Page 31: Game Programming 04 - Style & Design Principles

Member Design – Operator Overloads

• Make sense for types that feel like primitive types

• Should be defined symmetrically

• Provide methods with friendly names, as well

Some languages don‘t support operator overloads.

31 / 61

Page 32: Game Programming 04 - Style & Design Principles

Member Design – Parameters

• Use the least derived required paramter type

• Validate all arguments

• params keyword is useful for arbitrary (but small) numbers of

parameters

Pay attention on parameter order

Be aware that null is a valid params array argument

32 / 61

Page 33: Game Programming 04 - Style & Design Principles

Boolean Trap #2

Guess what this code means?

widget.repaint(false);

33 / 61

Page 34: Game Programming 04 - Style & Design Principles

Boolean Trap #2

Guess what this code means?

widget.repaint(false);

• Function argument is called immediate

true means immediate painting

false means deferred painting

• Better use method overloads or enums!

34 / 61

Page 35: Game Programming 04 - Style & Design Principles

Boolean Trap #3

Guess what this code means?

var opacitySlider = new Slider(true);

35 / 61

Page 36: Game Programming 04 - Style & Design Principles

Boolean Trap #3

Guess what this code means?

var opacitySlider = new Slider(true);

• Function argument is called horizontal

true means horizontal slider

false means vertical slider

• Better use subclasses!

„Heck, who knows someday you’ll need a diagonal slider!”

36 / 61

Page 37: Game Programming 04 - Style & Design Principles

Boolean Trap #4

Guess what this code means?

stackView.updateHeight(false);

37 / 61

Page 38: Game Programming 04 - Style & Design Principles

Boolean Trap #4

Guess what this code means?

stackView.updateHeight(false);

• Immediate or not?

• Don‘t update height?

• Update width???

38 / 61

Page 39: Game Programming 04 - Style & Design Principles

Boolean Trap #5

The more, the merrier!

event.initKeyEvent("keypress", true, true,

null, null, false, false, false, false, 9,

0);

39 / 61

Page 40: Game Programming 04 - Style & Design Principles

Exceptions

• Help you deal with any unexpected or exceptional situations that

occur when a program is running

• Exceptions are types that all ultimately derive from

System.Exception.

• Generated by the common language runtime (CLR), by the .NET

Framework or any third-party libraries, or by application code.

40 / 61

Page 41: Game Programming 04 - Style & Design Principles

Benefits of Exceptions

• Integrate well with object-oriented languages

Does not require changing the method signature

• Can’t be ignored, whereas error codes can

• Exception objects contain detailed information about the error, such

as the state of the call stack and a text description of the error.

• Possibility of defining an Unhandled Exception Filter (UEF)

• Supported by debuggers

41 / 61

Page 42: Game Programming 04 - Style & Design Principles

Gotcha!

Don’t return error codes!

42 / 61

Page 43: Game Programming 04 - Style & Design Principles

Exception Design

• Exceptions provide consistent error reporting

No bool return value required

No HRESULT

No GetLastError

• Don’t return error codes.

If your error code is for the developer, add additional information

to the exception message instead.

If your error code is for the exception handler, add a new

exception type instead.

43 / 61

Page 44: Game Programming 04 - Style & Design Principles

Throwing Exceptions

• Throw the most specific exception that makes sense.

ArgumentException

ArgumentNullException

• Provide rich and meaningful error messages.

• Introduce a new exception type only if it should be handled

differently than existing exception types.

44 / 61

Page 45: Game Programming 04 - Style & Design Principles

Handling Exceptions

• Use a try block around the statements that might throw exceptions.

• Once an exception occurs in the try block, the flow of control jumps

to the first associated exception handler that is present anywhere in

the call stack.

• If no exception handler for a given exception is present, the program

stops executing with an error message.

45 / 61

Page 46: Game Programming 04 - Style & Design Principles

Handling Exceptions

Unhandled exception reported by Microsoft Visual Studio 2012

46 / 61

Page 47: Game Programming 04 - Style & Design Principles

Exception Best Practice

47 / 61

Page 48: Game Programming 04 - Style & Design Principles

Exception Best Practice

• Do not catch an exception unless you can handle it and leave the

application in a known state.

• Do not catch non-specific exceptions, such as System.Exception.

• Use a finally block to release resources, for example to close any

streams or files that were opened in the try block.

48 / 61

Page 49: Game Programming 04 - Style & Design Principles

Gotcha!

Never use empty catch blocks!

49 / 61

Page 50: Game Programming 04 - Style & Design Principles

Common Exceptions

• Thrown by your application or the framework

InvalidOperationException

ArgumentException

ArgumentNullException

ArgumentOutOfRangeException

• Thrown by the CLR

NullReferenceException

IndexOfOutRangeException

StackOverflowException

OutOfMemoryException

50 / 61

Page 51: Game Programming 04 - Style & Design Principles

Collection Design

• Inherit from Collection<T>, ReadOnlyCollection<T> or KeyedCollection<TKey, TItem>

• Implement IEnumerable<T> Allows foreach iteration of your collection.

• Implement ICollection<T> or IList<T> where it makes sense

• Implement an indexer where it makes sense

51 / 61

Page 52: Game Programming 04 - Style & Design Principles

Gotcha!

Don’t implement ICloneable!

52 / 61

Page 53: Game Programming 04 - Style & Design Principles

The interface ICloneable

• Contract doesn’t define whether cloning an object returns a deep or

shallow copy

• Define your own Clone method if required, without implementing the

interface

53 / 61

Page 54: Game Programming 04 - Style & Design Principles

Hint

Implement IEquatable<T>

on value types!

54 / 61

Page 55: Game Programming 04 - Style & Design Principles

The interface IEquatable

• Defines a method for determining equality of object instances

• Implement on value types to prevent boxing

• Override Object.Equals, == and != operators as well

55 / 61

Page 56: Game Programming 04 - Style & Design Principles

Hint

Implement IComparable<T>

where it makes sense!

56 / 61

Page 57: Game Programming 04 - Style & Design Principles

The interface IComparable

• Defines a type-specific comparison method for ordering or sorting

type instances.

• Override <, >, <= and >= operators as well

57 / 61

Page 58: Game Programming 04 - Style & Design Principles

Equals, GetHashCode & ToString

• If Object.Equals returns true for any two objects, GetHashCode must

return the same value for these objects.

Dictionaries, which are implemented as Hashtables in .NET, will

place two equal objects in different buckets otherwise, and

lookup might fail in that case.

• Override ToString wherever it makes sense.

Provides more useful debug output.

58 / 61

Page 59: Game Programming 04 - Style & Design Principles

Gotcha!

GetHashCode must return the exactly same value across the

lifetime of an object!

59 / 61

Page 60: Game Programming 04 - Style & Design Principles

References

• Stack Overflow. What does a good programmer's code look like? http://stackoverflow.com/questions/366588/what-does-a-good-programmers-code-look-like, April 2017.

• Cwalina, Abrams. Framework Design Guidelines. 2nd Edition. Addison-Wesley, 2011.

• Hidayat. hall of api shame: boolean trap. http://ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html,August 24, 2011.

• Atwood. Death to the Space Infidels! http://www.codinghorror.com/blog/2009/04/death-to-the-space-infidels.html, April 13, 2009.

• MSDN. System Namespace. https://msdn.microsoft.com/en-us/library/System(v=vs.110).aspx, April 2017.

60 / 61

Page 61: Game Programming 04 - Style & Design Principles

Thank you!

http://www.npruehs.de

https://github.com/npruehs

@npruehs

[email protected]

Page 62: Game Programming 04 - Style & Design Principles

5 Minute Review Session

• Name a few characteristics of good code!

• How can you achieve good code?

• Tabs or spaces?

• When should you use a struct instead of a class?

• When should you use a method instead of a property?

• Name the three common interfaces and base classes that can be used for collections in .NET!

• What is the main purpose of the interface IEquatable?

• What is the main purpose of the interface IComparable?

• How are Equals and GetHashCode related to each other?