Enterprise applications power businesses from banks to e-commerce platforms. Building robust, maintainable, and scalable enterprise systems requires not only well-written code but also the right architectural patterns.
One powerful pattern from Martin Fowler’s Catalog of Patterns of Enterprise Application Architecture is the Active Record Pattern. This pattern combines the domain object with data persistence, simplifying CRUD operations and making the code straightforward for smaller domains or prototyping.
What is the Active Record Pattern?
The Active Record Pattern maps an object in the application directly to a row in the database. Each object is responsible for saving, updating, and deleting itself from the database.
Benefits:
- Easy to understand and implement
- Encapsulates data access logic within the object
- Reduces boilerplate code for CRUD operations
Drawback:
- Can become messy for complex domains where business logic grows
Real-World Example: User Management System in Ruby
We will implement a simple user system where the User object handles its own persistence using the Active Record pattern.
# user.rb
require 'sqlite3'
# Create database connection
DB = SQLite3::Database.new "enterprise.db"
DB.execute <<-SQL
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
);
SQL
class User
attr_accessor :id, :name, :email
def initialize(name, email, id=nil)
@name = name
@email = email
@id = id
end
def save
if @id
DB.execute("UPDATE users SET name=?, email=? WHERE id=?", [@name, @email, @id])
else
DB.execute("INSERT INTO users (name, email) VALUES (?, ?)", [@name, @email])
@id = DB.last_insert_row_id
end
end
def self.find(id)
row = DB.execute("SELECT * FROM users WHERE id=?", id).first
row ? User.new(row[1], row[2], row[0]) : nil
end
def self.all
DB.execute("SELECT * FROM users").map { |row| User.new(row[1], row[2], row[0]) }
end
def delete
DB.execute("DELETE FROM users WHERE id=?", @id) if @id
end
end
Demo
# main.rb
require_relative 'user'
# Create users
alice = User.new("Alice", "alice@example.com")
alice.save
bob = User.new("Bob", "bob@example.com")
bob.save
# List all users
puts "All users:"
User.all.each { |user| puts "#{user.id}: #{user.name} (#{user.email})" }
# Find and update user
user = User.find(1)
user.name = "Alice Smith"
user.save
# Delete a user
User.find(2).delete
puts "After updates:"
User.all.each { |user| puts "#{user.id}: #{user.name} (#{user.email})" }
Expected Output:
All users:
1: Alice (alice@example.com)
2: Bob (bob@example.com)
After updates:
1: Alice Smith (alice@example.com)
Why Active Record Helps
- Encapsulation: Each object handles its own persistence
- Simplicity: Easy to implement for small applications or prototypes
- Readability: CRUD operations are directly visible on the object
For more complex systems, patterns like Repository or Unit of Work might be better, but Active Record is excellent for quick development and simple domains.
Conclusion
The Active Record Pattern is a practical enterprise design pattern for managing domain objects with integrated persistence. By using Ruby, we demonstrated a user management system where objects can save, update, and delete themselves, making the code readable, maintainable, and easy to extend.
Top comments (0)