22 thg 10, 2025·8 phút đọc

Tiến hóa schema an toàn khi tái tạo để migration có thể dự đoán

Tiến hóa schema an toàn khi tái tạo giữ dữ liệu production hợp lệ khi mã backend được tái tạo. Tìm cách thực tế để lên kế hoạch thay đổi schema và các migration.

Tiến hóa schema an toàn khi tái tạo để migration có thể dự đoán

Tại sao thay đổi schema khiến lo lắng khi backend được tái tạo

Khi backend của bạn được tái tạo từ một mô hình trực quan, thay đổi cơ sở dữ liệu có thể giống như việc kéo một sợi chỉ trên áo len. Bạn cập nhật một trường trong Data Designer, bấm tái tạo, và đột nhiên bạn không chỉ thay đổi một bảng. Bạn còn thay đổi API được sinh ra, quy tắc xác thực, và các truy vấn mà app dùng để đọc/ghi dữ liệu.

Điều thường đi sai không phải là mã mới không thể biên dịch. Nhiều nền tảng no-code (bao gồm AppMaster, vốn sinh ra mã Go thực cho backend) sẽ vui vẻ tạo một project sạch ở mỗi lần. Rủi ro thực sự là dữ liệu production đã tồn tại, và nó không tự động biến dạng để khớp với ý tưởng mới của bạn.

Hai lỗi đầu tiên người ta thường thấy rất đơn giản:

  • Đọc bị hỏng: app không còn tải được bản ghi vì một cột di chuyển, kiểu dữ liệu thay đổi, hoặc truy vấn kỳ vọng thứ không tồn tại.
  • Ghi bị hỏng: bản ghi mới hoặc cập nhật thất bại vì ràng buộc, trường bắt buộc, hoặc định dạng thay đổi, trong khi client cũ vẫn gửi hình dạng dữ liệu cũ.

Cả hai đều đau đớn vì có thể ẩn cho đến khi người dùng thật gặp phải. Database staging có thể trống hoặc mới seed, nên mọi thứ trông ổn. Production có các trường hợp biên: NULL nơi bạn tưởng đã có giá trị, chuỗi enum cũ, hoặc các hàng được tạo trước khi quy tắc mới tồn tại.

Đó là lý do tại sao tiến hóa schema an toàn khi tái tạo quan trọng. Mục tiêu là làm cho mỗi thay đổi an toàn ngay cả khi mã backend được tái tạo hoàn toàn, để bản ghi cũ vẫn hợp lệ và bản ghi mới vẫn có thể tạo.

"Migration có thể dự đoán" đơn giản có nghĩa là bạn có thể trả lời bốn câu hỏi trước khi deploy: database sẽ thay đổi gì, điều gì sẽ xảy ra với các hàng hiện có, phiên bản app nào vẫn hoạt động trong quá trình rollout, và làm sao rollback nếu có điều không mong muốn xuất hiện.

Mô hình đơn giản: schema, migrations và mã tái tạo

Khi nền tảng có thể tái tạo backend, hữu ích khi tách ba thứ trong đầu: schema cơ sở dữ liệu, các bước migration thay đổi nó, và dữ liệu đang chạy đã có trong production. Nhầm lẫn giữa chúng là lý do khiến thay đổi cảm thấy không thể dự đoán.

Hãy nghĩ việc tái tạo như “xây lại mã ứng dụng từ mô hình mới nhất.” Trong một công cụ như AppMaster, việc xây lại đó có thể xảy ra nhiều lần trong quy trình làm việc: bạn tinh chỉnh một trường, chỉnh logic nghiệp vụ, thêm endpoint, tái tạo, test, lặp lại. Việc tái tạo diễn ra thường xuyên. Database production thì không nên như vậy.

Mô hình đơn giản như sau.

  • Schema: cấu trúc các bảng, cột, chỉ mục và ràng buộc. Là điều database mong đợi.
  • Migrations: các bước có thứ tự, có thể chạy lại để đưa schema từ phiên bản này sang phiên bản khác (và đôi khi di chuyển dữ liệu). Đây là thứ bạn chạy trên từng môi trường.
  • Dữ liệu runtime: các bản ghi thực do người dùng và các tiến trình tạo ra. Nó phải giữ hợp lệ trước, trong và sau khi thay đổi.

