backend first

Học Lập Trình /backend-first #Golang #Vue #CMS #Sqlite

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à:

  1. Người dùng mở URL.

  2. Server lấy dữ liệu.

  3. Server render HTML.

  4. 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-chi

Em sẽ học được rõ ràng các bước:

  1. Router nhận request.

  2. Router lấy ra slug từ URL.

  3. Controller dùng slug để tìm bài viết trong database.

  4. Nếu không có bài viết thì trả trang 404.

  5. Nếu có bài viết thì nạp vào template HTML.

  6. 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-chi

Trong đó:

  • 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/12

Nhưng nó có 3 điểm yếu:

  1. Người đọc nhìn không hiểu bài viết nói về gì.

  2. Link kém đẹp.

  3. 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ỹ:

  1. Admin tạo bài viết mới.

  2. Backend nhận title.

  3. Backend tạo slug từ title.

  4. Backend lưu bài viết vào database, gồm cả title và slug.

  5. Người dùng mở /bai-viet/{slug}.

  6. Router lấy slug từ URL.

  7. Controller tìm bài viết theo slug.

  8. Nếu không tìm thấy, trả 404.

  9. Nếu tìm thấy, render HTML.

Ví dụ dễ hiểu

Giả sử tiêu đề bài là:

Hoc Go Router voi Chi

Backend có thể biến nó thành:

/bai-viet/hoc-go-router-voi-chi

Khi đó URL public sẽ là:

/bai-viet/hoc-go-router-voi-chi

Nê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-router

Thì slug sẽ là:

hoc-go-router

findPostBySlug(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:

  1. Người dùng đang làm gì?

  2. Đây là chỗ quản trị hay chỗ đọc nội dung?

  3. Trang này có cần trạng thái phía client phức tạp không?

  4. 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

1 comment
duchoang 04/05/2026 18:35

oke

Giới hạn 60 ký tự cho tên và 1000 ký tự cho nội dung.

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.