Migrating our VueJS Frontend to Domain Driven Design

Ricardo Delgado
PENNgineering
7 min readFeb 10, 2022

--

The Good: Modern Javascript frontend frameworks have empowered companies and startups, big and small, to create incredibly complex and sophisticated applications that have been a boon for users and have led to a much improved interaction with a company’s software.

The Bad: Modern Javascript frontend frameworks are often bloated, overly complicated and confusing, creating headaches for developers and QA alike, because of the inability to scale software in a straightforward way. This leads to bugs and costly mistakes to a company, which tends to worsen over time.

This is the delicate balance a modern Javascript developer faces — how to create a complicated application while maintaining the golden standard of readability and simplicity.

At Penn Interactive our frontend codebase has slowly grown into a massive hulking beast, like a Hydra slowly raising from the waters, growing two new heads for each one that is cut off.

It was time to make a change, and our biggest was changing our architecture to Domain Driven Design.

Domain Driven Design

Domain Driven Design (DDD) is an architectural concept in software engineering where the structure of a codebase follows a pattern set by domains rather than the loose model-view-controller (MVC) that most Vue codebases follow.

For these purposes MVC refers to the relationship that splits folder structure up by its relationship to the functional aspects of a codebase. For example: router, store, pages, components, assets, helpers.

For VueJS these are the standard folders that most developers use at the start of their project to organize their folder structure.

As for a domain, it refers to a subject matter most likely tied to specific sets of data handled by the app.

This could mean folders like: user, location, product, payments, etc.

DDD looks to move the conceptual structure of an app into a realm that makes more sense to the project itself, rather than an abstracted code-centric model that really doesn’t make sense to the specific project — and as most developers who’ve worked on a massive enterprise-level Vue app can attest, doesn’t scale very well either.

Migrating Barstool Sportsbook from MVC to Domain

PI started on Barstool Sportsbook’s codebase almost two years ago. At that time most, if not all, of the philosophies around architecting a Vue app were driven by MVC.

This can especially be seen with Nuxt’s auto importing features, where folders like pages, stores, layouts, and components can be auto imported and used throughout the app, forcing a dev into the MVC structure.

For Sportsbook our root folders were structured as such:

/sportsbook
- assets
- components
- directives
- filters
- hooks
- mixins
- modules
- plugins
- request
- router
- styles
- utilities
- views

This structure essentially lines up with Nuxt’s and VueJS’s default architectures. But where the MVC structure breaks down is as you dive into each one of the folders.

For example, within views we have some of the following folders:

/views
- bs-exclusives
- casino
- event-details
- live-events
- sports

And within event-details:

/views
/event-details
- event-detail-content.vue
- event-detail-error.vue
- event-detail-footer.vue
- event-detail-skeleton.vue
- event-details.vue
- event-stats.vue

Then looking into modules (which is where we keep our Vuex store modules, only selected shown):

/modules
- casino
- events
- live-events
- sports

As you can already see there’s a similarity in the folder structure. And this holds true in other areas, as well, such as tests, and assets.

To make things even more complicated, other folders, such as plugins or mixins don’t have any structure, and certain files may also only relate to a live-event or casino.

This overlap (and lack of overlap) is a feature and not a bug of following MVC. Even though I’d readily admit is useful and preferred in smaller applications.

But for us, this was becoming untenable:

  1. Each file would have an associated number of other files that were in totally different root folders. This includes helper files, constant files, store files, test files, asset files, possibly plugins, and more. It would make navigating files in the IDE nightmarish.
  2. Because of files related to a subject matter (domain) spread across different locations throughout the codebase, this led to slower development time and something akin to spaghetti code.
  3. This spreading of code is especially troublesome as folders grow in size, and as Sportsbook grew from dozens of files to thousands of files things became more and more difficult to keep straight.

Moving to Domains

Moving to Domains was motivated by a presentation made by Filip Rakowki of Vue Storefront during Vue Conf Toronto 2020, and also inspired by Thomas Findlay’s Vue — Road to Enterprise.

