Skip to content
Tamerlan Satualdypov edited this page Jul 31, 2023 · 2 revisions

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.

Designing your Model

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.

Examples

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 { ... } 
}
Clone this wiki locally