Mã được tái tạo nên được coi là “ứng dụng hiện tại nói chuyện với schema hiện tại.” Migrations là cầu nối giữ cho schema và dữ liệu runtime đồng bộ khi mã thay đổi.

Tại sao tái tạo thay đổi cách nhìn vấn đề

Nếu bạn tái tạo thường xuyên, bạn sẽ tự nhiên thực hiện nhiều chỉnh sửa nhỏ cho schema. Đó là bình thường. Rủi ro xuất hiện khi các chỉnh sửa đó ngụ ý một thay đổi database không tương thích ngược, hoặc khi migration của bạn không mang tính xác định.

Cách thực tế để quản lý là lập kế hoạch tiến hóa schema an toàn khi tái tạo như một chuỗi các bước nhỏ, có thể đảo lại. Thay vì một công tắc lớn, bạn thực hiện các bước có kiểm soát giữ cho mã cũ và mới cùng hoạt động trong một khoảng thời gian ngắn.

Ví dụ, nếu bạn muốn đổi tên một cột đang được API trực tiếp sử dụng, đừng đổi tên ngay lập tức. Trước hết thêm cột mới, ghi vào cả hai cột, backfill các hàng hiện có, rồi chuyển đọc sang cột mới. Chỉ sau đó mới xóa cột cũ. Mỗi bước dễ kiểm tra, và nếu có gì sai bạn có thể tạm dừng mà không làm hỏng dữ liệu.

Mô hình tư duy này giúp migrations trở nên có thể dự đoán, ngay cả khi tái tạo mã diễn ra hàng ngày.

Các loại thay đổi schema và thay đổi nào phá production

Khi backend được tái tạo từ schema mới nhất, mã thường giả định database hiện tại khớp schema đó ngay lúc này. Đó là lý do tiến hóa schema an toàn khi tái tạo không chỉ là “Chúng ta có thể thay đổi database không?” mà là “Dữ liệu cũ và các yêu cầu cũ có sống sót được trong quá trình rollout không?”

Một số thay đổi tự nhiên an toàn vì không làm vô hiệu các hàng hay truy vấn hiện có. Những thay đổi khác làm thay đổi ý nghĩa dữ liệu hoặc loại bỏ thứ app đang mong đợi, và đó là nơi xảy ra sự cố production.

Rủi ro thấp, thường an toàn (thêm tính)

Các thay đổi mang tính bổ sung dễ triển khai nhất vì chúng có thể tồn tại cùng dữ liệu cũ.

  • Bảng mới mà chưa có gì phụ thuộc.
  • Cột mới cho phép NULL và không yêu cầu default.
  • Trường API mới là tuỳ chọn end-to-end.

Ví dụ: thêm cột middle_name cho bảng users (cho phép NULL) thường an toàn. Các hàng cũ vẫn hợp lệ, mã tái tạo có thể đọc khi có dữ liệu, và hàng cũ đơn giản có NULL.

Rủi ro trung bình (thay đổi về ý nghĩa)

Những thay đổi này thường "kỹ thuật thì chạy được" nhưng có thể phá vỡ hành vi. Cần phối hợp cẩn thận vì tái tạo sẽ cập nhật validation, model sinh ra, và giả định trong logic nghiệp vụ.

Đổi tên là cái bẫy cổ điển: đổi phone thành mobile_phone có thể khiến mã được sinh ra không còn đọc phone, trong khi production vẫn có dữ liệu ở đó. Tương tự, đổi đơn vị (lưu giá theo đô-la vs cent) có thể làm sai phép tính nếu bạn cập nhật mã trước dữ liệu, hoặc dữ liệu trước mã.

Enum là một cạnh sắc. Thắt chặt enum (loại bỏ giá trị) có thể làm các hàng hiện có không hợp lệ. Mở rộng enum (thêm giá trị) thường an toàn, nhưng chỉ khi mọi luồng mã có thể xử lý giá trị mới.

Cách tiếp cận thực dụng là coi các thay đổi về ý nghĩa như "thêm mới, backfill, chuyển, rồi xóa sau."

Rủi ro cao (phá hủy)

