Skip to main content

How to structure your code, an MVCS approach (Model View Controller Service)

·3 mins

This post shows you a Model View Controller Service approach to structure a python backend service for a Shopify app.

This post builds upon How to build a Shopify app powered by a Python backend service so head over and read it to get some more context, or not, it’s all up to you :)

Structuring your python services using the model view controller service pattern #

Let’s walk through a Python backend service that is used to power a Shopify app. The example in this guide are for Django application but should be easy to understand even if you arent that comfortable with Python or Django.

The design pattern I use when structuring code is a variant of the old and battle tested MVC (Model, View, Controller) with the addition of an S (MVC+Service) which holds my business logic. The following picture sums it up quite nicely.

Model view controller service code structure

Why should you introduce a service “layer” in your application #

I know it might sound stupid to introduce a service “layer” for some simple tasks such as fetching a record from a database. Below you can see an API endpoint built in Django using MVC and then showing a better way to implement the same endpoint using MVCS:

Django MVC example

Django MVCS (service) example

So what is a service? #

A service is nothing more than a collection of functions, this is the merchant_service.get() function.

def get(shop_url):
    try:
        return Merchant.objects.get(shop_url=shop_url)
    except ObjectDoesNotExist:
        return Merchant()

> Ok, cool, but I’m still not convinced 🤷

Quite often it feels weird to add this extra abstraction, especially for the most simple use cases.

But consider this…

Fetching the store might be something we need to do in multiple endpoints.

Later on we might decide to only fetch active stores.

If you use a service you only have to update it in one place, making sure you have a consistent behaviour throughout your API endpoints. Pretty nice if you ask me!

It also makes it really easy to extend functionality of your services, below we are modifying the service to only return active Merchants by specifying a default input variable.

def get(shop_url,
        active=True):
    try:
        return Merchant.objects.get(shop_url=shop_url, 
                                    active=active)
    except ObjectDoesNotExist:
        return Merchant()

Why should you add a service layer in your code structure? #

These are just some of the reasons why I like to add the service layer when I build stuff, not just in Python but also Go or other languages.

  • Keeping the business logic in a service (or app or whatever you want to call it)
  • Gives you glance-ability into what your application does (just look at the function names in the service files).
  • Makes it a lot easier to test your business logic without having to test the full API endpoints.
  • It also makes you more alert that when you change a service you know that this can impact one or more consumers of the service.
  • It makes it really easy to add and modify your API endpoints, ie calling one or more services instead of writing business logic over and over again.

Best practices when working with services in MVCS #

  • A service should not call another service (unless absolutely necessary) instead the API endpoint / controller should be the one calling one or more services
  • All requests to the service layer must be validated, errors / exceptions should be raised to the caller
  • Services are a great way to achieve separations of concerns
  • Calls to external API’s should be done from the service layer

Thats all I have to say about that

Forrest Gump

I hope this triggered an interest to use this pattern the next time you are building something from scratch, or even made you refactor some of your existing code.