DataOps nâng cao 27 — BI-as-code & kiểm thử tầng phục vụ
Điểm mù cuối đường ống: tầng phục vụ
Hầu hết công sức DataOps đổ vào phần "trước": ingest, transform, test dữ liệu trong warehouse. Đến cuối đường ống — nơi con số chạm mắt người ra quyết định — kỷ luật thường tan biến. Ai đó vào Looker/Superset/Power BI kéo thả vài field, gõ một công thức, lưu lại. Không review, không version, không test. Dashboard là sản phẩm dữ liệu cuối cùng, nhưng lại là thứ được quản trị lỏng lẻo nhất.
Hệ quả rất quen: pipeline xanh sạch, mọi test dbt pass, nhưng dashboard giao ban hiện số sai. Nguyên nhân không nằm ở data — nó nằm ở tầng phục vụ: một field bị đổi tên trong mart khiến chart lặng lẽ trả rỗng; một người sửa filter "dư nợ nhóm 2" rồi quên; hai chart cùng tên "CASA" tính bằng hai công thức khác nhau; một dashboard được clone 20 lần, mỗi bản trôi một hướng. Pipeline tốt không cứu được một tầng BI vô kỷ luật.
Bài này áp chính xác cùng bộ kỷ luật DataOps — version, review, CI, test, deploy tự động, observability — lên tầng BI. Hai trụ cột: BI-as-code (định nghĩa BI dưới dạng code trong Git) và kiểm thử tầng phục vụ (test dashboard/metric như test bất kỳ artifact nào khác).
BI-as-code là gì
BI-as-code nghĩa là dashboard, metric, model BI, và cả phân quyền được định nghĩa bằng file code trong Git, thay vì cấu hình tay qua giao diện. Thay đổi đi qua pull request, được review, chạy CI, rồi deploy tự động — y như code ứng dụng.
Có hai kiểu công cụ:
| Kiểu | Công cụ | Cách "as-code" | Ghi chú |
|---|---|---|---|
| Code-native | Looker (LookML), Cube, Evidence, Lightdash | Định nghĩa gốc là file .lkml/.yml/.sql trong repo | Git là nguồn sự thật, giao diện chỉ render |
| Export/import | Superset, Metabase, Power BI | Sửa qua UI rồi export ra YAML/JSON, commit; import lại khi deploy | Cần quy trình chống trôi giữa UI và Git |
Với Looker, LookML đã là code từ đầu: view, explore, dashboard đều là file văn bản, mỗi thay đổi là một commit. Với Superset/Metabase/Power BI, định nghĩa gốc sống trong DB của công cụ, nên ta dùng cơ chế export → commit → import: Superset có superset export-dashboards/import-dashboards ra bundle YAML; Power BI có định dạng dự án .pbip (PBIR) đọc được bằng text, hợp với Git.
Vì sao phải làm vậy? Vì dashboard là sản phẩm dữ liệu, và mọi sản phẩm dữ liệu cần cùng một kỷ luật:
- Version — biết ai đổi gì, khi nào, vì sao; rollback được về bản đúng.
- Review — thay đổi định nghĩa "dư nợ nhóm 2" phải được người thứ hai (và cán bộ nghiệp vụ) duyệt trước khi lên production, không phải một cú click lặng lẽ.
- CI/test — bắt lỗi trước khi người dùng thấy số sai.
- Tái lập — dựng lại toàn bộ dashboard ở môi trường mới (dev/staging/prod, hay sau sự cố) từ code, không phải "click lại từ trí nhớ".
Cấu hình tay thì trôi: không ai nhớ vì sao chart này lọc thêm một điều kiện, bản staging và prod lệch nhau, và mỗi dashboard trở thành một hộp đen.
Ví dụ định nghĩa as-code
Một explore và metric trong LookML (minh hoạ, không phải block chạy được):
# file: dư_nợ.view.lkml — minh hoạ
view: du_no {
sql_table_name: marts.fact_du_no ;;
dimension: nhom_no {
type: number
sql: ${TABLE}.nhom_no ;;
}
measure: tong_du_no {
label: "Tổng dư nợ"
type: sum
sql: ${TABLE}.du_no_goc ;;
value_format_name: decimal_0
}
measure: du_no_nhom_2 {
label: "Dư nợ nhóm 2"
type: sum
sql: ${TABLE}.du_no_goc ;;
filters: [nhom_no: "2"] # định nghĩa 1 lần, mọi chart dùng chung
}
}
Một dashboard Superset export ra YAML (minh hoạ):
# dashboard_bao_cao_giam_sat.yaml — minh hoạ
dashboard_title: "Báo cáo giám sát tín dụng"
slug: bao-cao-giam-sat
metadata:
refresh_frequency: 3600
charts:
- slug: du-no-theo-nhom
viz_type: table
datasource: mart_du_no
metrics: [tong_du_no, du_no_nhom_2]
Điểm mấu chốt: những file này nằm trong Git, mọi thay đổi đi qua PR và CI.
Các lớp kiểm thử tầng BI
Test tầng phục vụ có nhiều lớp, mỗi lớp bắt một loại lỗi khác nhau:
1. Validator cú pháp & tham chiếu (LookML validator, CI). Looker có LookML Validator kiểm cú pháp và tham chiếu nội bộ; công cụ Spectacles chạy validation trong CI: LookML validation (cú pháp, tham chiếu), SQL validation (chạy thử SQL sinh ra từ mỗi explore để chắc nó không lỗi trên warehouse), và content validation (kiểm dashboard/look có còn tham chiếu field tồn tại không). Đây là hàng rào đầu tiên, chặn PR làm vỡ định nghĩa.
2. Content validation — field còn tồn tại. Lỗi phổ biến nhất khi refactor mart: một cột bị đổi tên/xóa ở tầng dữ liệu, còn dashboard vẫn trỏ tên cũ. Chart không báo lỗi ầm ĩ — nó lặng lẽ trả rỗng hoặc rơi field. Content validation quét mọi dashboard, phát hiện tham chiếu gãy trước khi merge PR đổi schema. Đây là cầu nối quan trọng giữa thay đổi ở tầng transform và tầng BI.
3. Data test — số trên dashboard khớp nguồn. Validator chỉ đảm bảo query chạy được, không đảm bảo con số đúng. Data test đối soát: lấy một chỉ tiêu hiển thị trên dashboard, tính lại độc lập từ nguồn (warehouse/sandbox), và so khớp. Ví dụ: tổng "dư nợ" trên dashboard phải bằng tổng tính trực tiếp từ mart. Lệch → chặn deploy. Đây là lá chắn cuối chống việc một filter/join sai làm số hiển thị lệch mà query vẫn "chạy được".
4. Visual regression — ảnh chụp dashboard đổi. Chụp ảnh dashboard render và so với ảnh baseline. Bắt lỗi mà data test bỏ sót: chart bị vỡ layout, mất chú thích, đổi loại biểu đồ ngoài ý muốn, hoặc filter mặc định sai làm biểu đồ trống. Diff ảnh > ngưỡng → cảnh báo để người duyệt xem có chủ đích hay không.
5. Performance test — truy vấn dashboard đủ nhanh. Dashboard chậm là dashboard chết. Test đo thời gian render và thời gian query của từng chart trên dữ liệu thực tế; đặt ngưỡng (VD p95 < 5s). PR làm một explore chậm gấp đôi (thêm join nặng, bỏ pre-aggregation) bị bắt trong CI thay vì khi lãnh đạo mở dashboard và bỏ cuộc.
| Lớp test | Bắt lỗi gì | Không bắt được gì |
|---|---|---|
| Validator/SQL validation | Cú pháp sai, SQL không chạy | Số sai, layout vỡ |
| Content validation | Field bị xóa/đổi tên | Số sai do logic |
| Data test đối soát | Số hiển thị lệch nguồn | Layout, tốc độ |
| Visual regression | Vỡ layout, chart trống | Số lệch trong ngưỡng ảnh |
| Performance test | Query/render chậm | Số sai, layout |
Không lớp nào đủ một mình — như pyramid test analytics, cần phối hợp: nhiều validation rẻ chạy mỗi PR, ít visual/performance đắt chạy trước release.
Block đối soát chạy được
Trọng tâm data test là tính lại độc lập con số dashboard hiển thị. Giả sử dashboard "cơ cấu tiền gửi" hiện tổng số dư và tỷ trọng theo loại tiền; ta chạy truy vấn đối soát trên sandbox để lấy con số "sự thật" đem so với dashboard:
-- ▶ Chạy được
WITH theo_tien AS (
SELECT currency, SUM(balance) AS tong_so_du, COUNT(*) AS so_tk
FROM accounts
GROUP BY currency
),
tong AS (
SELECT SUM(balance) AS tong_toan_bo FROM accounts
)
SELECT
t.currency,
t.so_tk,
ROUND(t.tong_so_du::numeric, 2) AS tong_so_du,
ROUND((100.0 * t.tong_so_du / g.tong_toan_bo)::numeric, 2) AS ty_trong_pct
FROM theo_tien t
CROSS JOIN tong g
ORDER BY tong_so_du DESC;
Con số tong_so_du và ty_trong_pct từ truy vấn này phải khớp từng đồng với ô tương ứng trên dashboard. Trong CI, ta gọi API của công cụ BI (VD Looker Query API, Superset chart data API) lấy số dashboard trả về, so với kết quả truy vấn nguồn; lệch quá ngưỡng làm bí (fail) pipeline. Đây là kiểu test reconciliation áp cho tầng phục vụ.
Nhất quán chỉ số qua semantic layer
BI-as-code giải quyết version và review, nhưng nếu mỗi dashboard vẫn tự viết lại công thức, ta chỉ version hóa sự không nhất quán. Gốc rễ của "mỗi dashboard một con số" là logic metric bị nhân bản. Lời giải là định nghĩa metric một lần ở semantic layer rồi để mọi dashboard tiêu thụ chung, thay vì mỗi chart tự SUM theo cách riêng.
Khi "dư nợ", "CASA", "khách hoạt động" được định nghĩa as-code ở tầng ngữ nghĩa, dashboard chỉ tham chiếu tên metric — không có cơ hội tính lại sai. Test đối soát ở trên khi đó test một định nghĩa duy nhất, không phải hàng chục bản sao. Đây là lý do BI-as-code và semantic layer đi cặp: một cái cho version/deploy, một cái cho tính nhất quán của con số.
CI/CD & môi trường cho BI
Áp CI/CD analytics lên BI: mỗi PR sửa file BI kích hoạt pipeline validate → test → deploy. Nên có nhiều môi trường cho tầng BI, không chỉ prod:
- Dev — nơi kỹ sư/analyst thử LookML/dashboard trên nhánh riêng, trỏ vào schema dev.
- Staging — dựng lại dashboard từ code, chạy full test suite (visual, performance) trên dữ liệu giống prod.
- Prod — chỉ deploy tự động từ nhánh chính sau khi CI xanh.
Với Looker, cơ chế branch/deploy tích hợp sẵn (development mode → commit → deploy to production). Với Superset/Power BI, pipeline chạy import bundle đã export vào từng môi trường. Nguyên tắc: không ai sửa trực tiếp trên prod — mọi thay đổi đi từ code qua pipeline, để prod luôn tái lập được từ Git.
Quản trị, phân quyền, và observability BI
Phân quyền as-code. Ai xem được dashboard nào, hàng/cột nào — cũng nên là code. LookML có access_grant/access_filter (lọc hàng theo user, VD chi nhánh); model access, connection permission khai báo trong file. Đưa phân quyền vào Git nghĩa là thay đổi quyền cũng qua review — hợp với kiểm soát truy cập và yêu cầu kiểm toán của ngân hàng.
Observability cho BI. Giống observability pipeline, tầng BI cần được quan sát:
- Hiệu năng — dashboard/chart nào chậm, query nào tốn tài nguyên (Looker System Activity, Superset query log).
- Lỗi — chart trả lỗi/rỗng, tần suất render fail.
- Usage — dashboard nào được mở, tần suất, bởi ai; đâu là dashboard chết (không ai mở nhiều tháng).
Usage analytics là công cụ chống dashboard sprawl (bùng nổ dashboard): tổ chức tích lũy hàng trăm dashboard, phần lớn là bản clone bỏ hoang hoặc trùng lặp, khiến người dùng không biết bản nào là "chính chủ". Định kỳ dùng usage data để dọn dashboard chết — archive bản không ai dùng, gộp bản trùng, giữ danh mục gọn và đáng tin. Vì dashboard là code, "xóa" là một PR có review, không phải hành động không dấu vết.
Use case thực tế
Bối cảnh. Khối giám sát NCB có một bộ dashboard báo cáo quản trị và số liệu phục vụ báo cáo NHNN (dư nợ theo nhóm, tỷ lệ nợ xấu, cơ cấu huy động). Ban đầu tất cả tạo tay trong công cụ BI: không version, ai cũng sửa được, không test. Sự cố điển hình: một analyst refactor mart, đổi cột du_no thành du_no_goc; một chart trên dashboard giám sát trỏ tên cũ nên lặng lẽ trả 0 cho một phân khúc. Không ai để ý cho tới buổi giao ban, khi con số tổng lệch — phải rà tay từng chart mất nửa ngày và giải trình vì sao báo cáo sai.
Giải pháp — chuyển dashboard giám sát sang BI-as-code.
- Đưa định nghĩa vào Git. Metric ("dư nợ nhóm 2", "tỷ lệ nợ xấu") định nghĩa một lần ở semantic layer; dashboard export ra YAML, commit vào repo. Prod chỉ deploy từ nhánh chính.
- CI nhiều lớp mỗi PR. Validator + SQL validation (query chạy được), content validation (bắt ngay tham chiếu
du_nogãy khi cột đổi tên), data test đối soát (tổng dư nợ trên dashboard phải khớp truy vấn nguồn như block chạy được ở trên), visual regression cho layout. - Review bắt buộc. Mọi thay đổi định nghĩa chỉ tiêu báo cáo NHNN cần cán bộ nghiệp vụ duyệt PR — biến "sửa dashboard" thành một quyết định có dấu vết, kiểm toán được.
- Observability + dọn dẹp. Usage report hàng quý phát hiện 40% dashboard nội bộ không ai mở > 6 tháng → archive qua PR, giảm sprawl.
Kết quả (minh hoạ, mục tiêu vận hành). Lỗi "cột đổi tên làm chart trả 0" bị bắt ngay tại PR bởi content validation thay vì lộ ở giao ban. Số trên dashboard báo cáo được đối soát tự động với nguồn mỗi lần deploy. Mọi thay đổi báo cáo NHNN có lịch sử review, rollback được. Danh mục dashboard gọn lại, người dùng tin "bản trong Git là bản đúng".
Ghi nhớ
- Tầng phục vụ là điểm mù của DataOps. Pipeline sạch không cứu được dashboard vô kỷ luật — số sai thường sinh ở tầng BI, không phải tầng data.
- BI-as-code: dashboard/metric/model/phân quyền là file trong Git → version, review, CI, tái lập. Code-native (LookML) hoặc export/import (Superset/Metabase/Power BI).
- Dashboard là sản phẩm dữ liệu — xứng đáng cùng kỷ luật version/test/deploy như code.
- Kiểm thử BI có nhiều lớp: validator/SQL validation (chạy được), content validation (field còn tồn tại), data test đối soát (số khớp nguồn), visual regression (layout), performance (đủ nhanh). Không lớp nào đủ một mình.
- Data test đối soát = tính lại độc lập con số dashboard từ nguồn rồi so khớp — lá chắn cuối chống số hiển thị lệch.
- Semantic layer là gốc của nhất quán: định nghĩa metric một lần, dashboard chỉ tham chiếu → không tính lại sai. BI-as-code lo version, semantic layer lo tính đúng.
- CI/CD + nhiều môi trường (dev/staging/prod); không sửa trực tiếp prod, mọi thay đổi qua pipeline.
- Observability BI: theo dõi hiệu năng, lỗi, usage → dọn dashboard chết, chống dashboard sprawl.
- Bối cảnh ngân hàng: dashboard báo cáo quản trị/NHNN được version & test để không hiển thị số sai; mọi thay đổi có review, kiểm toán, rollback được.
Bài viết liên quan
CSV/JSON/Parquet/Avro, lưu trữ theo hàng vs cột, nén, và OLTP vs OLAP.
Data Engineering là gì, vai trò trong vòng đời dữ liệu, và bức tranh hệ sinh thái công cụ.
Vì sao xử lý phân tán, mô hình Spark (RDD/DataFrame), lazy evaluation, shuffle và tối ưu.
Đảm bảo chất lượng & minh bạch dữ liệu bằng dbt: data tests dựng sẵn (unique, not_null, relationships, accepted_values), singular test, unit test, và tài liệu tự sinh kèm lineage graph.