🛠️ 技術框架與設計模式
🎯 Ruby on Rails 7.1
企業級 Web 框架,提供 MVC 架構、ORM、路由和中間件支援,是整個應用的核心基礎。
🗄️ MySQL 8.0 + Redis
主資料庫使用 MySQL 8.0 進行事務處理,Redis 作為快取和 session 存儲,MongoDB 處理非結構化數據。
🔍 Elasticsearch
全文搜索引擎,支援商品搜索、用戶搜索,提供高效的索引和查詢能力。
⚡ Sidekiq
背景任務處理,包含 100+ 種不同的 Worker,處理郵件發送、支付處理、報表生成等異步任務。
🌐 React + Shakapacker
現代化前端技術棧,Shakapacker 取代 Webpacker,提供更好的構建效能和開發體驗。
🎨 Tailwind CSS
實用優先的 CSS 框架,提供一致的設計語言和響應式佈局支援。
核心設計模式
🎯 Strategy Pattern - 支付處理器策略
Gumroad 需要支援多種支付處理器(Stripe、PayPal、Braintree),每個處理器有不同的 API 和處理流程。Strategy Pattern 讓系統能夠在運行時動態選擇適合的支付策略,而無需修改現有代碼。
主要優勢:
- 支援動態切換支付處理器
- 新增支付方式時無需修改現有代碼
- 統一的支付介面簡化業務邏輯
- 每個策略獨立測試和維護
🔧 ChargeProcessor 策略實作
module ChargeProcessor
# 支付處理器映射表
CHARGE_PROCESSOR_CLASS_MAP = {
StripeChargeProcessor.charge_processor_id => StripeChargeProcessor,
BraintreeChargeProcessor.charge_processor_id => BraintreeChargeProcessor,
PaypalChargeProcessor.charge_processor_id => PaypalChargeProcessor,
}.freeze
def self.create_payment_intent_or_charge!(
merchant_account, chargeable, amount_cents, amount_for_gumroad_cents,
reference, description, metadata: nil
)
charge_processor = get_charge_processor(merchant_account.charge_processor_id)
chargeable_for_charge_processor = chargeable.get_chargeable_for(merchant_account.charge_processor_id)
charge_processor.create_payment_intent_or_charge!(
merchant_account, chargeable_for_charge_processor,
amount_cents, amount_for_gumroad_cents, reference, description,
metadata: metadata
)
end
def self.get_charge_processor(charge_processor_id)
charge_processor_class = CHARGE_PROCESSOR_CLASS_MAP[charge_processor_id]
return charge_processor_class.new if charge_processor_class
nil
end
end
這段程式碼展示了 Gumroad 如何透過策略模式統一管理多種支付處理器,系統可以根據商戶帳戶類型動態選擇合適的支付策略。
Strategy Pattern 類別圖
🏢 Service Layer Pattern - 業務邏輯服務層
Gumroad 擁有複雜的業務邏輯,如產品複製、稅務計算、郵件處理等。Service Layer Pattern 將這些業務邏輯從 Controller 和 Model 中抽離出來,形成獨立的服務類別,提高代碼的可讀性和可測試性。
主要優勢:
- 業務邏輯集中管理,便於維護和測試
- Controller 保持簡潔,專注於請求處理
- Service 可以在不同 Controller 間重用
- 複雜操作的事務管理更加清晰
🔧 ProductDuplicatorService 實作
class ProductDuplicatorService
REDIS_STORAGE_NS = Redis::Namespace.new(:product_duplicator_service, redis: $redis)
TIMEOUT_FOR_DUPLICATE_PRODUCT_CACHE = 10.minutes
attr_reader :product, :duplicated_product
def initialize(product_id)
@product = Link.find(product_id)
@product_file_external_ids_mapping = {}
end
def duplicate
ApplicationRecord.connection.stick_to_primary!
ApplicationRecord.connection.transaction do
@duplicated_product = product.dup
duplicated_product.name = "#{product.name} (copy)"
mark_duplicate_product_as_draft
duplicated_product.save!
duplicate_prices
duplicate_product_files
duplicate_rich_content(original_entity: product, duplicate_entity: duplicated_product)
duplicate_offer_codes
duplicate_variant_categories_and_variants
end
set_recently_duplicated_product
duplicated_product
end
private
def duplicate_product_files
product.product_files.alive.each do |product_file|
new_product_file = product_file.dup
new_product_file.link = duplicated_product
new_product_file.is_linked_to_existing_file = true
new_product_file.save!
@product_file_external_ids_mapping[product_file.external_id] = new_product_file.external_id
end
end
end
此服務類別封裝了產品複製的複雜邏輯,包括檔案複製、關聯資料處理、Redis 快取管理等,確保操作的原子性和一致性。
Service Layer Pattern 類別圖
👁️ Observer Pattern - 郵件送達觀察者
Gumroad 需要追蹤郵件送達狀態、處理客戶郵件資訊等。Observer Pattern 讓系統能夠在郵件送達時自動觸發相關的業務邏輯,而無需在郵件發送代碼中硬編碼這些處理邏輯。
主要優勢:
- 鬆散耦合的事件驅動架構
- 新增觀察者時無需修改主要邏輯
- 事件處理邏輯獨立且可重用
- 便於測試和維護各個觀察者
🔧 EmailDeliveryObserver 實作
class EmailDeliveryObserver
def self.delivered_email(message)
EmailDeliveryObserver::HandleEmailEvent.perform(message)
EmailDeliveryObserver::HandleCustomerEmailInfo.perform(message)
end
end
ActionMailer::Base.register_observer(EmailDeliveryObserver)
簡潔的觀察者實作展示了如何在郵件送達時同時觸發多個處理邏輯,保持系統的模組化和可擴展性。
Observer Pattern 類別圖
🔄 State Machine Pattern - 用戶風險狀態管理
Gumroad 需要管理用戶的風險狀態,從初始的未審核狀態到合規狀態,或是欺詐嫌疑狀態等。State Machine Pattern 確保狀態轉換的合法性和業務邏輯的正確執行。
主要優勢:
- 狀態轉換規則明確且可視化
- 防止非法的狀態轉換
- 狀態變更時自動執行相關邏輯
- 便於追蹤和審計狀態變更歷史
🔧 User Risk State Machine 實作
class User < ApplicationRecord
state_machine(:user_risk_state, initial: :not_reviewed) do
before_transition any => %i[suspended_for_fraud suspended_for_tos_violation],
:do => :invalidate_active_sessions!
after_transition any => %i[suspended_for_fraud suspended_for_tos_violation],
:do => :disable_links_and_tell_chat
after_transition any => :compliant, :do => :enable_refunds!
event :mark_compliant do
transition all => :compliant
end
event :flag_for_fraud do
transition %i[not_reviewed compliant] => :flagged_for_fraud
end
event :suspend_for_fraud do
transition %i[flagged_for_fraud] => :suspended_for_fraud
end
end
private
def disable_links_and_tell_chat
links.each(&:disable!)
SlackMessageWorker.perform_async("User #{id} suspended")
end
end
State Machine 確保用戶風險狀態的變更遵循預定義的規則,並在狀態轉換時自動執行相關的業務邏輯,如停用商品連結、發送通知等。
State Machine Pattern 類別圖