Which .NET Design Pattern is Best For Your Next Project
Today’s .NET projects are more than just a few lines of code hidden behind a windows form. They are a construction of classes, projects, or even entire solutions grouped by responsibility. By grouping classes in specific ways, we are able to build the solution quickly and implement many features that assist you in creating robust and testable solutions.
Just a quick note, the last letter in a design pattern is where the business logic lies. It’s where you morph data. Others say it’s the “driver” of the application—it’s used to navigate the application. While the latter holds true for most patterns, there are outliers that make this false. We will look more into this below. But first, let’s jump into the four patterns we’ll be discussing today—MVP, MVC, MVVM, and MVVMC.
Although it may seem like MVP is the most valuable (slow clap), it is rarely used these days since it’s been replaced by more robust and testable design patterns. In MVP, the presentation layer (the layer with all the awesome-looking controls) is where the business logic lies. In .NET an MVP pattern is commonly used in Windows Forms. The presentation’s code behind is in charge of most of the business logic. As you can see, oftentimes the View sits in the presentation layer, so this design can be redundant.
While this is great in small projects, unit testing is almost impossible since you have to spin up the application to test any logic. Mocking data is possible, but automating unit testing is not (or not easily possible without doing some major overhauling of the structure. Most of your tests will have to rely on reading data that may be formatted for the presentation layer, which may result in more assertions and more data conversions to test your application.
If you have worked in .NET web applications, you may have run across the MVC pattern. While this is not a true MVC pattern, it does hold many characteristics of MVC. In MVC, you have a Controller, a View, and a Model. The Controller is exactly that—a controller. It controls the business logic and navigation. The Model (a.k.a. a Data Transport Object, or DTO) is introduced here and is used to transport data from the data source to the View. The View binds to the model and displays what the model contains in a user-readable way.
There are a number of advantages this pattern has over its predecessor – MVP. You can now mock the data source and fill the Models with data without using a hard data source. With this, you can now test your domain (where all the magic happens) without running the application. This is good news in the automation world where you build and test your application in an automated build. The builds can not only test your application without running it, but it can also run multiple tests in parallel.
If you have worked with Windows Presentation Foundation (WPF), then you have at least heard of the MVVM pattern. The MVVM pattern is very similar to MVC (after all, it manifested from MVC), except there are some differences. MVVM uses a shared (or portable) domain. Meaning that the domain can be placed in several front ends, or presentation layers. It also has multiple data stores.
In the beginning, MVVM was used to share your domain in Windows Desktop, Windows Phone, and Windows Apps. Since the developer only had to develop and test the domain once for each type of device, it saved a lot of time in development and testing. Much like the controller in MVC, The ViewModel is at the heart of the design. It contains the business logic and controls how the data moves in and out of the application. Also, much like the controller, the ViewModel sends and receives data with the use of a Model. However, the ViewModel (unlike the Controller) also holds properties the View will bind to. It does not pass a Model to the View, instead, the View binds to the ViewModel. Because of this, the View can now retrieve real-time updates from the ViewModel. All while keeping a separation between the View and the ViewModel.
Since Microsoft abandoned the beloved Windows Phone and increased the portability of Windows Apps, MVVM has changed over the years from a portable domain that can be used in Silverlight Applications, Windows Phone Applications, Desktop Applications, and Windows Apps to more of a power design pattern use to rely on data-binding to the View while keeping the separation between the layers—all while allowing unit tests and build automation. You can see why it is still used today.
While this pattern looks very confusing, it’s a pattern used very frequently in the ASP.NET MVC space. Instead of binding the View to a Model that comes from a database, the controller will take many models and combine them into a ViewModel. The View will then bind to the ViewModel. The ViewModel will not have real-time updates from the controller like in MVVM, but it will ease the pain of dealing with multiple Models in a View.
There is no real advantage as far as testing goes with this pattern. The Models are still used to transport data to and from the data source. The advantage strictly deals with the Presentation layer of the application.
Which Design Pattern Do You Choose?
While the world remains heavily invested in web technologies, there is (and always will be) a place for native applications. Knowing what design pattern to use is just as crucial as using the design pattern correctly:
- MVP is appropriate for very small applications that do not require unit testing or where scalability is minimal.
- MVC is appropriate for applications that usually have one front end, and run on one platform, such as small enterprise applications. This pattern is also used widely in the webspace.
- MVVM is appropriate for large, complex enterprise applications that require unit testing and real-time updates to the front end.
- MVVMC is used in applications where multiple models are combined for use in the Presentation Layer. This pattern is also used alongside the MVC pattern.
There is more to these design patterns as well as design pattern infrastructure than this post covers – such as Dependency Injection, Mocking, Automated Builds, and Automated Testing. I felt it was out of scope. This article aims to contextualize the common design patterns you will come across when working with .NET.