Design patterns help developers and teams solve problems using proven approaches. In this talk, you'll learn how to solve a series of real world problems by applying patterns. Not only do patterns help individual developers solve particular problems, but they also enable teams to discuss design decisions using a richer, more descriptive language. By the end, you'll have some concrete tools you can apply, and hopefully the desire to master more patterns as you continue to improve!
10. Stages of Learning
Stage Zero - Ignorance
Stage One - Awakening
Stage Two - Overzealous
Stage Three – Mastery
http://flic.kr/p/6StgW5
11. Goal After This Presentation
At least Stage One – Awakening for a number of
useful patterns
Armed with resources to dive deeper into patterns of
interest
13. Overheard during a code
review…
“We have some tight coupling to the database here. We can
probably fix it if we apply some refactorings.
Maybe we can start by extracting an interface. Then we can
extract a method that contains the persistence code.
After that, we can extract that method into its own class that
implements the interface we created.
Then, we should be able to replace the local instantiation of the
class with a parameter we can pass in and assign to a field.”
14. Consider instead…
“We have some tight coupling to
the database here. Let’s use the
Repository Pattern to eliminate it.”
17. A Few Especially Helpful
Patterns
(Singleton)
Strategy
Repository
Proxy / Decorator
18. Singleton: Intent
Ensure a class has only one instance
Make the class itself responsible for keeping
track of its sole instance
“There can be only one”
21. Singleton Consequences
The default implementation is not thread-safe
Avoid in multi-threaded environments
Avoid in web server scenarios (e.g. ASP.NET)
Introduce tight coupling among collaborating
classes
Singletons are notoriously difficult to test
Commonly regarded as an anti-pattern
Some commercial tools
can be used to mock and
test Singletons
But why would you
intentionally write code
you can only test with
certain premium tools?
22. Singleton Consequences
Violates the Single Responsibility
Principle
Whatever the class does
AND
Lifetime Management
Using an IOC/DI Container it is
straightforward to avoid the coupling
and testability issues
23. Object Lifetime (in ASP.NET
Core)
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// you don’t need to implement singleton behavior in class!
services.AddSingleton<ISomeService>();
}
24. Singleton behavior is fine and
often desirable.
Implementing this behavior using the
Singleton Pattern on the class itself is
usually not ideal.
26. Strategy: Intent
Encapsulate a family of related algorithms
Let the algorithm vary and evolve independently from the class(es) that use it
Allow a class to maintain a single purpose
Single Responsibility Principle (SRP)
Also enables Open/Closed Principle (OCP)
Learn more about SRP and OCP in my Pluralsight course:
https://www.pluralsight.com/courses/principles-oo-design
28. Strategy : Common Usage
Dependency Inversion and Dependency Injection
Decouple class dependencies and responsibilities
Refactoring Steps
Create interfaces for each responsibility
Inject the implementation of the interface via the constructor
Move the implementation to a new class that implements the interface
29. Hidden Dependencies
Classes should declare their dependencies via their constructor
Follow the Explicit Dependencies Principle
Avoid hidden dependencies
Anything the class needs but which is not passed into constructor
Avoid making non-stateless static calls
Avoid directly instantiating classes (except those with no dependencies, like
strings)
Instead, move these calls to an interface, and call a local instance of the interface
30. “New is
Glue”
Be conscious of the
consequences of using
“new”
If you need loose coupling,
replace “new” with Strategy
Pattern
http://flic.kr/p/aN4Zv
“new” creates tight
coupling between classes
32. Data Access Evolution
Initially no separation of concerns
Data access logic baked directly
into UI
ASP.NET Data Source Controls
Classic ASP scripts
Data access logic in UI layer via
codebehind
ASP.NET Page_Load event
ASP.NET Button_Click event
User Interface
Database
Compile Time
Runtime
33. Data Access : Helper Classes
Calls to data made through a
utility
Example: Data Access
Application Block (SqlHelper)
Logic may still live in UI layer
Or a Business Logic Layer may
make calls to a Data Access
Layer which might then call the
helper
User Interface
Database
Compile Time
Runtime
Helper Class
34. What’s Missing? Abstraction!
No way to abstract away data
access
Tight coupling
Leads to Big Ball of Mud
system
Solution:
Depend on interfaces, not
concrete implementations
What should we call such
interfaces? Repositories!
User Interface
Database
Compile Time
Runtime
Core
IFooRepository
Infrastructure
SqlFooRepository
35. Repository
A Data Access Pattern
Introduced as part of Domain-Driven Design
Very popular outside of DDD
Separates persistence responsibility from
business and UI classes
36. Repository Benefits
Enables Single Responsibility Principle
Promotes Separation of Concerns
Reduces coupling to persistence details
Improves testability
38. Repository Approaches
Generic Implementation
IRepository<TEntity>
EfRepository<TEntity>
With specific implementations where necessary
ProductRepository (with special product-specific methods added)
39. Repository Approaches
Organize by Reads vs. Writes (CQRS)
IReadRepository<T>
IWriteRepository<T>
Organize per Bounded Context
Organize per Aggregate
Prevent ability to persist any entity outside of its aggregate
41. What should List methods
return?
IEnumerable<T>
IQueryable<T>
What about deferred execution?
How (and where) to define custom queries?
What about lazy loading?
46. (1)
Create/extend an interface to represent
the data access you need
(2)
Copy the
implementation from
your class into a new
class implementing
this interface.
(3)
Inject the interface using the
Strategy Pattern. Use the local field
of this interface type in place of
previous implementation code.
47. Where do Repositories
Live?
Place interfaces in Core
Core includes Model classes and most business logic
Core has no dependencies (ideally)
Place implementation in Infrastructure
Infrastructure references Core
UI layer (app entry point) references Core
Accesses Infrastructure at runtime
Responsible for creating object graph, either manually or via
an IOC Container
49. Proxy
A class that controls access to another
Implemented via subclass or via
delegation using a common interface
Frequent use cases:
Remote Proxy for web services / network calls
Lazy loading implementations
Security / access control
52. Adding Caching to a
Repository
Caching is frequently added to query
methods in repositories
Caching logic is a separate concern and
should live in a separate class from the
main data access logic
53. Proxy or Decorator?
Proxy pattern provides a
straightforward means to control
access to the “real” data, versus
the cache.
Decorator pattern adds additional
functionality or behavior: caching.
Contact me if you’d like a 30-day pass to Pluralsight. Please consider some of my courses on design patterns, architecture, and domain-driven design.
General, reusable solutions to common problems
Not a complete, finished solution
A template, recipe, or approach to solving certain problems
Each has a specific name, so we can discuss common elements of design using a common vocabulary
Published in 1977, this book is cited as the inspiration for the classic, Design Patterns book, by the Gang of Four.
Published in 1994, this book is still in its first edition after almost 25 years. Though you can find much of the concepts online, the book is a great reference and if nothing else look great on your bookshelf to impress visitors.
Here are some images of programmer bookshelves I found with a quick google search…
Learning anything – a musical chord, a martial arts technique, etc.
Zero: You used a what? Never heard of it.
Awakening: Wow, I just learned how XYZ pattern can improve my design. I’m not really sure where it would work in my code, but I’m definitely looking.
Overzealous: I totally “get” the XYZ pattern; I’m adding it everywhere I can shoehorn it into my code. My design’s gonna be better now, for sure!
Mastery: In response to some specific design pain points, the XYZ pattern was a logical next step and was achieved through a simple refactoring.
Design pattern names provide placeholders or complex abstractions and sets of refactorings.
This is where a lot of people work. Don’t be these guys. When you have a lot of wood to cut, it pays off to periodically sharpen the saw. Sharpening the saw is one of the seven habits of highly effective people. Take time to improve your skills, and practice, and in the long run you will be more effective.
It’s possible for the new Singleton(); line to be called more than once.
Jon Skeet lays out several different ways to implement the Singleton pattern in C#, with different performance and thread safety considerations.
Add Kragle slide next
In my own career as a developer, I’ve seen an evolution in how most data access is performed. I started with classic ASP and soon after, the first version of ASP.NET. In both cases, there was typically little separation of concerns between UI, business rules, and data access. This tended to result in a lot of duplicate concepts and code, as well as direct dependence on a database.
To address the duplication, helper classes were often created to take repetitive tasks and centralize them. However, in this case the runtime program flow still mirrored the compile time dependency tree, in both cases targeting a database. This made testing such applications difficult.
The problem with these approaches is that there is no abstraction layer between the application and its infrastructure – in this case the database.
Consider grabbing repository image from DDD slide here
Split into two slides
Consider grabbing repository image from DDD slide here
Split into two slides
Note – this cannot easily be tested without an actual database instance in place.
Add image showing Onion Architecture and/or a simple solution with Core, Infrastructure, and Web.
Note that the structure of the Proxy is very similar to the Strategy pattern, which we already saw (click). The key difference between the two is in the intent. Note that this is just one Proxy implementation – it can also be achieved with a proxy class that inherits from the subject class, rather than sharing a common interface implementation.
TODO: Show an example of adding caching logic to a repository without any separation of concerns.
Consider starting with an MVC method that does direct data access without any repository, uses caching, etc, and lament its lack of testability. Perhaps a Music Store method, maybe with some modification.
Don’t try to apply every pattern you know up front.
Update PS links to use referral links
Maybe look for an image representing military orders being received
Ask about Amazon and what actually happens when you place an order there, compared to with most other online stores.
The background for this slide is the FirstOrDefault image I liked for the Null Object pattern
Some polymorphic code
Change this to something that isn’t displayed in the UI layer, such as a function that must be called or a number to be summed.
Apply patterns via refactoring,
Not Big Design Up Front
Show the MvcMusicStore application
Hg clone https://hg.codeplex.com/forks/ssmith/mvcmusicstorerepositorypattern
Talk about the CacheDependencyBug in AdSignia and how it was introduced by moving a hard-coded instantiation to a parameter, and then fixed by replacing the parameter with a Factory (lambda).
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Update with imagery and review of patterns and when to use them. Fewer words.
Don’t be too busy to improve
Avoid adding coupling to your system with Singleton
Decouple specific implementation from use with Strategy
Avoid hidden dependencies; remember New is Glue!
Decouple your database with Repository
Decouple caching, lazy loading, and other access concerns with Proxy
Decouple execution of other actions with Commands
Decouple construction with Factory – remember Lazy<T> and lambda as factory shortcuts
Cut down on prolific null checks with the Null Object Pattern
Don’t try to use every pattern up front – practice Pain Driven Development
Decouple construction with Factory
Remember Lazy<T> and lambda as factory shortcuts
Remember IOC containers are factories on steroids
Decouple construction with Factory
Remember Lazy<T> and lambda as factory shortcuts
Remember IOC containers are factories on steroids
Don’t try to apply every pattern you know up front.