How to separate concepts with MVC

I interned at my first and current job. I was tasked with working on one of the internal tools that the team uses to manage various resources and assets for our platform. Being new to “corporate software development,” I was excited to get to start writing code. It was a great place to start, but I realized just how little I knew about writing good code, and how unfamiliar I was with the framework. This internal tool used ASP.NET MVC as its primary framework, with Entity Framework for the database mapper.

I had never worked with a framework like Entity Framework, and I was blown away with how easy it was to work with database objects, and how its abstraction made working with data super easy. Since Entity Framework primarily depends on your ability to work with objects in C#, I was able to get accustomed to it fairly quickly. MVC though, I struggled with.

Table of Contents

Defining MVC

The MVC design pattern stands for Model, View, Controller. Each of these three parts play an important role in holding, displaying, and processing data.

  • Model: A collection of properties that represent a theoretical object. This could be a User, a Chair, a Tree, or a WebRequest. Your model should not provide business logic specific processing abilities.
  • View: A template or similar that defines what the User will see. The view should not have any processing logic in it, besides in some situations conditional views and sorting or pagination.
  • Controller: Handles business logic, and creates and processes Models to be passed to the View for display.

Simple enough, so where can it get confusing?

Organization

In ASP.NET MVC, you get three folders, helpfully named Views, Models, and Controllers. It’s pretty clear what is supposed to go in what folder, but don’t be constrained to only these folders! What I mean by this is, your only components do not have to be Views, Models, and Controllers, and they don’t all have to be defined at the root level in those folders. Make subfolders! Make other folders outside of those three! I struggled with this because I was trying to learn the framework, and I figured that I should just stick to what was provided to me. Also, make use of Utilities!

Utilities

Utilities are one of the most underrated abstraction concepts out there. I also think they can be one of the messiest parts of a codebase if not handled properly. So what are they?

I think a utility can best be described as common helper functions for your models, and for any other common operation that doesn’t fit with any specific model. This can be things like extended string formatting, common verification tools, and anything else.

Be careful about just throwing methods in a utility class though. You should still be abstracting in your utility classes. If you don’t, your utility classes are only going to cover a narrow scope of issues, and you’ll end up with code duplication and hard coded processes. Think about the separation of concerns idea. Your methods should really only be doing 1 thing in them. If you keep these things in mind, your Utility classes will prove useful in all other areas of your code.

Does this go in the Controller or a Utility?

I ran into this question all the time, and I had a hard time figuring out what my mentor was expecting. I think this was primarily due to me not thinking about what the controller’s action was actually supposed to be doing, and not having any other helper classes. In general you want to keep your controller actions fairly simple, again with the separation of concerns idea. Utilities also are meant to be tools, not entire processing tools. Enter the fourth part of MVC: Services!

Services

In my opinion, MVC, should have had an “S” added in for “Service.” Services are similar to controllers, except they’re more of a dedicated “backend” tool for processing data. If you have a common type of data lookup you need to perform, you may want to consider making a service for it. The service would take parameters to customize what data it may look at, any filters it may apply, and more. Then, your controller would simply call the service with the appropriate parameters and then present the results of the service to the view.

Services are more likely to contain more complex processes that wouldn’t make sense in a utility, so they can help you keep your utilities and your controllers smaller and more modular. By encapsulating these complex processes within services, you can maintain a high level of abstraction in your application, making it easier to understand, test, and maintain.

Services should be independent of the calling controller or utility, as they’re meant to provide a service to anything that needs it. If you’re abstracting your code properly, this shouldn’t be much of an issue.

Views and Composition

You know about composition in programming? Well, the same concept applies to views! If you put everything directly into a view without using any partial views or components, you’re likely going to run into code duplication errors! What’s worse, is this is in your user experience, so at the point you want to redesign your service, you’re left with finding all instances of whatever common component you have that you copied around to all of your views.

Each framework is going to handle this a little differently, but they should all have some sort of concept of nesting views. Nesting views will make your front end development way easier and maintainable. You’ll have common components, which will help keep you from reinventing the wheel constantly. Your user experience will be consistent. Because your views are used in multiple places, you’ll have fewer bugs due to having greater coverage. Just overall better!

Nobody’s Perfect

I think my last piece of advice (for now), is that nobody’s perfect. You’ll make mistakes when developing your program that you’ll wish you hadn’t. You’ll realize that some other structure would have been better, and now you’re having to painfully refactor your code. That’s ok!

Part of the software development learning process is making many, many mistakes. Sometimes, that’s the only way to actually learn. And sometimes, there’s no way you would have known to not do it that way!

If you sit and stumble over design concepts and never actually write any code, you’re not making progress on your program! There’s a balance between rushing code and writing well thought out and well designed code, see the Timeline Dilemma. But at some point, you’ve got to start. This is why I encourage working on side projects, as you’re likely to run into design issues as you stand up new services and then try to expand on them. And the more projects you work on, the more familiar you’ll be with future projects.

But as always, abstract! Abstracting your concepts is so important. Abstracting your concepts is what will help you refactor your code down the road. It’ll help you keep things reusable and testable. It’ll help you use your models, services, and utilities in other controllers and other areas of your code. I’m slowly writing some articles on abstraction over here, so feel free to check that out.

Do you have any other questions? Feel free to drop a comment below, and I’ll see what I can help you with!