Một cái client không kết nối được
Cái mysql client chuẩn không vào được database của gateway. Không phải chậm,
không phải chập chờn — nó không mở nổi connection, vì những lý do nằm ở cách
mạng được sắp xếp chứ không phải thứ gì một cái flag của client sửa được.
Thế là có một dạo, mỗi câu query là một màn xoay xở nho nhỏ. Người này có sẵn một cái GUI tình cờ chạy được. Người kia giữ một đoạn code kết nối trong file nháp. Người khác thì dán SQL vào chat, nhờ ai đang có setup còn sống hôm đó chạy hộ. Cuối cùng ai cũng có câu trả lời, nhưng mỗi câu trả lời đi một con đường hơi khác nhau. Khi đường vào bất tiện, người ta không ngừng query — người ta xoay xở, mà xoay xở thì không có hành vi chuẩn nào để mình suy luận được.
Một script thay cho năm kiểu xoay xở
Cái thay thế thì cố tình nhạt: một script nhỏ, nhận SQL, trả về rows. Nó thành tool chuẩn không phải nhờ ai ra lệnh, mà nhờ nó dễ hơn mọi kiểu xoay xở nó thay thế — gõ query, nhận kết quả, xong.
Phần đáng viết ra không phải là chuyện xử lý kết nối. Mà là những gì được xây vào trong script, thay vì phó mặc cho kỷ luật.
SELECT chạy ngay lập tức. Không hỏi, không flag, không nghi thức gì. Đọc
chiếm tuyệt đại đa số nhu cầu với cái database này, và tool đối xử với nó đúng
như vậy.
Lệnh write thì không chạy. Script nhận ra nó, dừng lại, và in hai thứ cho con người xem trước khi bất cứ gì xảy ra: cái hostname nó sắp ghi vào, và cờ read_only của server. Rồi nó đòi confirm rõ ràng. Chỉ sau một tiếng "yes" thì câu lệnh mới được thực thi.
Vì sao hai dòng đó tồn tại
Vì một cái config trên máy dev có thể đang trỏ vào production, và cái terminal
chẳng có gì mách cho bạn biết điều đó. Một file config đã commit, một file
.env copy lại, một biến shell export từ cái incident tuần trước — thứ nào
cũng có thể lẳng lặng chĩa session của bạn vào nhầm database, và với một client
trơn thì dấu hiệu đầu tiên chính là hậu quả. Đọc nhầm host thì ngượng. Ghi nhầm
host thì là câu chuyện mà đội nào rồi cũng kể lại ở thì quá khứ.
Dòng hostname trả lời câu mình đang thật sự nối vào đâu. Dòng read_only trả
lời câu đây có phải primary không — và nó bắt luôn cả cái nhầm theo chiều
ngược lại: ghi vào replica rồi ngồi thắc mắc sao dữ liệu không ăn. Chẳng check
nào trong hai cái là thông minh cả. Cả hai đúng là những check mà một người cẩn
thận sẽ tự tay chạy, mọi lần, nếu như người cẩn thận thật sự chạy check mọi
lần.
Guardrail trong tool và guardrail trong người
Họ không chạy đâu, và đó chính là bài học. Phòng tuyến cũ là kỷ luật — trước khi write phải xem mình đang ở host nào — mà kỷ luật là loại guardrail sống trong con người. Nó đứng vững vào một buổi sáng yên ả và sụp vào cuối một cái incident, khi người đang gõ câu UPDATE cũng chính là người đã mệt nhoài vì nhìn log suốt mấy tiếng. Cái script thì không quan tâm hôm nay là ngày kiểu gì. Nó in hostname cho cả người đang mệt xem.
Về bằng chứng thì mình phải nói thẳng. Không tồn tại con số nào đếm các sai lầm đã được chặn — chẳng có gì log lại khoảnh khắc ai đó đọc dòng hostname, tái mặt, rồi bấm "no". Mình không thể nói cái check này đã cứu bọn mình N lần, vì N chưa bao giờ được đo và mình sẽ không bịa nó ra. Lý do để tin nằm ở thiết kế, không phải ở thống kê: check chạy trên mọi lệnh write, con người nhìn thấy đúng hai sự thật quan trọng trước khi có gì được commit, và cái lỗi nó nhắm tới là loại lỗi mà đội nào có nhiều hơn một database rồi cũng sẽ gặp.
Cái luật
Làm cho đường an toàn thành đường dễ đi. Script thắng vì SELECT — trường hợp
phổ biến — ít ma sát hơn mọi kiểu xoay xở trước đó, nên người ta tự tìm đến
nó mà không cần ai nhắc; ma sát chỉ rơi vào đúng cái trường hợp hiếm và nguy
hiểm, với liều lượng đúng bằng mức nó đáng nhận. Guardrail sống trong tool thì
sống sót qua một ngày tồi tệ. Guardrail sống trong con người thì không — mà
ngày tồi tệ lại chính là ngày nó sinh ra để trực.