0

Code Scalability Mindset – Tư duy viết mã có khả năng mở rộng

I. Mở đầu: Tại sao phải quan tâm đến khả năng mở rộng?

Khi phát triển một ứng dụng web, bạn sẽ trải qua hai giai đoạn quan trọng: phát triển nhanh chóng và mở rộng. Giai đoạn đầu tiên có thể xử lý với các giải pháp đơn giản và tốc độ phát triển nhanh.

Tuy nhiên, khi ứng dụng có người dùng thực sự và nhu cầu mở rộng tính năng, số lượng người dùng tăng lên, dữ liệu trở nên phức tạp hơn, và các tính năng ngày càng đa dạng, hệ thống bắt đầu "căng thẳng". Lúc này, nếu không có tư duy về khả năng mở rộng, bạn sẽ phải đối mặt với việc phải viết lại toàn bộ hệ thống.

Vậy làm sao để đảm bảo mã nguồn của bạn có thể mở rộng khi ứng dụng phát triển? Câu trả lời chính là tư duy về scalability ngay từ khi viết mã.

ChatGPT Image Sep 29, 2025, 11_44_40 PM.png

📌 Scalability không chỉ là chuyện của hệ thống, mà bắt đầu từ từng dòng code.

II. Code Scalability Mindset là gì?

Code Scalability Mindset là một tư duy thiết kế giúp bạn viết mã sao cho hệ thống có thể dễ dàng mở rộng khi cần thiết. Điều này không chỉ liên quan đến việc tối ưu hóa hiệu suất mà còn bao gồm các yếu tố như bảo trì dễ dàng, dễ dàng thêm tính năng mới mà không phá vỡ các phần còn lại của hệ thống


3 yếu tố cốt lõi:

  • Modularization: Chia nhỏ ứng dụng thành các phần độc lập để có thể mở rộng từng phần mà không ảnh hưởng đến phần còn lại.
  • Maintainable: Viết mã dễ hiểu, dễ thay đổi và dễ dàng kiểm tra.
  • Performance: Đảm bảo mã không chỉ hoạt động tốt ở quy mô nhỏ mà còn ở quy mô lớn.

Trong bài viết này, chúng ta sẽ thảo luận về cách áp dụng tư duy scalability trong Ruby on Rails – một framework rất phổ biến và mạnh mẽ cho phát triển web

III. Các Nguyên Tắc Vàng Đảm Bảo Khả Năng Mở Rộng Cho Mã Nguồn

1. Modularization (Mô-đun hóa)

Tách biệt logic ứng dụng vào các module, service và concerns

Khi ứng dụng của bạn phát triển, việc để tất cả logic trong controllers hoặc models sẽ làm mã của bạn trở nên rối rắm và khó bảo trì. Việc tách logic thành các module hoặc service giúp tăng tính linh hoạt và dễ dàng mở rộng sau này.

Ví dụ:

Giả sử bạn có một ứng dụng quản lý người dùng. Nếu bạn viết tất cả logic trong UsersController, sau này khi ứng dụng có thêm yêu cầu xử lý phức tạp (như gửi email, kiểm tra hạn sử dụng mật khẩu, hoặc phân quyền), bạn sẽ dễ dàng gặp phải tình trạng mã nguồn rối ren.

Giải pháp:

Tách logic ra thành các services.

# app/services/user_registration_service.rb
class UserRegistrationService
  def initialize(user_params)
    @user_params = user_params
  end

  def call
    user = User.new(@user_params)
    if user.save
      send_welcome_email(user)
      return user
    else
      raise 'User registration failed'
    end
  end

  private

  def send_welcome_email(user)
    UserMailer.welcome_email(user).deliver_later
  end
end

Trong controller, bạn sẽ gọi service này thay vì để logic trong controller.

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def create
    user = UserRegistrationService.new(user_params).call
    render json: user, status: :created
  rescue => e
    render json: { error: e.message }, status: :unprocessable_entity
  end

  private

  def user_params
    params.require(:user).permit(:name, :email, :password)
  end
end

Khi bạn cần mở rộng hoặc thay đổi logic đăng ký người dùng, bạn chỉ cần thay đổi service mà không phải lo lắng về việc thay đổi controller hoặc model.

2. Maintainable (Dễ bảo trì và dễ mở rộng)

Khi xây dựng hệ thống có khả năng mở rộng, việc giữ mã nguồn dễ bảo trì là cực kỳ quan trọng. Điều này không chỉ có nghĩa là viết mã dễ đọc mà còn bao gồm việc testrefactor mã.

🌱 Sử dụng ActiveRecord Scopes và Validations hợp lý

Một vấn đề phổ biến trong các ứng dụng Rails là việc lặp lại các truy vấn tương tự trong nhiều nơi trong mã nguồn. Sử dụng ActiveRecord Scopes giúp bạn tái sử dụng mã một cách hiệu quả.

Ví dụ:

Giả sử bạn muốn tìm tất cả người dùng đã đăng nhập trong vòng 30 ngày qua:

# app/models/user.rb
class User < ApplicationRecord
  scope :recently_logged_in, -> { where('last_login_at > ?', 30.days.ago) }
end