Các thay đổi phá hủy là thứ thường phá production ngay lập tức, đặc biệt khi nền tảng tái tạo mã khiến app không còn mong đợi hình dạng cũ.

Xóa cột, xóa bảng, hoặc đổi cột từ nullable sang not-null có thể khiến ghi lỗi ngay khi có yêu cầu chèn hàng thiếu giá trị đó. Ngay cả khi bạn nghĩ “tất cả hàng đã có giá trị”, một edge case hay job nền tiếp theo có thể chứng minh điều ngược lại.

Nếu cần thay đổi thành not-null, làm theo pha: thêm cột là nullable, backfill, cập nhật logic app luôn set giá trị, rồi mới enforce not-null.

Thay đổi về hiệu năng và an toàn (có thể chặn ghi)

Chỉ mục và ràng buộc không phải là thay đổi hình dạng dữ liệu, nhưng vẫn có thể gây downtime. Tạo chỉ mục trên bảng lớn hoặc thêm ràng buộc UNIQUE có thể khoá ghi đủ lâu để gây timeout. Trong PostgreSQL, một số thao tác an toàn hơn khi làm theo phương pháp thân thiện với online, nhưng điểm chính là thời điểm: làm các thao tác nặng vào thời điểm ít traffic và đo thời gian trên bản sao staging.

Khi thay đổi cần thận trọng hơn ở production, lên kế hoạch cho:

  • Triển khai hai bước (schema trước, mã sau hoặc ngược lại) sao cho giữ tương thích.
  • Backfill chạy theo lô.
  • Kế hoạch rollback rõ ràng (sẽ ra sao nếu backend tái tạo chạy sớm).
  • Truy vấn kiểm chứng chứng minh dữ liệu khớp luật mới.
  • Ticket "xóa trường cũ sau" để dọn dẹp không nằm trong cùng một deploy.

Nếu dùng nền tảng như AppMaster tái tạo mã backend từ Data Designer, tư duy an toàn nhất: ra thay đổi mà dữ liệu cũ vẫn sống được hôm nay, rồi siết chặt quy tắc sau khi hệ thống đã thích nghi.

Nguyên tắc cho các thay đổi an toàn khi tái tạo

Backend được tái tạo rất tiện cho tới khi một thay đổi schema xuống production và các hàng cũ không khớp hình dạng mới. Mục tiêu của tiến hóa schema an toàn là đơn giản: giữ app hoạt động trong khi database và mã tái tạo theo kịp nhau bằng các bước nhỏ, có thể dự đoán.

Mặc định theo “mở rộng, migrate, thu gọn”

Coi mọi thay đổi có ý nghĩa là ba bước. Trước hết mở rộng schema để cả mã cũ và mới có thể chạy. Sau đó migrate dữ liệu. Chỉ khi đó thu gọn bằng cách xóa cột cũ, defaults hoặc ràng buộc.

Quy tắc thực tế: không bao giờ kết hợp “cấu trúc mới” và “dọn dẹp phá vỡ” trong cùng một deploy.

Hỗ trợ cả hình dạng cũ và mới trong một thời gian

Giả sử sẽ có một khoảng mà:

  • một số bản ghi có trường mới, số khác thì không
  • một số instance app chạy mã cũ, một số chạy mã tái tạo
  • job nền, import hoặc client mobile có thể chậm hơn

Thiết kế database để cả hai hình dạng đều hợp lệ trong thời gian chồng lấp đó. Điều này đặc biệt quan trọng khi nền tảng tái tạo backend từ mô hình (ví dụ, trong AppMaster khi bạn cập nhật Data Designer và tái tạo backend Go).

Làm cho đọc tương thích trước khi chuyển ghi

Bắt đầu bằng việc làm cho mã mới có thể đọc dữ liệu cũ an toàn. Chỉ sau đó chuyển các đường ghi để tạo hình dạng dữ liệu mới.

Ví dụ, nếu bạn tách một trường status thành status + status_reason, hãy ship mã có thể xử lý thiếu status_reason trước. Sau đó bắt đầu ghi status_reason cho các cập nhật mới.

Quyết định xử lý dữ liệu thiếu hoặc không rõ

