Bài viết được sự cho phép của tác giả Huỳnh Quán Cẩm
Có một thủ pháp thường hay được sử dụng khi deploy app là chạy database migration ngay khi deploy, nhưng liệu đó có phải là một good practice (tam dịch: cách làm tốt) hay không?
Tất nhiên, để đảm bảo tính khách quan, mình giữ lập trường “câu trả lời vẫn luôn là còn tùy”, nhưng 99.9999% trường hợp là KHÔNG.
Xem thêm các việc làm database hấp dẫn tại TopDev
Giả sử ta có một app cần phải đổi tên cột dob
của bảng users
thành date_of_birth
.
Dễ ợt như a ă â đúng không, ta chỉ cần một đoạn code migration như sau.
def change
rename_column "users", :dob, :date_of_birth
end
Và trong đoạn code trả về cho người dùng.
# trước khi sửa
render_json({id: user.id, date_of_birth: user.dob})
# sau khi sửa
render_json({id: user.id, date_of_birth: user.date_of_birth})
Như đầu đề, ta sẽ chạy migration code cùng lúc với deploy. Có thể nó khá phức tạp tùy theo từng app nhưng chung quy lại gồm 3 bước: a) Kéo code mới từ SCM về b) chạy đoạn code migration ở trên và c) restart lại ứng dụng để áp dụng mã mới.
Vậy thì vấn đề của cách làm trên là ở đâu?
Vấn đề
Có thể bạn sẽ để ý được là ở khoảng thời gian sau b) cho tới khi c) kết thúc, phần API đọc và ghi users của bạn sẽ bị lỗi không ngừng nghỉ với rate là 100%, lý do là vì lúc đó cột dob
đã bị gỡ khỏi database nhưng code mới thì chưa được release lên.
Đương nhiên bạn có thể đảo ngược thứ tự giữa b) và c) nhưng vấn đề không đổi, cột date_of_birth
chưa được tạo.
Là một lập trình viên, đôi lúc bạn sẽ nghĩ là vài giây đó thì thấm tháp vào đâu, nhưng chắc chắn 99.99% đồng nghiệp của bạn đang làm cho bộ phận tiếp nhận phàn nàn từ khách hàng sẽ nghĩ khác, những phần tử trong 0.001% còn lại (ừ thì 1 + 1 = 3) chắc hết chiều hôm đó thôi việc.
Giải pháp
Không có một giải pháp chuẩn nào cho việc này cả nhưng nói một cách hàn lâm thì quy tắc chung là:
Đảm bảo bản deploy hiện tại tương thích với bản deploy trước ở bất kì thời điểm nào của deploy.
Vậy với vấn đề ở trên (định dùng chữ bài toán nhưng sợ bạn rule keeper ở #random phàn nàn) cách giải quyết là chia thành nhiều bản deploy nhỏ (chú ý mỗi bước sau đây là một bản deploy).
a) tạo ra cột date_of_birth
trong bảng users
.
b) sửa đoạn code ghi ngày sinh và đoạn code đọc ngày sinh.
## ghi
User.update(user_id, date_of_birth: params[:dob])
## đọc
user = User.read(user_id)
date_of_birth = user.date_of_birth || user.dob
render_json({id: user.id, date_of_birth: date_of_birth)
c) Viết đoạn script migrate tất cả dữ liệu từ dob
qua date_of_birth
.
d) Xóa đoạn code đọc đi (đừng xóa đoạn viết nếu bạn không muốn đồng nghiệp quay qua hỏi thăm bằng tiếng Đan Mạch).
e) Tạo migration để xóa cột dob
.
Kết luận
Quản lý database schema là một vấn đề khó và đòi hỏi sự cẩn thận, tốt nhất là bạn nên đùn công việc này cho người khác nếu có thể (troll đó cơ mà nếu đùn được thì tốt).
Các bước thực hiện có thể sẽ khác nhau tùy trường hợp nhưng ý tưởng cơ bản thì là như trên, bạn có thể xào nấu lại tùy thích.
Lời cuối: Chúc chúng ta không bị banh server và ngủ ngon mỗi đêm.
Bài viết gốc được đăng tải tại quan-cam.com
Có thể bạn quan tâm:
- Gặp gỡ Nguyễn Sơn Tùng CTO Viec.co – Quán quân StartupViet 2019
- Database conventions
- Kinh nghiệm vận hành MySQL – Chú ý khi chọn MySQL làm database
Xem thêm Việc làm IT hấp dẫn tại TopDev