- Câu chuyện phát triển dự án LegiNote 1 - Ý tưởng
- StatPan đã bắt đầu dự án LegiNote với mục tiêu nâng cao khả năng tiếp cận với các dự luật và biên bản họp của Quốc hội và sử dụng AI để cải thiện hiệu quả lập pháp.
Bài viết được dịch bởi AI.
Bài viết được tóm tắt bởi durumis AI
- Dự án LegiNote sử dụng Svelte, Rust, Go, Python để phát triển dịch vụ web, trong đó Worker được viết bằng Go có vai trò thu thập và cập nhật dữ liệu từ OpenAPI.
- Worker thực hiện các chức năng như thiết lập logic thu thập dữ liệu, thực thi và tải dữ liệu lên cơ sở dữ liệu, đồng thời hướng đến khả năng mở rộng cho nhiều API khác nhau.
- Dự án được cấu trúc theo cách phân chia từng thư mục cho từng chức năng nhằm giảm thiểu sự phụ thuộc, sử dụng PostgreSQL, pq, sqlx để kết nối và xử lý truy vấn cơ sở dữ liệu.
Xin chào, tôi là StatPan.
Tôi đang viết nhật ký phát triển của dự án phụ LegiNote.
Hãy tham khảo liên kết sau đây để biết thêm về các phần trước.
Kiến trúc cơ bản
Thiết kế Leginote được tài trợ bởi 태양토끼님
Leginote được thiết kế để phát triển thành một dịch vụ web, và dự kiến sẽ sử dụng các công nghệ sau đây.
Frontend: Svelte
Backend: Rust (đang xem xét sử dụng rupring, nhưng có thể thay đổi)
Worker: Go (theo đuổi việc sử dụng std tối đa, ngoại trừ các phụ thuộc bắt buộc)
Phân tích dữ liệu: Python (từ xử lý trước đến tích hợp AI trong tương lai)
Trong số các công nghệ trên, tôi sẽ tập trung vào việc phát triển các phần Worker và Phân tích dữ liệu - những lĩnh vực mà tôi đóng góp nhiều nhất, và sẽ đăng tải nhật ký phát triển liên quan đến chúng.
Trước tiên, hãy cùng tìm hiểu về Worker.
Worker
Lựa chọn ngôn ngữ
logo golang
Tôi bắt đầu với việc lập trình bằng Python và hiện tại công việc chính của tôi là trong lĩnh vực Khoa học dữ liệu, vì vậy Python là ngôn ngữ tôi quen thuộc nhất. Tuy nhiên, chỉ biết ngôn ngữ kịch bản thôi chưa đủ, tôi bắt đầu muốn có một ngôn ngữ biên dịch mạnh mẽ, và bắt đầu quan tâm đến Go và Rust.
Đặc biệt, ngôn ngữ tôi theo dõi sát sao trong thời gian gần đây là Rust, và thường được nhắc đến cùng với C++ và Golang. (C++ cũng là một ngôn ngữ tuyệt vời, nhưng tôi đã loại trừ nó khỏi các dự án phát triển dịch vụ mạng này. Tôi không chắc liệu mình có sử dụng nó trực tiếp trong tương lai hay không, trừ khi phải làm việc với các framework học máy ở cấp độ sâu hơn).
Sau khi học Rust và Golang, và thử nghiệm chúng với các yêu cầu mạng cơ bản, tôi đã có cái nhìn sơ bộ về ưu và nhược điểm của cả hai. Bài viết này sẽ không đi sâu phân tích ưu nhược điểm của chúng, vì sẽ làm bài viết dài dòng. Tôi nghĩ rằng nên có một bài viết riêng để giải thích chi tiết hơn. Nói tóm tắt lại thì
Trong lĩnh vực mạng, có thể cấu hình mà không cần thêm phụ thuộc, và đối với một dự án không chắc chắn về doanh thu như thế này,Golangđược chọn làm ngôn ngữ phát triển.
Vai trò của Worker
Giao diện OpenAPI
Vai trò của Worker là thu thập và cập nhật dữ liệu thông qua trang web OpenAPI định kỳ, có thể chia thành 3 phần sau:
1. Thiết lập logic thu thập cho thông tin cụ thể
2. Thiết lập trình chạy để thực hiện logic thu thập
3. Lưu trữ dữ liệu thu thập vào cơ sở dữ liệu
Mục tiêu là áp dụng và mở rộng 3 bước trên cho nhiều API dữ liệu khác nhau.
Phương án cấu trúc dự án
Có nhiều kiến trúc khác nhau có thể được sử dụng để cấu trúc dự án, đặc biệt là khi sử dụng các framework, có thể giúp bắt đầu dự án với cấu trúc sẵn có. Tuy nhiên, như đã đề cập ở trên, mục tiêu của dự án này là tối thiểu hóa phụ thuộc trong quá trình phát triển, vì vậy tôi muốn tách các thư mục theo chức năng, sao cho gần với logic đã được định nghĩa.
Dự án được cấu trúc như sau:
leginote-worker-bill/
├── main.go
├── api/
│ └── client.go
├── db/
│ ├── connection.go
│ └── repository.go
├── util/
│ ├── error.go
│ └── runner.go
│ └── config.go
├── worker/
│ └── worker.go
├── go.mod
└── go.sum
api - Việc thu thập dữ liệu được thực hiện thông qua OpenAPI của dữ liệu công khai. Do đó, mã cơ bản để giao tiếp với OpenAPI sẽ nằm trong thư mục api. Hiện tại, chỉ có một API chính được sử dụng, vì vậy chỉ có một tệp client duy nhất.
db - Logic giao tiếp với DB được định nghĩa ở đây. Mã bên trong connection chỉ chịu trách nhiệm kết nối, trong khi repository chứa logic thực thi các câu lệnh SQL upsert khác nhau. Việc có các câu lệnh SQL trực tiếp trong mã là quá phức tạp, vì vậy tôi dự định sẽ tạo các tệp riêng cho SQL sau này.
util - Nơi định nghĩa các logic hỗ trợ khác nhau trong quá trình thực hiện công việc. error là một script tạm thời được tạo ra để xử lý kết quả lỗi từ go một cách thuận tiện. Như sẽ được đề cập trong các phần tiếp theo của nhật ký phát triển, điều này sẽ dẫn đến một hiệu ứng domino đáng kể (?)
Tệp config được tạo để đọc tệp .env mà không cần sử dụng gói riêng, và nó chứa hàm đọc tệp .env được định nghĩa trực tiếp.
worker - Chứa logic chính để sử dụng logic api và db một cách phù hợp và tạo ra các hành vi mong muốn. Khi có thêm nhiều loại worker, nó cũng sẽ cần phải được mở rộng tương ứng. Tuy nhiên, hiện tại chỉ có một hành vi worker chính.
Trong tương lai, tôi dự định sẽ tiếp tục phát triển mã dựa trên các nguyên tắc của kiến trúc phân lớp.
Phụ thuộc của dự án
pq để sử dụng postgres
sqlx để sử dụng truy vấn
Kết thúc Worker
Chỉ liệt kê lý thuyết mà không có mã nguồn nghe có vẻ không thú vị lắm, và tôi cũng thấy hơi nhàm chán, nên tôi sẽ kết thúc phần này một cách nhanh chóng.
Phần 2 đã kết thúc rồi đấy. Tôi hy vọng rằng từ phần 3 trở đi, tôi có thể đưa thêm một vài dòng mã để thảo luận cho sinh động hơn.
Trong quá trình phát triển Leginote, nếu bạn có bất kỳ tính năng nào cho rằng cần thiết, hoặc có bất kỳ câu hỏi nào về quá trình phát triển, đừng ngần ngại để lại bình luận nhé!