Khi thêm enum, cột non-null, hoặc ràng buộc chặt hơn, quyết định trước xử lý khi giá trị thiếu hoặc bất ngờ:

  • tạm thời cho phép null, rồi backfill
  • đặt default an toàn không đổi nghĩa
  • giữ một giá trị “unknown” để tránh đọc lỗi

Điều này tránh hỏng dữ liệu im lặng (default sai) và lỗi cứng (ràng buộc mới từ chối hàng cũ).

Có phương án rollback cho mỗi bước

Rollback dễ nhất trong pha mở rộng. Nếu cần revert, mã cũ vẫn chạy trên schema mở rộng. Ghi rõ sẽ rollback gì (chỉ mã, hay mã + migration), và tránh các thay đổi phá hủy cho tới khi bạn chắc không cần undo.

Từng bước: lên kế hoạch thay đổi sống sót khi tái tạo

Duy trì tương thích trong khi cập nhật
Thêm các trường tùy chọn trước để client cũ vẫn hoạt động trong cửa sổ triển khai.
Thử AppMaster

Backend được tái tạo khó tính: nếu schema và mã sinh ra không thống nhất, production thường là nơi phát hiện trước. Cách an toàn là coi mọi thay đổi như một rollout nhỏ, có thể đảo lại, ngay cả khi bạn dùng công cụ no-code.

Bắt đầu bằng việc viết mục tiêu bằng ngôn ngữ đơn giản và dữ liệu hiện tại trông như thế nào. Chọn 3–5 hàng thực từ production (hoặc dump gần đây) và ghi những điểm lộn xộn: giá trị trống, định dạng cũ, default bất ngờ. Điều này ngăn bạn thiết kế một trường mới hoàn hảo mà dữ liệu thực không đáp ứng được.

Đây là trình tự thực tế khi nền tảng tái tạo backend (ví dụ AppMaster tái tạo backend Go từ Data Designer):

  1. Mở rộng trước, không thay thế. Thêm cột hoặc bảng mới theo cách bổ sung. Làm trường mới cho phép NULL ban đầu, hoặc cho default an toàn. Nếu giới thiệu quan hệ mới, cho phép khoá ngoại rỗng cho tới khi bạn populate.

  2. Triển khai schema mở rộng mà không xóa gì. Áp thay đổi database khi mã cũ vẫn hoạt động. Mục tiêu: mã cũ vẫn ghi các cột cũ và database chấp nhận.

  3. Backfill bằng job có kiểm soát. Điền trường mới bằng batch có thể theo dõi và chạy lại. Giữ idempotent (chạy hai lần không làm hỏng). Chạy dần cho bảng lớn và log số hàng đã cập nhật.

  4. Chuyển đọc trước, với fallback. Cập nhật logic tái tạo để ưu tiên trường mới nhưng fallback về trường cũ nếu thiếu. Chỉ sau khi đọc ổn định, chuyển viết sang trường mới.

  5. Dọn dẹp sau cùng. Khi tin tưởng (và có kế hoạch rollback), xóa trường cũ và siết ràng buộc: đặt NOT NULL, thêm ràng buộc UNIQUE, enforce foreign key.

Ví dụ cụ thể: bạn muốn thay status kiểu free-text bằng status_id trỏ tới bảng statuses. Thêm status_id nullable, backfill từ giá trị text, cập nhật app đọc status_id nhưng fallback về status khi null, rồi cuối cùng drop status và make status_id required. Mỗi pha giữ migration an toàn vì database tương thích ở mọi trạng thái.

Các mẫu thực tế có thể tái sử dụng

Diễn tập thay đổi trước production
Giảm bất ngờ muộn bằng cách thử các thay đổi schema trên dữ liệu thực trước khi release.
Xây giải pháp

Khi backend được tái tạo, các chỉnh sửa nhỏ có thể lan sang API, validation và form UI. Mục tiêu là thay đổi sao cho dữ liệu cũ vẫn hợp lệ trong khi mã mới được triển khai.

Mẫu 1: Đổi tên không phá vỡ