Sau đó, bạn có thể gọi scope này ở bất kỳ đâu trong ứng dụng của bạn:

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.recently_logged_in
    render json: @users
  end
end

Bằng cách này, bạn giữ mã nguồn sạch sẽ và dễ bảo trì, vì bạn không phải viết lại cùng một câu truy vấn nhiều lần.

🌱 Sử dụng Concerns để Tái Sử Dụng Logic

Concerns trong Rails là một cách tuyệt vời để chia sẻ logic giữa các models, controllers, hoặc bất kỳ đối tượng nào mà không cần phải lặp lại mã. Việc này giúp mã nguồn trở nên dễ bảo trì và dễ mở rộng hơn.

Ví dụ:

Giả sử bạn có một logic tính toán điểm thưởng người dùng có thể được áp dụng trong nhiều model, chẳng hạn như User, Admin, … Thay vì viết lại logic đó trong từng model, bạn có thể sử dụng Concerns.

# app/models/concerns/rewardable.rb
module Rewardable
  extend ActiveSupport::Concern

  def calculate_rewards
    rewards = self.points * 0.1
    rewards
  end
end

# app/models/user.rb
class User < ApplicationRecord
  include Rewardable
end

# app/models/admin.rb
class Admin < ApplicationRecord
  include Rewardable
end

Cách này giúp bạn tái sử dụng logic mà không cần phải lặp lại mã trong từng model, giúp bảo trì dễ dàng hơn nếu sau này có thay đổi về cách tính điểm thưởng.

🌱 Dùng Callbacks Cẩn Thận để Quản Lý Logic

Rails hỗ trợ callbacks (như before_save, after_create, v.v.) để xử lý logic trước hoặc sau các hành động của model. Tuy nhiên, quá nhiều callbacks có thể làm mã trở nên khó hiểu và khó bảo trì.

Hãy đảm bảo chỉ sử dụng callbacks khi thực sự cần thiết. Nếu quá phức tạp, hãy cân nhắc tách riêng logic ra ngoài model.

Ví dụ:

# app/models/user.rb
class User < ApplicationRecord
  before_save :downcase_email

  private

  def downcase_email
    self.email = email.downcase
  end
end

Việc sử dụng callback này giúp tự động chuyển đổi email thành chữ thường trước khi lưu vào cơ sở dữ liệu. Tuy nhiên, nếu có quá nhiều logic phức tạp trong các callbacks, mã nguồn sẽ trở nên khó theo dõi. Trong những trường hợp như vậy, chuyển logic sang service objects hoặc Jobs có thể là một giải pháp tốt.

3. Performance (Hiệu suất và tối ưu)

Tối ưu hóa hiệu suất là một phần không thể thiếu khi nói đến scalability. Ruby on Rails cung cấp nhiều công cụ để giúp bạn tối ưu hóa truy vấn cơ sở dữ liệu và giảm thiểu thời gian phản hồi của ứng dụng.

🌱 Sử dụng Eager Loading

Khi bạn làm việc với quan hệ giữa các model trong Rails, bạn có thể gặp phải vấn đề N+1 query, tức là việc thực hiện quá nhiều truy vấn cho một tập hợp các đối tượng.

Giải pháp đơn giản là sử dụng eager loading.

Ví dụ:

Giả sử bạn muốn lấy tất cả các bài viết và tác giả của chúng:

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.includes(:author).all
    render json: @posts
  end
end

Ở đây, includes(:author) sẽ giúp Rails eager load tác giả của từng bài viết, thay vì thực hiện một truy vấn riêng biệt cho mỗi tác giả.

🌱 Một kỹ thuật quan trọng khác để tối ưu hóa hiệu suất là caching.

Ví dụ:

Giả sử bạn muốn cache kết quả một trang danh sách sản phẩm:

# app/controllers/products_controller.rb
class ProductsController < ApplicationController
  def index
    @products = Rails.cache.fetch('all_products', expires_in: 12.hours) do
      Product.all
    end
    render json: @products
  end
end

Bằng cách này, bạn sẽ không phải truy vấn cơ sở dữ liệu mỗi lần người dùng truy cập trang này, giúp tiết kiệm tài nguyên và tăng tốc độ phản hồi.

IV. Kết luận

Tư duy code scalability không chỉ là viết mã hoạt động tốt trong giai đoạn hiện tại mà còn phải nghĩ tới khả năng phát triển và mở rộng của hệ thống trong tương lai. Với Ruby on Rails, bạn có rất nhiều công cụ mạnh mẽ để áp dụng tư duy này – từ modularization, service objects, cho đến các kỹ thuật tối ưu hiệu suất như eager loading và caching.

Khi xây dựng một ứng dụng với khả năng mở rộng, hãy luôn nhớ rằng việc thiết kế mã có khả năng mở rộng từ đầu sẽ giúp bạn tiết kiệm rất nhiều thời gian và công sức khi hệ thống của bạn phát triển.

Hy vọng bài viết này của mình sẽ giúp mọi người hiểu thêm về Code Scalability Mindset và cách áp dụng nó trong dự án. Hãy bắt đầu áp dụng các phương pháp này để đảm bảo ứng dụng của chúng ta có thể dễ dàng mở rộng và duy trì trong tương lai nhé, tạm biệt.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí