Your Controllers Are Doing Too Much — This Is How to Simplify Them

No business logic or data access allowed. Refactor to very thin controllers for better maintainability and flexibility

Nicklas Millard
Jul 12, 2020 · 5 min read

I’m sure you’ve at least once before accessed a database directly from inside a controller. Perhaps you’ve also snuck some business logic in as well.

Chances are you’ve learned this practice from the many tutorials you have watched and all the documentation you’ve skimmed thru. Even Microsoft is guilty of this.

This practice doesn’t seem too bad at first as it gets you out of the gates almost immediately. However, it has some massive drawbacks such as encouraging duplicate logic and entangled responsibilities.

This is the kind of bad practice we need to eliminate.

Let me tell you this, controllers shouldn’t do anything remotely related to business logic, and directly access data stores.

The controller’s only purpose is to receive a request and return a response. Everything that goes in between is not its responsibility.

So, with regards to the statement above, you should now be aware that code like the snippet below is a complete no-go.

Controller accessing a data store

Accessing a data store, or even a repository, from a controller, is bound to introduce trouble down the road.

This controller is so far an incredibly simple one. It first starts to get exponentially crazier when you’re also inserting data into your database from the controller.

Your controllers should be super thin

In modern days, we’ve left the Model-View-Controller (MVC) pattern on the shelf. It’s no longer a pattern any new web application uses. Now, we’re mostly building APIs that’ll expose data to the world. We can think of our controllers as the modern-day (data-)presentation layer.

It’s simply well outside the responsibility of the controller to know how data is retrieved — such as remembering to include the user’s list of articles.

Placing data retrieval and business logic in controllers nowadays is the equivalent of placing it inside old-school views, in the context of MVC.

I’m sure you wouldn’t want to do that… so why should you do it in modern controllers?

Let’s refactor that poorly designed controller

Show me the code — git repo

Refactoring the messy controller requires a tad more leg work from us. I propose three simple refactoring steps.

  1. Create a user repository class that’ll deal with data access
  2. Use a poor man’s version of CQS to encapsulate business logic
  3. Inject a specialized query class into the controller

We’ll end up with a controller looking like this snippet below. Neat, clean, and easy to understand.

Now, the controller has no idea of how data is accessed. All it knows is it must use this GetUsers query class.

I’ve drawn an overall solution structure to the absolute best of my abilities… I hope this will help you to understand the different parts and code snippets I’m going to show you.

So, let me give you a brief guided tour thru our system.

1 First off, some user makes a GET request to our web client’s controller at api/users that invokes the controller action Get(). The controller takes a dependency on aGetUsers` class which resides in a different module — or project in .NET terms.

2 Our GetUsers class is a special query class that has a dependency on a repository interface defined inside the same module. At runtime, we’re getting a concrete implementation of the IUserRepository` thru a dependency container.

Simple query class to fetch users

3 The UserRepository` implements the required interface used by GetUsers. To retrieve the actual user objects, we need access to a specialized data store class. In the case of .NET, we’ll be using EntityFramework Core for this. It comes with a DbContext class that much like an in-memory database. I’m sure your framework of choice has something similar to this.

Notice how the UserRepository` now has all the knowledge required to query the database for the full user object graph — i.e. including every users’ articles.

We’ve completed pull out this knowledge from our controller, which now, only deals with accepting a request and replying with a response.

“It’s a lot more complex now”, you might say

Well, we increased the number of classes.

Some equal this to increasing complexity. However, each class now has a very narrow responsibility. Whenever we’re about to go beyond a class’ responsibility, we make a new one that’ll care only about one single functionality.

Following the separation of concerns principle, you’ll quickly realize how enjoyable it’ll be to work with your solution.

Resources for the curios
C# Design Patterns: Command by Filip EkbergCommand in C# by refactoring.guruWhy I No Longer Use MVC Frameworks by Jean-Jacques DubrayIs Model-View-Controller Dead On The Front-End by Alex Moldovan

Nicklas Millard is a software development engineer in one of the fastest-growing banks, building mission-critical financial services infrastructure.

Previously, he was a Big4 Senior Tech Consultant developing software for commercial clients and government institutions.

Connect on LinkedIn

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Nicklas Millard

Written by

Tech writer with 759K+ views. Sharing my opinion and what I learn. Danish C# backend engineer in FinTech. Ex Big4 senior tech consultant.

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Nicklas Millard

Written by

Tech writer with 759K+ views. Sharing my opinion and what I learn. Danish C# backend engineer in FinTech. Ex Big4 senior tech consultant.

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store