Applying Pain Driven Development to Patterns
This week we talk about specific ways you can apply my strategy of Pain Driven Development to the use of design patterns. This is an excerpt from my Design Pattern Mastery presentation that goes into more detail on design patterns.
Sponsor - DevIQ
Thanks to DevIQ for sponsoring this episode! Check out their list of available courses and how-to videos.
Show Notes / Transcript
I talked about Pain Driven Development, or PDD, in episode 10 - check out that episode first if you're not familiar with the practice. I've recently been focusing a bit on some design patterns. An easy trap to fall into with design patterns is trying to apply them too frequently or too soon. PDD suggests waiting to experience pain while trying to work with the application's current design before you attempt to refactor to improve its design by applying a design pattern. In this tip, I'll walk through a few common steps where applying a specific pattern may be helpful.
To begin, let's assume we have a very simple web application. Let's say it's using MVC, and there's a controller that needs to be used to return some data fetched from a database. It could be an API endpoint or a view-based page - the UI format isn't important in this case. The absolute simplest thing you can do in this situation is hard code your data access code into your controller. So, assuming you're using ASP.NET Core and Entity Framework Core, you could instantiate an DbContext in the controller and use that to fetch the data. This works and meets the immediate requirement, so you ship this version.
A little bit later, your application has grown more complex. You have some filters that also use data, along with other services. You start to notice occasional bugs from EF and realize that you've introduced a bug. By instantiating a new DbContext in each controller, but occasionally passing around entities between parts of the application, EF gets in a state where entities are tracked by one instance but you're trying to operate on them with another instance of DbContext. You need to use a single EF Core DbContext per web request, which is to say it should have a "Scoped" lifetime. Fortunately, ASP.NET Core makes it very easy to achieve this by configuring your DbContext inside of ConfigureServices. In fact, if you don't read the docs, you probably don't even know what lifetime EF Core is using, because it's hidden within an extension method. In any case, once you configure DbContext in ConfigureServices, you need a way to get it into your Controller(s). To do this requires the Strategy pattern, covered in episode 19. If you're familiar with dependency injection, you've used the Strategy pattern. Add a constructor to your Controller, pass in the DbContext, and set a private local field with the value passed into the constructor. Do this anywhere you're otherwise newing up the DbContext. Remind yourself 'new is glue'. You just fixed an issue with too tight of coupling to the instantiation process by using the service collection built into ASP.NET Core, an IOC container, essentially a factory on steroids. Your EF Core lifetime bug is now fixed, so you ship the code.
Some more time passes, the application has grown, and now there are a bunch of controllers and other places that all have DbContext injected into them. You've noticed some duplication in how code works with the DbContext. You've also found that it's tough to unit test your classes that have a real DbContext injected, except by configuring EF Core to use its In Memory data store. This works, but you'd prefer it if your unit tests truly had no dependencies so you could just test behavior, not low-level data access libraries. You decide that you can solve both of these problems by introducing the Repository pattern, which is just a fancy name for an abstraction used to encapsulate the low level details of your data access. You create a few such interfaces, implement them with DbContext, and make sure your Controllers and other classes that were directly using DbContext now have an interface injected instead. Along the way you fix a couple of bugs you discovered that had grown due to duplicate code that had evolved differently, but which should have remained consistent. When you're done, the only types that know about DbContext directly are your concrete Repository implementations.
Your application is growing more popular now, and some of the pages are really hammering the database. Their data doesn't change very often, so you decide to add some caching. Initially you start putting the caching logic directly in your data access code in your repository implementations that use EF Core, but you quickly find that there is a lot of ...
10/01/18 • 8 min
Generate a badge
Get a badge for your website that links back to this episode
<a href="https://goodpods.com/podcasts/weekly-dev-tips-155124/applying-pain-driven-development-to-patterns-8360125"> <img src="https://storage.googleapis.com/goodpods-images-bucket/badges/generic-badge-1.svg" alt="listen to applying pain driven development to patterns on goodpods" style="width: 225px" /> </a>
Copy