Principles to get acquainted with
When software development first came to life. People that wanted to start developing, obviously had no prior
knowledge. Thus, everyone started applying their own ways of how they thought software should be written. The
SOLID principles were introduced by Robert C. Martin (a.k.a Uncle Bob) in 2000. The intention of these principles is
to make software designs more understandable, easier to maintain and extend. These principles are essential for
every developer to know, because it will help them in writing better code an better understanding other code that
was written with these principles in mind.
- S - Single Responsibility
- O - Open/Closed
- L - Liskov Substitution
- I - Interface Segregation
- D - Dependency Inversion
Introduction to Patterns
One might not believe it, but design patterns do not find their origin in software architecture. Patterns were first
described in the 1970s by a real "Bricks and Stones" architect. A pattern is defined as a re-usable solution to a
common type of problem, without ever repeating the actual way the solution is implemented. This means that patterns
are an ideal learning tool and also ideal for communicating design ideas. Of course there are also anti-patterns,
things often used, but actually better avoided.
- What is a Pattern?
- The Gang of Four: Erich Gamma, Ralph Johnson, Richard Helm and John Vlissides.
- Different kinds of design patterns: creational, structural and behavioral patterns.
- Patterns everywhere: the difference between implementation, design and architecture patterns...
- When to apply patterns, and when not to.
- Some anti-patterns such as Loosy-Goosy.
When creating software, you feel yourself continuously creating new objects. Although the basic form of creating new
objects is not bad, it can result in design problems or added complexity to the design. Creational patterns will
help you deal with object creation that is suitable to the situation.
- Singleton - a.k.a. The Pluto Pattern and how the .NET runtime can help at implementing it
- LAB: Building a Singleton in .NET
- Builders - seperating the construction from the representation
- Factory Method - delegating/hiding the creation of objects to a factory
- Abstract Factory - abstracting the factory to create families of objects
- LAB: Implementing an Abstract Factory
Once your objects are created, they start interacting. When you're not careful, these interactions can quickly start
leading into code that is tightly coupled. Behavioral design patterns help identifying common communication patterns
between objects and realize these patterns. By correctly applying these patterns, you can increase flexibility in
carrying out the interaction between objects.
- Template Method - defer exact parts of an algorithm to inheriting classes, delegates, ...
- LAB: Building a Template Method for a board game
- Strategy - template method without the annoying inheritance
- LAB: Implementing a Builder as a Strategy
- Chain of Responsibility - strategy to go through a chain of strategies
- LAB: Using a Chain of Responsibility to implement a Builder
- State - defer state dependending logic to state classes, state machines, using the Stateless library
- LAB: Implementing a VCR with the State patterns
- Iterator - providing a generic way of navigating through collections, yield is your friend, asynchronously
iterating a collection
- Observer - notifying whoever is interested in what you have to say, event vs. delegate
- Mediator - providing two-way communication between objects unaware of one another, correcly implementing
- LAB: Avoiding the String-based programming anti-pattern
More loose coupling using dependency injection
When writing code, you have to make sure you are not introducing unnecessary dependencies on other objects.
Dependencies will just cost you on the long run since they are harder to maintain, not easily testable,
exchangeable, ... . If you need to depend on another, then depend on the interface. Interfaces describe the
dependency, but do not force it. Now, you don't want those dependencies to be filled hard coded and this is where
dependency injection (DI) can help you. Dependency injection can help you at runtime dynamically deciding which
implementations to plug into the dependencies.
- What is tight coupling and how to prevent it?
- Using Inversion of Control (IoC) containers.
- Constructor and Property injection.
- Microsoft.Extensions.DependencyInjection as an example.
- LAB: Dependency Injection in ASP.NET Core MVC
Created objects do not tend to stand on their own. No, they start encapsulating other objects trying to create
structure in, what otherwise would be a chaotic software environment. Structural patterns help at identifying and
setting up relationships between objects.
- Adapter - plugging in different objects into your code that do not fit
- LAB: Building INotifyPropertyChanged as a generic Adapter
- Decorator - altering the behavior of an object without the caller realising it
- LAB: Changing IComparable<T> with a Decorator
- Composite - tree structures are here to help you, working with Linq Expressions
- Facade - hiding the complexity of subsystems from the caller
- Flyweight - reduce memory consumption by preventing unnecessary creation of object
- Proxy - proxying requests made to the subject without changing the behavior
Building your own little programming language with some patterns - Fun!
Programming languages also use a bunch of patterns in their implementation. In this chapter you will build your own
little programming language, which is extensible by the way. While doing so you will discover and apply some very
which are perfectly useable outside of the scope of building programming languages!
- Interpreter: Build your own expressive language-grammar and execute it.
- How LINQ uses Interpreter - and how you can take advantage of it yourself.
- Builder: Hide how complex hierarchies of objects get built - and allow variations.
- XAML as the ultimate builder.
- Reflection: the ideal .NET way for implementing your own builder.
- How NOT to use reflection.
- LAB: Building your own calculator with Interpreter and Builder
- Visitor: When you need a lot of different operations on the same object structure.
- Building a pretty-printer using Visitor.
- Implementing Visitor the dynamic way.
- LAB: Implementing a Visitor to walk over a complex hierarchy of objects
Most developers make lousy graphic designers. That is why we see the emergence of patterns that allow developers to
focus on writing code to implement the behavior of the application, while allowing graphics designers to build
user interfaces. The main pattern is called Model-View-*Whatever*, with *Whatever* replaced depending on the
you are using. Understanding the MVW pattern is important as it is used to develop both windows and web
- Model-View-Controller: An ancient pattern back in fashion.
- ASP.NET MVC - an introduction.
- MVVM in WPF - MVC taking advantage of powerful databinding capabilities.
- Command: Encapsulate behavior in objects.
- Implementing commands using closures.
- LAB: Using MVVM in a WPF application
Have you ever heard of Reactive Programming? This is an important new development where you learn to
program using Observables. You will learn to apply this technique to solve some common, hard-to-solve problems
with classic Object-Oriented Programming, and we will also explore the Redux pattern.
- What are Observables?
- Using Reactive Extensions.
- Applying the Redux pattern so simplify complex applications.
- LAB: Implementing a search system with Observables
Unit testing in .NET
Every developer's dream: maintainable code that works. How do you keep your code maintainable?
And how do you ensure some small change does not break your code? Unit testing to the rescue!
- What every developer wants: Quality code that works; and keeps on working.
- Finding bugs: not just in code. - Or how NASA lost a 125.000.000$ Mars orbiter.
- What is unit testing? And what is a good unit test?
- Understanding the difference between a unit test and an integration test.
- Test Driven Development - Should you be doing it?
- Role-playing: Marge, Homer and Bart
- The Triple-A of unit testing - and what has cooking to do with this?
Unit testing with Visual Studio
In this chapter we will look at building unit tests with the built-in features of Visual Studio.
- MSUnit - Built into Visual Studio
- Building and running Unit Tests with MSUnit.
- Using the Test Explorer Window
- LAB: Test driven development of an improved collection
Design Patterns Applied: Developing your own reusable library.
When do you need patterns the most?! When you are building a framework yourself. Building a framework means handling
new features while keeping backward compatibility. This very hard task can be make easier with the proper use of
patterns. So in this last part of the training we will build a reusable library, and while doing so encounter some
problems and then solve these problems by applying the right pattern.
- Adding the GoF Command pattern to MVVM.
- Using interfaces for flexibility.
- Building Command Objects - extending WPF's ICommand interface.
- Adding Undo and Redo functionality to the command pattern.
- Using a CommandManager class.
- Challenge: retro-fitting our commands into MVVM without lots of changes.
- Implementing Undo-Redo using the Memento pattern.
- Choosing whether or not to add the Prototype pattern.
- Ideas on how to proceed with the command pattern.
- LAB: Implementing Undo/Redo logic as a reusable library