Đổi tên trực tiếp rủi ro vì bản ghi và mã cũ vẫn mong đợi trường gốc. Cách an toàn coi đổi tên như một khoảng migration ngắn.

  • Thêm cột mới (ví dụ customer_phone) và giữ cột cũ (phone).
  • Cập nhật logic để dual-write: khi lưu, ghi vào cả hai.
  • Backfill hàng hiện có để customer_phone đầy.
  • Chuyển đọc sang cột mới khi coverage cao.
  • Drop cột cũ ở release sau.

Cách này hoạt động tốt với công cụ như AppMaster nơi tái tạo rebuild data model và endpoint từ schema hiện tại. Dual-write giữ hai thế hệ mã cùng chạy trong quá trình chuyển.

Mẫu 2: Tách một trường thành hai

Tách full_name thành first_namelast_name tương tự, nhưng backfill phức tạp hơn. Giữ full_name cho tới khi chắc tách xong.

Quy tắc thực tế: đừng xoá trường gốc cho tới khi mọi bản ghi đã backfill hoặc có fallback rõ ràng. Nếu parsing thất bại, lưu nguyên chuỗi vào last_name và đánh dấu bản ghi để review.

Mẫu 3: Làm một trường thành bắt buộc

Đổi nullable thành required là vấn đề kinh điển. Thứ tự an toàn: backfill trước, enforce sau.

Backfill có thể cơ học (đặt default) hoặc do người dùng (yêu cầu bổ sung). Chỉ khi dữ liệu đầy đủ mới thêm NOT NULL và cập nhật validation. Nếu nền tảng tái tạo backend tự động thêm validation chặt hơn, tuần tự này tránh lỗi bất ngờ.

Mẫu 4: Thay đổi enum an toàn

Enum phá khi mã cũ gửi giá trị cũ. Trong chuyển đổi, chấp nhận cả hai. Nếu thay "pending" bằng "queued", giữ cả hai giá trị hợp lệ và map chúng trong logic. Khi chắc chắn không còn client gửi giá trị cũ, loại bỏ nó.

Nếu phải ship trong một release, giảm vùng ảnh hưởng:

  • Thêm trường mới nhưng giữ trường cũ, dù không dùng.
  • Dùng default ở database để inserts tiếp tục.
  • Làm mã dung hòa: đọc từ mới, fallback về cũ.
  • Thêm lớp mapping tạm (nhập giá trị cũ, lưu giá trị mới).

Những mẫu này giữ migration dự đoán được ngay cả khi mã tái tạo thay đổi hành vi nhanh.

Sai lầm phổ biến gây bất ngờ

Bất ngờ lớn nhất xảy ra khi mọi người coi tái tạo mã như nút reset ma thuật. Backend tái tạo giúp mã sạch, nhưng database production vẫn chứa dữ liệu của hôm qua, với hình dạng của hôm qua. Tiến hóa schema an toàn có nghĩa là bạn lên kế hoạch cho cả: mã mới sẽ được sinh ra và các hàng cũ vẫn nằm trong bảng.

Một cái bẫy là nghĩ nền tảng sẽ “lo migration” thay bạn. Ví dụ, trong AppMaster bạn có thể tái tạo backend Go từ Data Designer, nhưng nền tảng không thể đoán bạn muốn biến đổi dữ liệu khách hàng thực như thế nào. Nếu bạn thêm trường bắt buộc mới, bạn vẫn cần kế hoạch rõ ràng cho cách các hàng hiện có nhận giá trị.

Một bất ngờ khác là xóa hoặc đổi tên trường quá sớm. Một trường có vẻ không dùng trong UI chính nhưng vẫn bị đọc bởi báo cáo, export theo lịch, webhook, hoặc màn hình admin hiếm khi ai mở. Thay đổi trông an toàn trong test, rồi hỏng ở production vì một đường đọc bị bỏ quên.

Năm sai lầm thường khiến phải rollback nửa đêm:

  • Thay đổi schema và tái tạo mã nhưng không viết hoặc xác minh migration để làm cho hàng cũ hợp lệ.
  • Đổi tên hoặc xoá cột trước khi mọi reader và writer đã cập nhật và deploy.
  • Backfill bảng lớn mà không kiểm tra thời gian chạy và liệu nó có chặn các ghi khác.
  • Thêm ràng buộc mới (NOT NULL, UNIQUE, foreign key) rồi phát hiện dữ liệu legacy vi phạm.
  • Quên các job nền, export và báo cáo vẫn đọc trường cũ.

