2. WHO AM I?
• Founder of Cambridge Software Craftsmanship Community
• Developer and Technical Lead at Red Gate Software
• Twitter: @alastairs
• http://www.codebork.com/
• alastair@alastairsmith.me.uk
4. 2. FAVOUR COMPOSITION OVER
INHERITANCE
• Loose coupling
• Strategies, Adapters, Composites and more are your friends
5. 3. THERE IS A CONTINUUM OF
ABSTRACTION
Instance
Class
Abstract
Class
Interface
6. 4. USE ABSTRACT CLASSES
• Not every abstract concept should be an interface
• Model all your abstractions at the right level
7. 5. DON’T EXPOSE STATE ON
INTERFACES
• Interfaces are contracts of behaviour
• State is data
8. 6. PROGRAM TO THE INTERFACE,
NOT THE IMPLEMENTATION
• Loose coupling
• Assume nothing about the implementation of the interface
9. 7. INHERITANCE IS FOR
SPECIALISATION
• Use composition for extension
• Specialisation is like evolution
10. 8. KNOW YOUR PATTERNS
• Design Patterns are our bricks and mortar
• Use GoF as a reference only
11. 9. AT THE BOUNDARIES OF AN
APPLICATION, OO BREAKS DOWN
• Use value objects to convey state out of the core of the application
• Do not reuse abstractions in different modules
• Use hexagonal architecture to separate concerns
12. 10. MAKE YOUR OBJECTS AND
VALUES IMMUTABLE
• Easier comparisons when testing
• Both have a concept of equality
• Thread safety in multi-threaded systems
• Less complex implementation
Applies to all OO languages, but some refer to C# language features
Alan Kay himself has said that, if he were designing Smalltalk again, he would call it Message-Oriented Programming rather than Object-Oriented Programming, because of the confusion rife over what he and the other designers of Smalltalk meant.The magic in object-orientation lies in the collaboration between objects, their behaviour, the messages they send to one another; not their state. Objects are often designed in terms of their properties rather than their behaviours: e.g. a Car has four wheels which allow it to travel from A to B, rather than the behaviours of adding a new passenger and travelling to a destination. This is why TDD (and, more specifically, Outside-In TDD as described in GOOS) works so well: it places the focus on the behaviour of the system under test, and not its state.
GoFDesign Patterns. Composition provides more flexible designs, because your components are more loosely-coupled: you can re-arrange them into whatever shape you need, much like LEGO. This works because of message-oriented programming: passing messages between objects via method calls leads to much more composable designs
Think about the words used for these different concepts, and their dictionary definitions:Class: “a number of persons or things regarded as forming a group by reason of common attributes, characteristics, qualities, or traits”Abstract: “thought of apart from concrete realities, specific objects, or actual instances; expressing a quality or characteristic apart from any specific object or instance”Interface: “a common boundary or interconnection between systems, equipment, concepts, or human beings.”A class is an abstraction! The only concrete thing you have is an instance of a class.
But, ensure they are well-defined:Common stateCommon behaviours – implementing multiple interfacesCohesiveIf you’re dealing with Animals, you almost certainly won’t need an abstraction for Dog, much less a springer spaniel; a dog is instead an instance of an animal. (RG Note: In SOC, there 8.3x as many interfaces as abstract classes.)
This is a leaky abstraction: by exposing an element of state it makes assumptions about the implementation of the interface. The only way to extend data (i.e., adding new data items) is through inheritance. Putting properties on interfaces encourages inheritance of interfaces, which breaks the Interface Segregation Principle, and makes your abstraction even more leaky.Again, think about the word “interface” in terms of its dictionary definition. A Graphical User Interface or Command-Line Interface has behaviour, not state: push button, enter text, run command, display results. You interact with interfaces, via their behaviours, and through those behaviours observe something about its state.
GoFDesign Patterns.Helps ensure loosely-coupled, composable code that is easy to test, because you’re interacting with the behaviour of collaborators, you’re not relying on their current state too.
“Inheritance is a tremendously powerful tool for sharing implementation details and specializing behaviour. But the fact that you only get "one shot" at inheritance in a single-inheritance world means that you’ve got to take that shot carefully and make sure you're using that power to its best ability.” – Eric LippertDo not add or modify behaviour through inheritance, use composition instead.Evolution: structural adaptation to a particular function for use in a particular environment
Know what problems they solve, where they can be applied appropriately, etc. Knowing the appropriate application of a pattern is more important than knowing the pattern itself. Know how to spot a poorly-implemented pattern.GoF is great as a reference book, but is perhaps too dry to learn the patterns from. Try other texts, such as Head First Design Patterns or Holub on Patterns to learn the patterns in context.
Use mapping techniques (e.g., AutoMapper) to convert between the models at the boundaries and the rich domain objects powering the applicationHexagonal architecture == ports and adapters from GOOS. See also Ian Cooper’s talk “TDD: Where did it all go wrong?”