Migrating Guide: Architecture Improvements (v2.0.0-pre6)

This guide covers the architecture enhancements and new persistence methods in v2.0.0-pre6.

Architecture Improvements

1. Enhanced Persistence Operations

New save_if_not_exists Method:

user = User.new(email: 'user@example.com')

# Only save if the user doesn't already exist
if user.save_if_not_exists
  puts "User created successfully"
else
  puts "User already exists"
end

Atomic Persistence with Transactions:

user.transaction do |conn|
  conn.set(user.key, user.serialize)
  conn.sadd("all_users", user.identifier)
  conn.expire(user.key, user.ttl) if user.ttl
end

2. Modular Class Structure

The Horreum class structure was reorganized for better maintainability:

Core Modules:

  • Familia::Horreum::Core - Essential functionality
  • Familia::Horreum::ClassMethods - Class-level methods
  • Familia::Horreum::Serialization - Object serialization
  • Familia::Horreum::Commands - Valkey/Redis command wrappers

Feature System Improvements:

  • Dependency management between features
  • Cleaner feature activation
  • Better error handling for missing dependencies

3. Enhanced Error Handling

New Exception Types:

begin
  user.save!
rescue Familia::PersistenceError => e
  puts "Failed to save: #{e.message}"
rescue Familia::ValidationError => e
  puts "Validation failed: #{e.message}"
end

Improved Data Consistency:

  • Automatic retry for transient Valkey/Redis connection issues
  • Better handling of concurrent modifications
  • Enhanced validation before persistence operations

Migration Steps

1. Update Error Handling

Before (v2.0.0-pre5):

begin
  user.save
rescue => e
  puts "Something went wrong: #{e}"
end

After (v2.0.0-pre6):

begin
  user.save
rescue Familia::PersistenceError => e
  puts "Persistence failed: #{e.message}"
  # Handle specific persistence issues
rescue Familia::ValidationError => e
  puts "Invalid data: #{e.message}"
  # Handle validation failures
end

2. Adopt Conditional Persistence

Replace existence checks with atomic operations:

Before:

user = User.new(email: email)
unless User.exists?(email)
  user.save
end

After:

user = User.new(email: email)
user.save_if_not_exists

3. Leverage Transaction Support

For complex operations, use transactions:

# Before - Multiple separate operations
user.save
user.tags.add(tag)
user.scores.add(score, timestamp)

# After - Atomic transaction
user.transaction do |conn|
  conn.set(user.key, user.serialize)
  conn.sadd(user.tags.key, tag)
  conn.zadd(user.scores.key, timestamp, score)
end

Performance Improvements

Connection Management

  • Improved connection pooling with better resource utilization
  • Reduced connection overhead through intelligent connection reuse
  • Enhanced concurrent operation support

Feature System

  • Lazy feature loading reduces memory footprint
  • Optimized method dispatch for feature methods
  • Better dependency resolution

Breaking Changes

Method Signatures

  • Some internal methods changed signatures for better consistency
  • Error handling improved with specific exception types
  • Transaction block interface standardized

Feature Dependencies

  • Features now explicitly declare dependencies
  • Better error messages for missing feature requirements
  • Automatic dependency resolution where possible

Next Steps

After completing architecture migration:

  1. Explore Relationships Migration for the comprehensive relationship system
  2. Review updated documentation for architectural patterns
  3. Consider adopting new persistence patterns in your application