Một kịch bản đơn giản: bạn đổi phone thành mobile_number, thêm NOT NULL, và tái tạo. Màn hình app có thể chạy, nhưng export CSV cũ vẫn chọn phone, và hàng ngàn record có mobile_number là null. Cách khắc phục thường là thay đổi theo pha: thêm cột mới, ghi cả hai trong thời gian, backfill an toàn, rồi siết ràng buộc và xóa cột cũ khi có bằng chứng không có gì phụ thuộc.

Checklist nhanh trước khi deploy để migration an toàn hơn

Dùng nguyên tắc expand migrate contract
Thêm trường mới, backfill dữ liệu và chuyển reads an toàn với các bước triển khai rõ ràng.
Xây dựng ngay

Khi backend được tái tạo, mã có thể thay đổi nhanh, nhưng dữ liệu production không tha lỗi. Trước khi ship thay đổi schema, chạy một kiểm tra ngắn "nó có thể fail an toàn không?". Nó làm cho tiến hóa schema an toàn trở nên nhàm chán (đó là điều mong muốn).

5 kiểm tra bắt được hầu hết vấn đề

  • Kích thước và tốc độ backfill: ước lượng có bao nhiêu hàng cần cập nhật và mất bao lâu ở production. Backfill ổn ở db nhỏ có thể mất hàng giờ trên dữ liệu thực và làm app chậm.
  • Khóa và rủi ro downtime: xác định thay đổi có thể chặn ghi không. Một số thao tác (thay đổi type, alter bảng lớn) có thể giữ khoá lâu. Nếu có khả năng chặn, lên kế hoạch rollout an toàn (thêm cột trước, backfill sau, chuyển mã cuối).
  • Tương thích mã cũ vs schema mới: giả sử backend cũ có thể chạy một khoảng thời gian trên schema mới trong deploy hoặc rollback. Hỏi: version trước có đọc/ghi được không? Nếu không, cần release hai bước.
  • Default và hành vi null: với cột mới, quyết định gì xảy ra cho hàng hiện có. Là NULL hay cần default? Đảm bảo logic xử lý thiếu giá trị bình thường, đặc biệt cho flag, status và timestamp.
  • Tín hiệu giám sát cần theo dõi: chọn chính xác cảnh báo bạn sẽ theo dõi sau deploy: tỉ lệ lỗi (API failures), truy vấn DB chậm, job/queue lỗi, và các hành động người dùng quan trọng (checkout, login, submit). Cũng theo dõi lỗi im lặng như tăng đột biến lỗi validation.

Ví dụ nhanh

Nếu thêm trường bắt buộc status vào bảng orders, đừng push luôn là "NOT NULL, không default". Trước hết thêm nó là nullable với default cho hàng mới, deploy mã tái tạo xử lý thiếu status, rồi backfill các hàng cũ, và chỉ sau đó siết ràng buộc.

Trong AppMaster, tư duy này đặc biệt hữu ích vì backend có thể được tái tạo thường xuyên. Coi mỗi thay đổi schema như một release nhỏ có rollback dễ, và migrations của bạn sẽ giữ được tính dự đoán.

Ví dụ: tiến hóa app đang chạy mà không phá các bản ghi hiện có

Luyện tập các migration có thể dự đoán
Tạo backend sẵn cho staging và tiến hóa trường dữ liệu bằng các bước nhỏ, có thể đảo lại.
Bắt đầu xây dựng

Giả sử một công cụ hỗ trợ nội bộ nơi agent gắn thẻ ticket bằng trường text priority (ví dụ: "high", "urgent", "HIGH", "p1"). Bạn muốn chuyển sang enum chặt để báo cáo và rule routing không phải đoán.

Cách an toàn là thay đổi qua hai release giữ lại bản ghi cũ hợp lệ khi backend tái tạo.

Release 1: mở rộng, viết cả hai, và backfill

Bắt đầu bằng mở rộng schema mà không xóa gì. Thêm trường enum mới, ví dụ priority_enum với giá trị low, medium, high, urgent. Giữ trường priority_text ban đầu.