Thinking of Domains is a bit like changing your perspective on the dimensions of a codebase.

As was hinted at in the previous section, the MVC model can create parallel structures that are nearly identical while also having a great distance away from each other.

So like shuffling a deck of cards, moving to Domains breaks down the artificial divisions in the codebase, and lets related matters find a home together.

One of the big challenges in the migration to Domains is how to determine what are Domains for your project. Some directions of thought:

  1. A domain might tie in very tightly to API calls, if you’re operating as a micro-service or a headless system. RESTful structures, if designed properly, should map across a domain nicely.
  2. Using your UI as a guide to what your app conceptually bundles together. For example, with Sportsbook:
Defining Domains such as Trending Items, Promotions, Leagues, and Events

Other Domains might include Users, Wallet, Casino, etc.

Now, instead of having pages, store, etc. root folders, we instead align our root folder structure like this:

/src
- events
- leagues
- promotions
- trending-items

But this is only part of the refactoring, because each of these folders now require their own structure.

This gives us the ability codify a coherent file structure, rather than dumping a file wherever it seems to fit in the given schema that may or may not have any rhyme or reason.

Now that the root of each grouping is within a Domain there now needs to be a restructuring of each folder so they can act as their own module based on the Domain.

Taking events:

/src
/events
- store.js
- helpers.js
- index.js // instead of view.js, but I prefer index for views
- constants.js
- plugins.js
/components // that are only for high event level
/sub-domain

This reveals the perspective change that has to occur when moving to Domains. The root folders that existed in the MVC model now become part of the starting template for our Domain Module.

The one tricky issue is this idea of sub-domains , which don’t have an equivalent in an MVC structure.

The purpose of sub-domains is purely administrative and organizational, but track closely with other programming concepts such as Component Driven Design and Test Driven Development — in so much that a developer should break concepts down to their smallest parts.

Since one avenue to determine a Domain is to check the UI, let’s check out an event page:

Here we see three sub-domains that could clearly be defined within an Event: Event Header, Event Bets, Events Stats.

Meaning that we can then have a structure such as:

/src
/events
- store.js
- helpers.js
- index.js
- constants.js
/components
/event-header
- store.js
- helpers.js
- index.js
- constants.js
/components
/event-bets
- store.js
- helpers.js
- index.js
- constants.js
/components
/event-stats
- store.js
- helpers.js
- index.js
- constants.js
/components

While there will obviously be differences depending on your codebase and app, hopefully this can provide a beginning track on how to migrate your own codebase to a Domain Driven Design architecture.

In Summary, MVC vs DDD

Model-View-Controller (MVC) Architecture:

Pros:

  • Native to VueJS, both in Vue and also in NuxtJS
  • Useful for smaller sized projects and apps
  • Follows functional structure

Cons:

  • Doesn’t scale
  • Could be difficult for inexperienced devs to follow code
  • Could potentially lead to related code spread across various locations in codebase

Domain Driven Design (DDD) Architecture:

Pros:

  • More intuitive folder structure
  • Aligns with other aspects of application, such as UI and data
  • Enables a structured method for architecture

Cons:

  • Overkill for smaller sized applications, too much systemic process if not justified
  • Requires enforcement and buy-in from all devs, could easily create issues if not adhered to strictly
  • Does not lend itself to auto-importing of components, layouts, store files, or pages/views, as seen in NuxtJS

Ricardo Delgado is a frontend web developer for Penn Interactive with an area of specialization in Unit Testing in VueJS, Component Driven Design, and Domain Driven Design.

You can see his other articles here:

For other links:

Twitter: https://twitter.com/ricardod_dev
LinkedIn: https://www.linkedin.com/in/ricardo-delgado-6ab12a93/
Practical Dev: https://dev.to/rdelga80
Website: https://rdelgado-portfolio.web.app/

--

--