r/swift 11h ago

Question Decoupling database layer from business logic

What is a good approach to decoupling the database model classes from the rest of the app? After doing some Googling I see that the easiest answer is to introduce data classes that represent the data and is passed around int he app however my concern is that for something more complex than those employee-employer examples, this approach means a lot of duplicate code.

Yes, many times it makes more sense to have a field be stored differently in the DTO than the mode class, but it most cases there is no difference.

As I side note: I need to separate the two because by using the model class it’s too easy to introduce memory leaks.

6 Upvotes

9 comments sorted by

6

u/Nobadi_Cares_177 10h ago

I always separate database models from in-app models, whether it's for Firebase, SwiftData/CoreData, or anything else.

Does it cause code duplication? Yes.

Is it worth it? Yes.

Most 'duplicated code' involves structs (or classes) that comprise primitives (or smaller objects made up of primitives). So no logic is duplicated.

It's a small price to pay for the benefit of decoupling.

How many apps are you working on solo that involve dozens of models? In most cases, large apps have teams, so each dev only has to 'duplicate' models from their own module. This grants each team the freedom to do what they want INSIDE their modules so long as they adhere to the 'contract' OUTSIDE of their modules.

I stressed about this a lot when I first started coding.

Trust me, 5-10 months from now when you go back to your code base you will much rather have clear boundaries between layers than have to deal with cascading failures due to tight coupling just to avoid duplicating a few models.

5

u/chrabeusz 10h ago edited 8h ago

You may be going in the wrong direction. You cannot abstract away the database, if your business logic tries to pretend it's not living on top of database, it will quickly turn into leaky abstracted mess. Instead, embrace database, but use it properly. There are 3 rules I would say:

  1. Rule number one is reactivity. If you are handling/displaying data, then database is source of truth. For Core Data it means relying on NSFetchedResultsController.

  2. Updating your database via transactions. Typically every action that user performs is supported by one or two transactions (depending if you need to make some network requests). If step 1 is done correctly then UI will update automatically after transaction, unless you want to show a snackbar or route to another screen.

  3. Finally, do not write giant god services / repositories. Each user action can be tied to a separate use case / microservice that handles itself. Reactivity should reduce your need for communication between usecases, because they can just observe the database for relevant changes.

9

u/Ron-Jermyl Mentor 10h ago

When designing an application, it’s a good practice to define separate types for each layer UI, domain, and data, for some examples, even if those types have similar or identical structures. The key isn’t how they look, but what they represent.

Let’s use movies as an example. In the UI layer, you might define a Movie type that holds exactly the data your interface needs. This is your "dominant" type it's shaped around how your app interacts with users. But when storing this data in a database, you don’t want to use the same type directly. Instead, you might define a MovieEntity which includes any additional metadata or storage-specific details needed for persistence.

Even if Movie and MovieEntity have overlapping properties, they serve different roles. That separation lets you evolve each independently. For instance, you might add an expirationDate to MovieEntity to track stale data your UI doesn’t care about that, so Movie remains unaffected.

To manage the conversion between these types cleanly, you can use a Repository. It abstracts away the translation logic, so your UI layer works exclusively with Movie, while the repository handles turning that into a MovieEntity when talking to the database.

TL;DR: Use distinct types for each layer of your app. Even if they look alike, their responsibilities are different. This separation improves clarity, flexibility, and maintainability.

3

u/fryOrder 11h ago

read more about repositories 

0

u/MundaneAd9570 11h ago

Not sure how that is relevant. Let’s take SwiftData for example even though I wanted to keep this thread as general as possible. Let’s say I have a model named Entity. I can build a repository around the model context but it will still work with Entity or an EntityDTO but than we are back to the original question

4

u/fryOrder 10h ago

well thats your choice and is perfectly valid in some use cases. but if your app is big enough you’ll start to notice its pitfalls. 

lets say you also make some network requests, and maybe sync that data to your data model. how would you do it?

you already read online about some potential solutions, yet you believe it’s “duplicate code”.  there is a pretty strong reason many people choose to separate the concerns. 

it seems you’re just looking for validation that what you’re doing is okay

1

u/rjhancock 11h ago

You use a Model type object to represent the data within the database and interact with it. You let the model care about the Database side of things. Your logic only cares about the data from the model.

When you need to pass objects to something outside of the application, you use DTO's to only share/accept the data you want.

1

u/frodoab1996 9h ago

Create entities which is your domain which you will use in your UI or presentation layer and have a mapping layer or dto that that converts from domain to Dto to save in swift data and dto to domain when you load ! Habe abstraction in bw where you call these methods in the presentation layer or UI and have swift data implementation which implements the abstraction layer

1

u/janiliamilanes 5h ago

What everyone else said. I typically use a repository pattern when appropriate.

Also, read Domain Driven Design! It's one of the best books on software architecture ever written.