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

WebUSB - Bridge between USB devices and web browsers

14
.
11
.
2023
Burak Aybar
Ruby on Rails
Frontend
Backend
Tutorial

Visuality comes to town - this time it's Poznań

14
.
11
.
2023
Michał Piórkowski
Visuality
HR

CSS Modules in Rails

14
.
11
.
2023
Adam Król
Ruby on Rails
Tutorial
Backend
Frontend

How to choose a software house.

14
.
11
.
2023
Michał Piórkowski
Ruby on Rails
Business
Visuality

JSON API versus the NIH syndrome

14
.
11
.
2023
Nadia Miętkiewicz
Backend
Frontend
Tutorial

From Idea to Concept

02
.
10
.
2024
Michał Krochecki
Ruby on Rails
Business
Startups

Styling React Components

14
.
11
.
2023
Umit Naimian
Ruby on Rails
Frontend
Tutorial

How good design can help your business grow

14
.
11
.
2023
Lukasz Jackiewicz
Design
Business
Marketing

TODO not. Do, or do not.

29
.
11
.
2023
Stanisław Zawadzki
Ruby on Rails
Software

CS Lessons #003: Density map in three ways

14
.
11
.
2023
Michał Młoźniak
Ruby
Backend
Tutorial
Software

Clean code for the win

14
.
11
.
2023
Michał Piórkowski
Ruby on Rails
Backend
Frontend
Business

Crowd-operated Christmas Lights

14
.
11
.
2023
Nadia Miętkiewicz
Ruby on Rails
Backend

How to startup and be mature about it

14
.
11
.
2023
Rafał Maliszewski
Ruby on Rails
Startups
Business

A journey of a thousand miles begins with workshops

14
.
11
.
2023
Michał Piórkowski
Software
HR

CS Lessons #002: Data structures

14
.
11
.
2023
Michał Młoźniak
Ruby
Software

Summary of Phoenix workshop at Visuality

14
.
11
.
2023
Karol Słuszniak
Ruby on Rails
Visuality
Backend

CS Lessons #000: Introduction and motivation

14
.
11
.
2023
Michał Młoźniak
Ruby
Software

CS Lessons #001: Working with binary files

14
.
11
.
2023
Michał Młoźniak
Ruby
Software

Working with 40-minute intervals

14
.
11
.
2023
Sakir Temel
Software
HR

THE MATURE TECH STARTUP DILEMMA: WHAT'S NEXT

14
.
11
.
2023
Susanna Romantsova
Startups

Win MVP workshop!

14
.
11
.
2023
Susanna Romantsova
Startups

FINTECH WEEK IN OSLO: WHATs & WHYs

14
.
11
.
2023
Susanna Romantsova
Conferences

MY FIRST MONTH AT VISUALITY

14
.
11
.
2023
Susanna Romantsova
Visuality
HR

NASA 1st global hackaton in Poland? Visuality Created it!

14
.
11
.
2023
Rafał Maliszewski
Ruby on Rails

Berlin StartupCamp 2016 summary

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