-
Notifications
You must be signed in to change notification settings - Fork 4
Model
The entities in the Model
layer are not a simple structs (DTOs
or POJOs
), they serve as repositories for the application's data and embody the logic for manipulating that data. This domain is a system of such objects, that has their own properties, methods and relationships. Models
should be independent and could be reused across all modules of an app. The objects in the Model
layer could use Active Record
, Data Mapper
or Factory Method
design patterns to avoid doing extra work and creating unnecessary layers in the project.
In order to successfully design your Model
, you should see it as an object that represents special knowledge and expertise. They identify and define the logic that manipulates the data. You should not see Models
as plain structs and put all the logic around it in other layers, as it is mistakenly done in other patterns, such as MVC
or MVVM
. Do not feel uncomfortable that entities in this layer contain the logic that manipulates its data, because it is natural and it gives you flexibility in reusing them in different modules of your app.
Data
, Store
and Service
objects belong to the Model
layer. Therefore, entities in this layer are not only structs. If you need to define an object that embodies the data, you create data object using structs. If you have advanced logic with the states around the data object, you create stores. If you are dealing with network, caching etc. you create service objects. And these entities are all models in the Model
layer.
You could use the following steps to quickly design the Model
:
- Identify the data (properties)
- Identify the tasks (methods)
- Identify the dependencies (nested
Models
)
Keep in mind that Model
should always be independent, reusable and not coupled with presentation logic.
Data Object
struct Post: Codable, Identifiable {
// Data
let id: String
let title: String
let text: String
let isLiked: Bool
// Dependency
let author: [Profile]
// Tasks
func publish() async { ... }
func edit() async { ... }
func like() async { ... }
func dislike() async { ... }
// Factory
static var all: [Post] { get async throws }
static var liked: [Post] { get async throws }
static func with(id: String) async throws -> Post { ... }
static func search(for query: String) async throws -> [Post] { ... }
}
Store Object
class PostStore: ObservableObject {
@Published var posts: [Post] = []
@Published var likedPosts: [Post] = []
func load() { ... }
func like(post: Post) { ... }
func dislike(post: Post) { ... }
}
Service Object
class Network {
static let default: Network = .init()
func request(endpoint: Endpoint) async throws -> Data { ... }
func request<T: Decodable>(endpoint: Endpoint, as object: T.Type) async throws -> T { ... }
}