Skip to content

Commit

Permalink
Design patterns 2 - Separate into new rules
Browse files Browse the repository at this point in the history
  • Loading branch information
bradystroud committed Apr 18, 2024
1 parent bc85d50 commit 45aa4ed
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ index:
- do-you-know-the-common-design-principles-part-1
- do-you-know-the-common-design-principles-part-2-example
- common-design-patterns
- do-you-know-the-common-design-patterns-part-2-example
- dependency-injection
- code-against-interfaces
- do-you-look-for-grasp-patterns
- code-can-you-read-code-down-across
- do-you-start-reading-code
Expand Down
47 changes: 47 additions & 0 deletions rules/code-against-interfaces/rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
type: rule
archivedreason:
title: Do you code against interfaces?
guid: d1088a85-0785-42ce-94f6-abb6290dfd61
uri: code-against-interfaces
created: 2024-04-18T02:29:38.0000000Z
authors:
- title: Adam Cogan
url: https://ssw.com.au/people/adam-cogan
- title: Damian Brady
url: https://ssw.com.au/people/damian-brady
- title: Adam Stephensen
url: https://ssw.com.au/people/adam-stephensen
- title: Eric Phan
url: https://ssw.com.au/people/eric-phan
- title: Dhruv Mathur
url: https://ssw.com.au/people/dhruv-mathur
related:
- do-you-name-your-dependencies-to-avoid-problems-with-minification
- common-design-patterns
- dependency-injection
redirects: []

---

Appropriate use of design patterns can ensure your code is maintainable and easy to read.

<!--endintro-->

### Code against Interfaces

Always code against an interface rather than a concrete implementation. Use dependency injection to control which implementation the interface uses. By doing this you create a contract for that service which the rest of the codebase has to adhere to.

By creating an interface for each service and programming against the interface, you can easily swap out the implementation of the service without changing the code that uses the service.

It is important to also control the scope of the injection. For example, in ASP.NET 8 application you have the option to register the concrete implementation in the DI container either as a singleton, scoped, or transient service. Each of them will have a different lifetime in the application and should be set as per the requirement.

![](Code against interfaces - bad.png)
**❌ Figure: Bad Example - Referencing the concrete EF context**

This is bad code because now the controller is directly dependent on the implementation of the EF context. This also increase the effort for unit testing.

![](Code against interfaces - good.png)
**✅ Figure: Good Example - Programming against the interface**

