backend first
Ghi chú dạy em học theo hướng Backend trước
Tài liệu này dành cho em đang học làm web với Go.
Mục tiêu của tài liệu này không phải là dạy thật nhiều thứ cùng lúc. Mục tiêu là giữ trọng tâm đúng:
Học chắc backend Go trước.
Hiểu dữ liệu đi như thế nào trong web app.
Hiểu route, slug, database, render HTML.
Chưa sa đà vào những phần khó và dễ rối của Vue.
Trả lời ngắn gọn trước
Cách nên đi với project này là:
Admin CMS: vẫn dùng Vue.
Trang public/home: nên dùng Go render HTML từ template.
Đây là hướng tôi khuyến nghị.
Vì sao tôi khuyến nghị như vậy?
Vì mục tiêu học chính của em bây giờ là backend Go, không phải frontend framework.
Nếu dồn cả admin lẫn mặt public vào Vue quá sớm, em rất dễ bị cuốn vào:
component
state
reactive data
router frontend
build tool
debug phía browser
Những thứ đó không sai. Nhưng nó làm em mất tập trung khỏi phần cốt lõi của backend.
Vấn đề thật sự ở đây là gì?
Khi mới học, nhiều người hay nghĩ:
Làm web thì cứ dùng frontend framework cho tất cả mọi thứ.
Cách nghĩ đó rất dễ làm người mới rối.
Vì thực ra một web app thường có hai mặt rất khác nhau.
1. Mặt quản trị admin
Đây là nơi để:
đăng nhập
tạo bài viết
sửa bài viết
xoá bài viết
cập nhật project
cập nhật CV
Mặt này có nhiều tương tác, nhiều form, nhiều trạng thái.
Ví dụ:
form đang nhập dở
nút đang loading
lưu xong rồi hiện thông báo thành công
token hết hạn thì đá về login
Đó là lý do Vue hợp với admin.
2. Mặt public/home
Đây là nơi người dùng vào để đọc nội dung.
Ví dụ:
xem trang chủ
xem danh sách bài viết
xem chi tiết một bài viết
xem danh sách dự án
xem CV
Phần này thường không cần quá nhiều trạng thái phức tạp ở trình duyệt.
Nó chủ yếu là:
Người dùng mở URL.
Server lấy dữ liệu.
Server render HTML.
Server trả trang về browser.
Đây là nơi rất tốt để học backend.
Vì sao Go render HTML lại tốt cho người mới?
Vì cách này giúp em nhìn thấy rõ luồng chạy của web.
Ví dụ khi người dùng vào:
text
/bai-viet/golang-routing-voi-chiEm sẽ học được rõ ràng các bước:
Router nhận request.
Router lấy ra slug từ URL.
Controller dùng slug để tìm bài viết trong database.
Nếu không có bài viết thì trả trang 404.
Nếu có bài viết thì nạp vào template HTML.
Server trả HTML hoàn chỉnh cho trình duyệt.
Đây chính là kiến thức backend rất quan trọng.
Nếu làm hết bằng Vue quá sớm, em sẽ dễ chỉ thấy:
gọi API
nhận JSON
nhét vào component
Nhưng em không thật sự hiểu rõ phần “web server đang làm gì”.
Cách chia vai trò cho dễ học
Phần admin: dùng Vue
Vue ở đây chỉ cần làm đúng vai trò của nó:
hiện form
hiện bảng dữ liệu
gọi API backend
hiển thị thông báo lỗi/thành công
Ví dụ các API admin:
POST /api/login
GET /api/posts
POST /api/posts
PUT /api/posts/{id}
DELETE /api/posts/{id}
Ở phần này, em cần học các ý chính sau:
JWT là gì
middleware là gì
validation là gì
JSON response là gì
CRUD là gì
Phần public: dùng Go template
Phần public nên đi theo kiểu:
GET /
GET /bai-viet
GET /bai-viet/{slug}
GET /du-an
GET /cv
Ở phần này, em sẽ học các ý chính sau:
route là gì
route param là gì
slug là gì
query database như thế nào
render template như thế nào
404 page hoạt động ra sao
Slug là gì, và vì sao nó quan trọng?
slug là phần chữ gọn gàng trong URL.
Ví dụ:
text
/bai-viet/golang-routing-voi-chiTrong đó:
bai-viet là nhóm nội dung
golang-routing-voi-chi là slug
Vì sao không dùng ID ngoài public luôn?
Ví dụ URL kiểu này vẫn chạy được:
text
/bai-viet/12Nhưng nó có 3 điểm yếu:
Người đọc nhìn không hiểu bài viết nói về gì.
Link kém đẹp.
Em sẽ mất cơ hội học cách ánh xạ URL đẹp sang dữ liệu thật trong database.
URL public nên khác URL API
Ví dụ:
API admin: GET /api/posts/12
Public page: GET /bai-viet/golang-routing-voi-chi
Đây là một điểm rất quan trọng để em hiểu:
Dữ liệu nội bộ và đường dẫn public không nhất thiết phải giống nhau.
Luồng xử lý một bài viết theo slug
Đây là luồng em nên học thật kỹ:
Admin tạo bài viết mới.
Backend nhận title.
Backend tạo slug từ title.
Backend lưu bài viết vào database, gồm cả title và slug.
Người dùng mở /bai-viet/{slug}.
Router lấy slug từ URL.
Controller tìm bài viết theo slug.
Nếu không tìm thấy, trả 404.
Nếu tìm thấy, render HTML.
Ví dụ dễ hiểu
Giả sử tiêu đề bài là:
Hoc Go Router voi ChiBackend có thể biến nó thành:
/bai-viet/hoc-go-router-voi-chiKhi đó URL public sẽ là:
/bai-viet/hoc-go-router-voi-chiNên cho em học theo thứ tự nào?
Tôi khuyến nghị thứ tự này.
Bước 1: thêm slug vào model Post
Mục đích:
để bài viết có đường dẫn public đẹp
để em bắt đầu hiểu URL không chỉ là ID
Bước 2: tự động sinh slug khi tạo hoặc sửa bài
Mục đích:
giảm lỗi nhập tay
để backend nắm quyền chuẩn hoá URL
Bước 3: đặt unique cho slug
Mục đích:
tránh 2 bài viết có cùng URL
Bước 4: viết hàm tìm bài theo slug
Mục đích:
tập query dữ liệu theo trường phục vụ URL public
Bước 5: tạo route public GET /bai-viet/{slug}
Mục đích:
nối URL thật với bài viết thật
Bước 6: tạo template danh sách và chi tiết bài viết
Mục đích:
học cách server render HTML
Bước 7: tạo trang 404 riêng
Mục đích:
hiểu lỗi “không tìm thấy nội dung” là một phần bình thường của web
Cấu trúc thư mục nên đơn giản thế nào?
Không cần làm kiến trúc quá to ngay.
Có thể đi theo hướng này:
controllers/
admin_post_controller.go
public_post_controller.go
routes/
api_router.go
web_router.go
templates/
layouts/
base.html
pages/
home.html
post_list.html
post_detail.html
projects.html
cv.html
404.htmlÝ nghĩa của cách chia này
api_router.go: chứa route trả JSON cho admin hoặc frontend.
web_router.go: chứa route trả HTML cho người dùng public.
admin_post_controller.go: xử lý bài viết theo kiểu API.
public_post_controller.go: xử lý bài viết theo kiểu render trang.
Điều em học được ở đây là:
Cùng là “bài viết”, nhưng cách phục vụ cho admin và cho người đọc là khác nhau.
Đây là một ý rất quan trọng trong backend.
Ví dụ controller public rất nên cho em học
go
func ShowPostBySlug(w http.ResponseWriter, r *http.Request) {
slug := chi.URLParam(r, "slug")
post, err := findPostBySlug(slug)
if err != nil {
renderNotFound(w)
return
}
renderTemplate(w, "pages/post_detail.html", map[string]interface{}{
"Title": post.Title,
"Post": post,
})
}Đoạn này dạy được gì?
chi.URLParam(r, "slug")
Dòng này lấy giá trị slug ra từ URL.
Nếu URL là:
/bai-viet/hoc-go-routerThì slug sẽ là:
hoc-go-routerfindPostBySlug(slug)
Dòng này dùng slug để đi tìm dữ liệu thật trong database.
Đây là phần backend cốt lõi.
renderNotFound(w)
Nếu không tìm thấy bài viết, đừng để server văng lỗi mơ hồ.
Hãy trả trang 404 rõ ràng. Đây là cách xử lý đúng về mặt web.
renderTemplate(...)
Dòng này đem dữ liệu bài viết nhét vào template HTML.
Nói đơn giản:
database giữ dữ liệu thô
template biến dữ liệu đó thành trang người dùng nhìn thấy
Ví dụ template base nên dạy em
html
<!doctype html>
<html lang="vi">
<head>
<meta charset="utf-8">
<title>{{ .Title }}</title>
</head>
<body>
<nav>
<a href="/">Trang chủ</a>
<a href="/bai-viet">Bài viết</a>
<a href="/du-an">Dự án</a>
<a href="/cv">CV</a>
</nav>
<main>
{{ template "content" . }}
</main>
</body>
</html>Điều em cần hiểu ở ví dụ này
{{ .Title }} là gì?
Đó là dữ liệu server đưa vào template.
Nó không phải “HTML tự biết”. Nó là dữ liệu do backend chuẩn bị.
{{ template "content" . }} là gì?
Đây là cách chèn phần nội dung riêng của từng trang vào khung chung.
Nói ngắn gọn:
base.html là khung nhà
content là nội dung từng phòng
Đây là cách rất dễ hiểu để người mới học layout server-side.
Những gì em nên học ở admin, và những gì chưa cần học sâu
Phải học
API là gì
request body là gì
JSON response là gì
auth bằng JWT là gì
middleware chặn quyền là gì
validation dữ liệu là gì
Chưa cần đào quá sâu ngay
state management phức tạp của Vue
tối ưu component phức tạp
composable nâng cao
animation frontend
kiến trúc frontend quá lớn
Không phải vì những thứ đó không quan trọng. Mà vì chưa phải trọng tâm học lúc này.
Lỗi người mới rất hay gặp
Lỗi 1: nghĩ rằng dùng Vue cho mọi thứ là hiện đại hơn
Đây là hiểu lầm rất phổ biến.
“Hiện đại” không có nghĩa là nhét một công cụ vào mọi nơi.
Điều đúng hơn là:
Chỗ nào cần nhiều tương tác thì dùng công cụ phía client.
Chỗ nào chủ yếu đọc nội dung thì server render thường đơn giản và dễ học hơn.
Lỗi 2: nhầm lẫn giữa API và web page
Ví dụ:
API thường trả JSON
web page thường trả HTML
Người mới hay trộn hai việc này vào một chỗ và bị rối.
Lỗi 3: chỉ nghĩ theo id, không nghĩ theo slug
Điều này làm em bỏ lỡ một bài học rất quan trọng về thiết kế URL.
Lỗi 4: coi template là “đồ cũ”
Không đúng.
Template server-side là cách học rất tốt để hiểu web hoạt động từ gốc.
Các hướng khác cũng có thể làm
Có nhiều cách đúng, không chỉ một cách.
Cách 1: dùng Vue cho cả admin lẫn public
Cách này hoạt động thế nào?
Public pages cũng gọi API rồi render ở phía client.
Khi nào hợp?
Khi team mạnh frontend.
Khi app có nhiều tương tác động ở phía client.
Vì sao tôi không chọn ở đây?
Vì mục tiêu học chính bây giờ là backend Go.
Nếu chọn cách này, em rất dễ học nhiều Vue hơn là học backend.
Cách 2: dùng Go template cho cả admin lẫn public
Cách này hoạt động thế nào?
Không dùng Vue nữa.
Cả admin lẫn public đều render từ server.
Khi nào hợp?
Khi muốn cực kỳ đơn giản.
Khi không cần giao diện admin tương tác nhiều.
Vì sao tôi không chọn ở đây?
Vì admin có form, auth, CRUD, trạng thái thao tác.
Vue vẫn giúp phần admin dễ làm và dễ dùng hơn.
Kế hoạch dạy em theo 4 buổi
Buổi 1: hiểu backend admin hiện tại
Học các ý sau:
request đi vào route nào
controller nhận dữ liệu ra sao
lưu database như thế nào
JWT được tạo và kiểm tra ở đâu
Buổi 2: thêm slug cho bài viết
Học các ý sau:
vì sao bài viết cần slug
tạo slug từ title như thế nào
vì sao slug phải unique
Buổi 3: dựng public pages bằng Go template
Học các ý sau:
route public
render HTML
tách layout và page
xử lý 404
Buổi 4: hoàn thiện tư duy tách admin và public
Học các ý sau:
admin phục vụ người quản trị
public phục vụ người đọc
API và HTML page là hai kiểu response khác nhau
Cách nghĩ nên giữ trong đầu lần sau
Khi gặp một tính năng mới, đừng hỏi ngay:
Có nên dùng Vue không?
Hãy hỏi theo thứ tự này:
Người dùng đang làm gì?
Đây là chỗ quản trị hay chỗ đọc nội dung?
Trang này có cần trạng thái phía client phức tạp không?
Nếu không cần phức tạp, server render có đủ chưa?
Đây là cách nghĩ backend-first.
Kết luận
Khuyến nghị của tôi là:
Admin CMS: vẫn dùng Vue.
Public surface: chuyển dần sang Go render bằng template.
Vì sao?
Vì cách này giúp em học được những thứ quan trọng hơn cho giai đoạn đầu:
route
controller
query database
slug
render HTML
404
tư duy tách admin và public
Nói ngắn gọn:
Vue dùng để quản trị.
Go template dùng để học web từ gốc và phục vụ mặt public.
Đó là hướng học chắc hơn, dễ hiểu hơn, và đúng trọng tâm backend hơn cho em lúc này.
Reader response
Bình luận
oke
Tác giả
Duc Hoang
Golang Backend Developer
Toi dang xay dung blog ca nhan de ghi lai qua trinh hoc lap trinh va cac project thuc hanh.