Domain-Driven Design in Swift: How to Stop Fighting Architecture

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Why DDD Is Not About "Just Another Pattern"

\n\n

Have you ever rewritten a project from scratch just because "business logic was scattered across all controllers"? Or maybe your UserManager grew to 2000 lines, and no one understands what it actually does? Sound familiar?

\n\n

In the world of Swift development, we are used to MVC, VIPER, or MVVM. But all these patterns solve the same problem: how to separate UI from logic. However, they say almost nothing about how to organize the business logic itself. And this is where Domain-Driven Design (DDD) enters the stage — an approach that puts not the framework, but the domain of your application at the center.

\n\n

In this article, we will break down how to apply Domain-Driven Design in Swift with real examples. You will see that DDD is not abstract theory, but a powerful tool that makes code readable, testable, and resilient to change.

\n\n

What is DDD in Simple Terms

\n\n

Imagine you are writing an application for an online store. MVC will tell you: "Make a Product model, a ProductViewController controller, and views." But DDD will ask: "What is a 'product' in your business? Can it exist without a price? What happens when it is added to a cart?"

\n\n

Domain-Driven Design is a way of modeling software where the code reflects the language and rules of the business as accurately as possible. Instead of "technical" entities (like DataManager), you work with domain objects: Order, Customer, Invoice.

\n\n

The Main Building Blocks of DDD

\n\n

To avoid getting lost in terminology, remember three main concepts:

\n\n
    \n
  • Entity — an object that has identity. Two objects with the same fields are different entities (like two different people with the same name).
  • \n
  • Value Object — an object defined only by its attributes. If two objects have all matching fields, they are the same object (like a date or an amount of money).
  • \n
  • Aggregate — a group of related objects treated as a single unit. An aggregate has a root entity through which access to all internal objects occurs.
  • \n
\n\n

Sounds dry? Let's move to Swift.

\n\n

Writing a Domain Model in Swift

\n\n

Let's say we are making a task management application (a TODO list). Let's start with the simplest — a Value Object for the task status.

\n\n
// Value Object: task status\nstruct TaskStatus: Equatable {\n    let rawValue: String\n    \n    static let todo = TaskStatus(rawValue: "todo")\n    static let inProgress = TaskStatus(rawValue: "inProgress")\n    static let done = TaskStatus(rawValue: "done")\n    \n    // Business rule: can only transition to the next status\n    func canTransition(to newStatus: TaskStatus) -> Bool {\n        switch (self, newStatus) {\n        case (.todo, .inProgress), (.inProgress, .done):\n            return true\n        default:\n            return false\n        }\n    }\n}
\n\n

Notice: we are not using an enum, because in real business, statuses may come from the server or be stored in a database. TaskStatus is an immutable object that knows its own rules.

\n\n

Now let's create an Entity — the task itself:

\n\n
// Entity: task\nfinal class Task {\n    let id: UUID\n    var title: String\n    var description: String\n    private(set) var status: TaskStatus\n    let createdAt: Date\n    \n    init(id: UUID = UUID(), title: String, description: String, status: TaskStatus = .todo) {\n        self.id = id\n        self.title = title\n        self.description = description\n        self.status = status\n                

Blogs

Book Recommendations