Rồi cập nhật logic để bản mới và bản sửa ghi vào cả hai. Trong công cụ no-code như AppMaster, điều này thường là chỉnh Data Designer và Business Process để map input vào enum đồng thời lưu text gốc.

Tiếp đó backfill ticket cũ theo lô nhỏ. Map các text phổ biến sang enum ("p1" và "urgent" -> urgent, "HIGH" -> high). Những giá trị lạ tạm map sang medium để review sau.

Người dùng thấy gì: lý tưởng là không gì thay đổi. UI vẫn hiển thị control priority giống trước, nhưng phía sau bạn đang populate enum mới. Báo cáo có thể bắt đầu dùng enum khi backfill đang chạy.

Release 2: thu gọn và loại bỏ đường cũ

Khi tự tin, chuyển đọc chỉ dùng priority_enum, cập nhật filter và dashboard, rồi drop priority_text ở migration sau.

Trước Release 2, validate bằng mẫu nhỏ:

  • Chọn 20–50 ticket khác đội và thời gian.
  • So sánh priority hiển thị với giá trị enum lưu.
  • Kiểm tra đếm theo enum để phát hiện spike bất thường (ví dụ quá nhiều medium).

Nếu có vấn đề, rollback đơn giản vì Release 1 giữ trường cũ: deploy lại Release 1 và set UI đọc priority_text trong khi sửa mapping và chạy lại backfill.

Bước tiếp theo: biến tiến hóa schema thành thói quen tái lặp được

Nếu muốn migrations dự đoán được, coi thay đổi schema như một dự án nhỏ, không phải sửa nhanh. Mục tiêu: mỗi thay đổi dễ giải thích, dễ diễn tập, và khó vô ý phá.

Mô hình dữ liệu trực quan hữu ích vì nó hiển ảnh hưởng trước khi deploy. Khi thấy bảng, quan hệ và kiểu trong một chỗ, bạn nhận ra những thứ dễ bỏ sót trong script, như trường bắt buộc không có default an toàn, hoặc quan hệ sẽ bỏ lửng record cũ. Làm nhanh một pass "ai phụ thuộc vào thứ này?": API, màn hình, báo cáo, job nền.

Khi cần thay đổi một trường đang dùng, ưu tiên một khoảng chuyển ngắn với cột nhân đôi. Ví dụ, thêm phone_e164 trong khi giữ phone_raw cho 1–2 release. Cập nhật logic đọc từ trường mới khi có, fallback về cũ khi không. Ghi vào cả hai trong thời gian chuyển, sau đó xóa cột cũ khi đã xác minh backfill hoàn tất.

Kỷ luật môi trường biến ý định tốt thành release an toàn. Giữ dev, staging và prod đồng bộ, nhưng đừng coi chúng giống hệt:

  • Dev: chứng minh backend tái tạo vẫn khởi động sạch và luồng cơ bản hoạt động sau regen.
  • Staging: chạy toàn bộ kế hoạch migration trên dữ liệu giống production và kiểm tra truy vấn, báo cáo, import.
  • Production: deploy khi có kế hoạch rollback, giám sát rõ ràng và một tập kiểm tra "phải đạt" nhỏ.

Viết kế hoạch migration thành tài liệu thật sự, dù ngắn: thay đổi gì, thứ tự, cách backfill, cách xác minh, và cách rollback. Sau đó chạy end-to-end trên môi trường test trước khi chạm production.

Nếu dùng AppMaster, tận dụng Data Designer để suy nghĩ trực quan về mô hình, và để việc tái tạo giữ mã backend nhất quán với schema cập nhật. Thói quen giữ mọi migration rõ ràng: bạn có thể lặp nhanh, nhưng mỗi thay đổi vẫn có lộ trình đã lên kế hoạch cho dữ liệu production hiện có.

Dễ dàng bắt đầu
Tạo thứ gì đó tuyệt vời

Thử nghiệm với AppMaster với gói miễn phí.
Khi bạn sẵn sàng, bạn có thể chọn đăng ký phù hợp.

Bắt đầu
Tiến hóa schema an toàn khi tái tạo để migration có thể dự đoán | AppMaster