This is good because now you can test the controller and the services independently. Also the controller only talks to the service through the functionality exposed by the interface, enforcing encapsulation.
26 changes: 20 additions & 6 deletions rules/common-design-patterns/rule.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ authors:
url: https://ssw.com.au/people/damian-brady
- title: Dhruv Mathur
url: https://ssw.com.au/people/dhruv-mathur
related: []
related:
- dependency-injection
- code-against-interfaces
redirects:
- do-you-know-the-common-design-patterns-(part-1)
- do-you-know-the-common-design-patterns-part-1
Expand All @@ -33,7 +35,7 @@ Design patterns are useful for ensuring [common design principles](/do-you-know-
* **IOC** | [Inversion of Control](http&#58;//en.wikipedia.org/wiki/Inversion_of_control)
In this pattern, control over the instantiation and management of objects is inverted, meaning that these responsibilities are handed over to an external framework like a DI container instead of being managed by the classes themselves. This separation enhances flexibility and decouples all the classes in the system.

* **DI** | [Dependency Injection](http&#58;//en.wikipedia.org/wiki/Dependency_injection)
* **DI** | [Dependency Injection](/dependency-injection)
DI is a form of IoC where dependencies are provided to objects rather than created by them, one instance of the dependency can be used by many. This pattern also reduces dependency coupling between components since the instantiation is handled externally, making the system easier to manage and test.

* **Factory** | [Factory Pattern](http&#58;//en.wikipedia.org/wiki/Factory_pattern)
Expand All @@ -48,18 +50,29 @@ A repository abstracts the data layer, providing a collection-like interface for
* **Unit of Work** | [Unit of Work Pattern](http&#58;//msdn.microsoft.com/en-us/magazine/dd882510.aspx)
It is a way to keep track of everything you do during a transaction that can affect the database. When it's time to commit the transaction, it figures out everything that needs to be done to alter the database as a result of your work. This pattern is crucial for maintaining the consistency of data within the boundaries of a transaction.

* **Mediator** | [Mediator Pattern](http://en.wikipedia.org/wiki/Mediator_pattern)
The mediator pattern uses a central object to handle communication between other objects in a system, promoting separation of concerns. This means each object doesn’t need to know about the details of how others operate, making the system easier to maintain and extend.

* **MVC** | [Model View Controller](http&#58;//en.wikipedia.org/wiki/Model%e2%80%93view%e2%80%93controller)
It is an architectural pattern that separates an application into three main logical components: the model, the view, and the controller. Each of these components handles different aspects of the application's data, user interface, and control logic, respectively. This separation helps manage complexity in large applications.

* **MVP** | [Model View Presenter](http&#58;//en.wikipedia.org/wiki/Model_View_Presenter)
This pattern is a simpler version of MVC designed for modern applications where the user interface (the view) just displays information and responds to user inputs. In MVP, a middle-man called the presenter handles all the decision-making behind the scenes. It takes care of updating the view and reacting to user actions, making the view very simple and straightforward. This setup makes it easier to test the user interface because the view itself doesn't contain any complex logic—it just shows what the presenter tells it to.

* **Mediator** | [Mediator Pattern](http://en.wikipedia.org/wiki/Mediator_pattern)
The mediator pattern uses a central object to handle communication between other objects in a system, promoting separation of concerns. This means each object doesn’t need to know about the details of how others operate, making the system easier to maintain and extend.

### Other design patterns

* **Decorator** | [Decorator Pattern](http://en.wikipedia.org/wiki/Decorator_pattern)
The decorator pattern allows behavior to be added to individual objects, either statically or dynamically, without affecting the behavior of other objects from the same class. This pattern is useful for adding new features to objects without changing their structure, making it easier to extend the functionality of an object.

* **Command** | [Command Pattern](http://en.wikipedia.org/wiki/Command_pattern)
The command pattern encapsulates a request as an object, allowing you to parameterize clients with queues, requests, and operations. This pattern helps in decoupling the sender and receiver of a request, making it easier to implement undo and redo functionalities.

* **Strategy** | [Strategy Pattern](http://en.wikipedia.org/wiki/Strategy_pattern)
The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. This pattern allows the algorithm to vary independently from the client that uses it, making it easier to switch between different algorithms at runtime.

* **Specification** | [Specification Pattern](http://en.wikipedia.org/wiki/Specification_pattern)
The specification pattern is used to define business rules that can be combined to form complex rules. This pattern helps in separating the logic for checking business rules from the domain model, making it easier to maintain and reuse the rules.

* **Prototype** | [Prototype Pattern](http://en.wikipedia.org/wiki/Prototype_pattern)
The prototype pattern is used to create new objects by copying a model instance. This method helps avoid the complexity of using subclasses and reduces the performance cost associated with creating new objects using the standard method (e.g., with the 'new' keyword), especially when it's too costly for the application.

Expand All @@ -81,5 +94,6 @@ The observer pattern defines a one-to-many dependency between objects so that wh
* **State** | [State Pattern](http://en.wikipedia.org/wiki/State_pattern)
The state pattern allows an object to change its behavior when its internal state changes. It encapsulates the behavior of an object into separate classes, making it easier to add new states and transitions without changing the object's code.


By leveraging these design patterns, developers can solve complex problems more efficiently and ensure that their applications are robust, scalable, and easy to maintain. It is assumed knowledge that you know these design patterns. If you don't, read about them on the sites above or watch the [PluralSight videos on Design Patterns.](https://www.pluralsight.com/paths/design-patterns-in-c)

It is important to know when the use of a pattern is appropriate. Patterns can be useful, but they can also be harmful if used incorrectly.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
type: rule
archivedreason:
title: Do you know the common Design Patterns? (Part 2 - Example)
title: Do you use the Dependency Injection design pattern?
guid: 076632c1-c3b3-4a59-8fa6-55d6fb9ceeae
uri: do-you-know-the-common-design-patterns-part-2-example
uri: dependency-injection
created: 2012-03-20T02:29:38.0000000Z
authors:
- title: Adam Cogan
Expand All @@ -18,6 +18,7 @@ authors:
url: https://ssw.com.au/people/dhruv-mathur
related:
- do-you-name-your-dependencies-to-avoid-problems-with-minification
- common-design-patterns
redirects:
- do-you-know-the-common-design-patterns-(part-2-example)

Expand Down Expand Up @@ -92,24 +93,4 @@ public class HomeController
}
```

**✅ Figure: Good example - code showing using dependency injection. No static dependencies.**

### Code against Interfaces

Always code against an interface rather than a concrete implementation. Use dependency injection to control which implementation the interface uses. By doing this you create a contract for that service which the rest of the codebase has to adhere to.

By creating an interface for each service and programming against the interface, you can easily swap out the implementation of the service without changing the code that uses the service.

It is important to also control the scope of the injection. For example, in ASP.NET 8 application you have the option to register the concrete implementation in the DI container either as a singleton, scoped, or transient service. Each of them will have a different lifetime in the application and should be set as per the requirement.

![](Code against interfaces - bad.png)
**❌ Figure: Bad Example - Referencing the concrete EF context**

This is bad code because now the controller is directly dependent on the implementation of the EF context. This also increase the effort for unit testing.

![](Code against interfaces - good.png)
**✅ Figure: Good Example - Programming against the interface**

This is good because now you can test the controller and the services independently. Also the controller only talks to the service through the functionality exposed by the interface, enforcing encapsulation.

It is important to know when the use of a pattern is appropriate. Patterns can be useful, but they can also be harmful if used incorrectly.
**✅ Figure: Good example - code showing using dependency injection. No static dependencies.**

0 comments on commit 45aa4ed

Please sign in to comment.