29
.
04
.
2024
16
.
08
.
2022
Ruby on Rails
Domain-Driven Design
Backend
Tutorial

Entity - DDD in Ruby on Rails

Paweł Strzałkowski
Chief Technology Officer

Entities are omnipresent. They are the backbone and the substance of most applications. We will take a deep dive into the concept of an entity from the Domain-Driven Design's perspective.

"An object defined primarily by its identity is called an ENTITY."

— Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software

Identity

The fundamental characteristic of an entity is its identity. The primary cause of its existence is to provide an identity and the ability to track a lifecycle.

Most applications orbit around identifiable objects. Those may be customers, products, operations, etc. For an e-commerce, it is crucial to track who has purchased what. For a bank, it is essential to distinguish every transfer (each deposit is a separate entity, even if their amounts match).

It is up to an application to define the level of identity recognition. For some, it may be enough to identify people using phone numbers when others cannot operate without a social security number-type value. Identity basis may be (among others) user-driven or application-generated. It all depends on use cases. It is important to choose the approach which aligns with your domain.

Once an entity, not always an entity

The decision to model a concept as an entity is not always obvious.

When designing a reservation system for a concert, we may assign a ticket to each seat. That seat would be modeled as an entity. It would also have characteristics such as location or type. The seat entity would come into existence at a point in time and go through changes (maybe a hard bench would be upgraded to a velour chair). Our reservation system would assign an attendee to the seat to book a concert ticket. On the other hand, there are events where seats are not assigned per ticket. What matters is the number of guests vs the total number of available seats. In such a situation, a seat would not be an entity but would rather become a value object representing the volume of seats.

Another example is money - the crowning example of a value object concept. Money amount is an attribute. But imagine numismatists who value each coin and each bill. They would put them in catalogs and carefully identify each item. Since the items have identities, we immediately recognize them as entities.

Identity assignment strategies

Vaughn Vernon, in Implementing Domain-Driven Design, describes four common strategies of identity assignment:

  • user provides a unique value (ie. email for a user account)
  • application generates an identifier (ie. invoice number or a UUID)
  • persistence store generates a unique identity (ie. DB auto-increment)
  • another bounded context has already defined an unique identity (when our entity is based on a remote one)

It is important to weight pros and cons of each approach before making a decision. Most entities in Ruby on Rails have their identity generated by a persistence store. Still, there may be a user-facing attribute (ie. email, phone or social security number) which can be used for authentication or for populating entities of the same identity in other contexts. DB-generated identifiers should remain local to the bounded context where they originate, as they have no meaning outside of it.

Most times, identity remains immutable after an entity is created. There are cases where an email address / username may be changed. It is a simple enough operation in a monolithic system. However, in a distributed one it may cause severe difficulties to propagate such a change.

Indispensable behavior

Entities not only are, but they also do. While doing, they go through their lifecycles of changes. A customer may change_phone_number(), an invoice may be voided by calling void(), an account may be activated with activate() method and so on.

Think what is the behavior of your entities. A list of operations is usually given to you by your client. It's important to realize that during the conversations and to be able to put down a list of methods similar to the ones listed above. They should express entity's behavior, not framework-related gimmicks like create_associations().

It's easy to fall into a trap of creating data bags, where every attribute has a setter and a getter. Such an entity is just a sack. It is moved around and operated on using a procedural approach. This way, you don't model your domain but rather elevate database tables to the level of objects. The result may only be described as an ORM-driven development. Whereas the nature of Object Oriented programming is encapsulation and representation of behavior.

How to design an Entity

"Rather than focusing on the attributes or even the behavior, strip the ENTITY object's definition down to the most intrinsic characteristics, particularly those that identify it or are commonly used to find or match it."

— Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software

Entities are characterized by multiple attributes but few of them are used for matching with other entities. The characteristics are valuable and drive the essential features of applications. However, what defines an entity is the identity which has to be matched or found. Therefore:

  • start by thinking what it represents and what are its relations with other elements. Don't jump right into listing all the attributes.
  • move on to the needed behavior
  • think carefully on naming - from now on, you will be using this language in every conversation
  • add the needed attributes and characteristics.

Please check out the follow-up post with a broad discussion of how to design an entity in Ruby on Rails.

Summary

ORM-centric frameworks, like Ruby on Rails, have always leaned towards treating entities as data wrappers. It is high time to put entities where they belong. They make the code explicit, readable and testable. They express identity, behavior and purpose. Entities reveal intention. Let us treat them the way, objected oriented paradigm demands and model their behavior with intention and purpose. Entities are the backbone of any well-designed domain model.

Resources

Articles in this series

Paweł Strzałkowski
Chief Technology Officer

Check my Twitter

Check my Linkedin

Did you like it? 

Sign up To VIsuality newsletter

READ ALSO

Is Go Language the Right Choice for Your Next Project?

14
.
11
.
2023
Maciej Zdunek
Backend
Business

SXSW Tradeshow 2020: Get Your FREE Tickets and Meet Us

02
.
10
.
2024
Michał Krochecki
Ruby on Rails
Conferences
Frontend
Backend
Business

How to build effective website: simplicity & McDonald's

14
.
11
.
2023
Lukasz Jackiewicz
Ruby on Rails
Frontend
Design

Thermal Printer Protocols for Image and Text

14
.
11
.
2023
Burak Aybar
Backend
Tutorial
Software

WebUSB - Print Image and Text in Thermal Printers

14
.
11
.
2023
Burak Aybar
Backend
Tutorial
Software

What happened in Visuality in 2019

14
.
11
.
2023
Maciej Zdunek
Visuality
HR

Three strategies that work in board games and in real life

14
.
11
.
2023
Michał Łęcicki
Ruby on Rails

HR Wave - No Bullshit HR Conference 2019

14
.
11
.
2023
Alicja Gruszczyk
HR
Conferences

Lightning Talks in your company

14
.
11
.
2023
Jarosław Kowalewski
Ruby on Rails
Visuality

Stress in Project Management

02
.
10
.
2024
Wiktor De Witte
HR
Project Management

How to find good developers and keep them happy - Part 1

02
.
10
.
2024
Michał Krochecki
HR
Visuality

PKP Intercity - Redesign and case study of polish national carrier

14
.
11
.
2023
Katarzyna Szewc
Design
Business
Frontend

Let’s prepare for GITEX Dubai together!

14
.
11
.
2023
Michał Piórkowski
Conferences
Business

Ruby Quirks

14
.
11
.
2023
Jan Matusz
Ruby on Rails
Ruby

Visuality recognized as one of the Best Ruby on Rails Devs

14
.
11
.
2023
Maciej Zdunek
Ruby on Rails
Visuality
Business

Is the culture of the organization important?

14
.
11
.
2023
Alicja Gruszczyk
Conferences
Visuality

Between the devil and the deep blue sea

04
.
12
.
2023
Mateusz Wodyk
Project Management
Backend
HR

Let’s prototype!

14
.
11
.
2023
Michał Łęcicki
Ruby on Rails
Backend

5 marketing hacks which will make your life easier

14
.
11
.
2023
Maciej Zdunek
Marketing
Design