Skip to content

Tầng DAO

Tầng DAO (Data Access Object) nằm dưới biz/dal/ và tách biệt phần lưu trữ khỏi business logic. Nó nhóm các data access object theo loại backend, đăng ký chúng qua một manager trung tâm, và giữ các cấu trúc dữ liệu trong các package models/do/ riêng. ftkit verify thực thi các quy ước dưới đây.

Bố cục

Tầng data access nằm dưới biz/dal/:

text
biz/dal/
├── dao/                  # các data access object, nhóm theo loại backend
│   ├── managers.go       #   registry DAO: hằng số, init(), RegisterDAO
│   ├── redis_dao/        #   các cache DAO (Redis)
│   ├── mongo_dao/        #   các DAO MongoDB
│   ├── mysql_dao/        #   các DAO MySQL
│   ├── postgres_dao/     #   các DAO PostgreSQL
│   ├── cql_dao/          #   các DAO Cassandra/CQL
│   └── elastic_dao/      #   các DAO Elasticsearch
├── models/               # model lưu trữ (cấu trúc row/document của database)
└── do/                   # data object dùng bởi tầng cache

ftkit verify (verifyDAOLayer) kiểm tra rằng biz/dal/dao/ tồn tại, rằng dao/managers.go có mặt, và nhận diện các thư mục con theo loại DAO liệt kê ở trên (redis_dao, mongo_dao, mysql_dao, postgres_dao, cql_dao, elastic_dao). Nó cũng tìm biz/dal/models/.

Giống như controller, file DAO mô tả logic truy cập, không phải dữ liệu. verifyNoDataStructs từ chối bất kỳ struct nào trong file DAO có tên không kết thúc bằng DAO / Dao hoặc Cache; mọi cấu trúc khác thuộc về biz/dal/do hoặc biz/dal/models.

Manager

dao/managers.go là registry đặt tên cho mọi backend và đăng ký các DAO factory. ftkit verify tìm ba thứ trong đó:

  • Hằng số — các định danh kết thúc bằng _CACHE, _DB, hoặc _STO đặt tên cho từng backend cache, database, và storage.
  • init() — hàm nơi việc đăng ký diễn ra lúc package được load.
  • RegisterDAO — các lời gọi đăng ký gắn mỗi DAO factory với backend của nó.
go
// biz/dal/dao/managers.go
package dao

const (
    SERVICE_CACHE = "service.cache"
    SERVICE_DB    = "service.db"
    SERVICE_STO   = "service.sto"
)

func init() {
    RegisterDAO(SERVICE_DB, func() any { return mongo_dao.NewOrdersDAO() })
    RegisterDAO(SERVICE_CACHE, func() any { return redis_dao.NewOrdersCache() })
}

Quy tắc import

Các package DAO chỉ được import các package dữ liệu phù hợp với tầng của nó. Đây là chuẩn dự kiến (check tương ứng trong verifier, verifyDAOImportRules, hiện đang bị tắt trong mã nguồn qua một guard if false, nhưng nó tài liệu hóa quy tắc mà bố cục được xây dựng dựa trên):

  • DAO databasemongo_dao, mysql_dao, postgres_dao, cql_dao, elastic_daochỉ import biz/dal/models, không bao giờ import biz/dal/do. DAO database làm việc với các model lưu trữ.
  • DAO cacheredis_dao — được import cả biz/dal/models lẫn biz/dal/do, vì tầng cache làm việc với cả data object (do) lẫn model.

Tuân theo quy tắc này giữ cho hướng phụ thuộc sạch sẽ: các model lưu trữ không dính tới mối bận tâm chỉ riêng của cache, và tầng cache là nơi duy nhất bắc cầu giữa hai thứ đó.

Quyền sở hữu

Mỗi loại DAO được sở hữu bởi đúng một controller, và các hàm tương tác với một DAO nhất định nằm trong một file duy nhất. ftkit verify (verifyDAOOwnership) thu thập các struct DAO/Cache được export từ mỗi thư mục con *_dao/ và quét các controller để thực thi cả hai quy tắc:

  • Một chủ sở hữu cho mỗi DAO — nếu cùng một loại DAO được tham chiếu như một field ở nhiều hơn một domain controller, verifier báo lỗi. Mỗi DAO thuộc về một controller duy nhất.
  • Một file cho mỗi tương tác DAO — trong một package controller, các hàm gọi một DAO nhất định phải nằm hết trong một file (định nghĩa struct controller trong controller.go được loại trừ). Trải các lời gọi DAO ra nhiều file là lỗi.

Điều này giữ cho việc truy cập dữ liệu của mỗi backend được khu trú và truy vết được tới một controller duy nhất và một file duy nhất.