Lập Kế Hoạch Trước Khi Viết Mã: Phát Triển Dựa Trên Đặc Tả (Spec Driven Development) Hiệu Quả trong Thực Tế

Khi còn là sinh viên, ý tưởng đầu tiên mỗi khi tôi có một dự án mới là mở VS Code và bắt đầu gõ mã ngay lập tức. Nghe có quen không?

Vấn đề là các dự án của tôi phát triển mà không có định hướng, mọi thứ thay đổi liên tục, tôi không bao giờ biết khi nào thì chúng “hoàn thành”, viết ra những dòng mã mà chính tôi cũng không hiểu sau hai tuần, và cuối cùng chúng trở thành một trong vô số dự án bị bỏ dở. Từ góc độ của tôi, đó không phải là vấn đề về kỹ năng kỹ thuật, vì tôi biết cách thực hiện mọi thứ. Mãi về sau, tôi mới nhận ra đó là một vấn đề về quy trình.

Nếu bạn mới bắt đầu sự nghiệp trong lĩnh vực công nghệ và gặp phải tình huống tương tự, đừng lo lắng, ai cũng từng như vậy. Nhưng có một phương pháp có thể giúp bạn làm việc hiệu quả hơn rất nhiều.

Trong bài viết này, chúng ta sẽ cùng tìm hiểu cách áp dụng nguyên tắc Phát triển dựa trên Đặc tả (Spec Driven Development – SDD) để biến một ý tưởng từ các trường hợp sử dụng ban đầu thành mã nguồn hoạt động. Chúng ta sẽ sử dụng [Kiro](https://kiro.dev/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) như một công cụ hỗ trợ minh họa. Nếu đây là lần đầu bạn biết đến Kiro và muốn tìm hiểu từ những bước cơ bản, Ana Cunha đã có một [hướng dẫn khởi đầu](https://builder.aws.com/content/34X2JujaGkTJed5N2KeMYt1Mz9m/como-comenzar-con-kiro-tu-guia-de-primeros-pasos?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) rất hữu ích.

Vấn Đề Thực Sự Không Phải Là Mã Nguồn

Theo kinh nghiệm của tôi, nhiều dự án thất bại không phải vì mã nguồn kém chất lượng. Chúng thất bại vì tôi chưa bao giờ định nghĩa rõ ràng vấn đề mà mình muốn giải quyết.

Hãy tưởng tượng bạn muốn xây dựng một ứng dụng so sánh CV của bạn với một mô tả công việc bằng cách sử dụng AI, sau đó cho bạn biết những gì bạn còn thiếu. Bạn sẽ bắt đầu từ đâu? Frontend? Cơ sở dữ liệu? Hay tích hợp trí tuệ nhân tạo?

Ở một giai đoạn nào đó trong sự nghiệp, tôi từng làm freelancer, và chính trong thời gian đó tôi mới thực sự trân trọng những gì mình đã học được từ các lớp kỹ thuật phần mềm. Tôi đã học được một điều thay đổi hoàn toàn cách tôi xây dựng mọi thứ: mã nguồn không phải là điểm khởi đầu, mà là hệ quả. Trước khi viết một dòng mã nào, bạn cần phải hiểu rõ bạn đang xây dựng cái gì và cho ai.

Trường Hợp Sử Dụng (Use Cases): Bản Thiết Kế Của Bạn Trước Khi Xây Dựng

Một trường hợp sử dụng (use case) đơn giản là mô tả cách một người dùng tương tác với hệ thống của bạn. Hãy coi chúng như bản thiết kế của một kiến trúc sư – bạn sẽ không xây nhà mà không có chúng, và bạn cũng không nên bắt đầu viết mã mà không hiểu rõ mình đang xây dựng cái gì.

Nếu bạn muốn tìm hiểu sâu hơn về định nghĩa chính thức, có rất nhiều [tài liệu xuất sắc](https://en.wikipedia.org/wiki/Use_case) về chủ đề này. Nhưng đối với mục đích thực tế, bạn cần ba điều cốt lõi:

  1. Câu chuyện người dùng (User Stories): Người dùng muốn làm gì và tại sao.
  2. Tiêu chí chấp nhận (Acceptance Criteria): Làm thế nào để biết rằng tính năng hoạt động đúng.
  3. Thực thể và Mối quan hệ (Entities and Relationships): Những “thứ” nào tồn tại trong hệ thống của bạn và chúng kết nối với nhau ra sao.

Hãy quay lại ví dụ về ứng dụng so sánh CV. Một ý tưởng mơ hồ như “tôi muốn một ứng dụng phân tích CV của tôi” trở nên cụ thể hơn khi bạn viết nó dưới dạng câu chuyện người dùng:


<strong>Là một</strong> người tìm việc,
<strong>Tôi muốn</strong> tải lên CV của mình dưới định dạng PDF hoặc văn bản,
<strong>Để</strong> hệ thống có thể phân tích và so sánh nó với một mô tả công việc.

Ngay lập tức, bạn đã biết được nhiều điều: bạn cần hỗ trợ định dạng PDF và văn bản, bạn cần mô tả công việc làm đầu vào thứ hai, và kết quả là một sự so sánh. Điều này hữu ích hơn nhiều so với việc chỉ nói “làm một ứng dụng CV”.

Và khi bạn bổ sung các tiêu chí chấp nhận, mọi thứ càng trở nên rõ ràng hơn:

  • KHI người dùng tải lên một tệp PDF, HỆ THỐNG PHẢI trích xuất nội dung một cách chính xác.
  • KHI người dùng cố gắng tải lên một định dạng không được hỗ trợ, HỆ THỐNG PHẢI hiển thị thông báo lỗi với các định dạng hợp lệ.

Giờ đây, bạn không chỉ biết cần xây dựng cái gì mà còn biết khi nào thì nó “hoàn thành”. Đó là điều mà khi còn là sinh viên, tôi chưa bao giờ có được sự rõ ràng.

Spec Driven Development (SDD): Cầu Nối Giữa Ý Tưởng và Mã Nguồn

Định nghĩa các trường hợp sử dụng là bước đầu tiên. Nhưng làm thế nào để chuyển từ những yêu cầu đó sang mã nguồn thực tế mà không bị lạc lối trên đường đi?

Đây là lúc khái niệm [Phát triển dựa trên Đặc tả (Spec Driven Development)](https://kiro.dev/blog/kiro-and-the-future-of-software-development/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) phát huy tác dụng. Đây là một phương pháp mà bạn ưu tiên thiết kế các đặc tả về những gì bạn sẽ xây dựng, sau đó mới thực hiện. Phương pháp này được chia thành bốn giai đoạn chính:

  1. Ghi lại ý định (Capture intention): Bạn định nghĩa những gì muốn xây dựng bằng ngôn ngữ tự nhiên. Đây là nơi các câu chuyện người dùng và tiêu chí chấp nhận mà chúng ta đã xem xét trước đó phát huy tác dụng. Mục tiêu là để bất kỳ ai (có hoặc không có kiến thức kỹ thuật) cũng có thể hiểu được những gì sẽ được xây dựng.
  2. Chuyển đổi ý định thành bản thiết kế hệ thống (Translate intention into a system blueprint): Bạn lấy những yêu cầu đó và biến chúng thành một thiết kế kỹ thuật: bạn cần những thành phần nào, chúng giao tiếp với nhau ra sao, bạn sẽ sử dụng công nghệ nào. Đây là bản thiết kế kiến trúc của bạn.
  3. Tạo các đơn vị công việc (Generate units of work): Bạn chia nhỏ thiết kế đó thành các nhiệm vụ cụ thể và tăng dần. Mỗi nhiệm vụ phải nhỏ, rõ ràng và phải tạo ra một thứ gì đó có chức năng mà bạn có thể kiểm thử.
  4. Thực thi và xác thực (Implement and validate): Giờ thì bạn viết mã. Nhưng mỗi nhiệm vụ bạn thực hiện đều được xác thực dựa trên các tiêu chí chấp nhận mà bạn đã định nghĩa ở giai đoạn đầu tiên. Bằng cách này, bạn biết rằng những gì bạn xây dựng chính là những gì bạn cần.

💡 Lưu ý quan trọng: Đây không phải là một quy trình bạn chỉ thực hiện một lần duy nhất. Mỗi khi bạn thêm một tính năng mới vào dự án, bạn sẽ lặp lại bốn giai đoạn này. Bạn định nghĩa ý định của tính năng đó, cập nhật bản thiết kế, tạo các đơn vị công việc và thực hiện chúng. Đó là một chu kỳ lặp lại, và mỗi lần lặp lại sẽ trở nên tự nhiên hơn.

(Hình ảnh minh họa quy trình Spec Driven Development: từ ý tưởng đến đặc tả, thiết kế, nhiệm vụ, và cuối cùng là mã nguồn có thể kiểm thử được.)

Điều thú vị của phương pháp này là nó không phụ thuộc vào bất kỳ công cụ cụ thể nào. Bạn có thể thực hiện nó bằng một tài liệu văn bản, một bảng trắng, hoặc thậm chí trên một chiếc khăn giấy. Điều quan trọng là quá trình tư duy trước khi viết mã.

Mặc dù vậy, các công cụ như [Kiro](https://kiro.dev/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) đã triển khai phương pháp này và giúp bạn thực hiện các giai đoạn một cách có cấu trúc. Kiro tuân theo một luồng ba giai đoạn (`1. requirements`, `2. design` và `3. tasks`) tương ứng trực tiếp với những gì chúng ta vừa tìm hiểu:

Giai đoạn SDD Điều gì xảy ra Trong Kiro
Ghi lại ý định Mô tả ý tưởng của bạn bằng ngôn ngữ tự nhiên Bạn nói với Kiro những gì bạn muốn xây dựng
Bản thiết kế hệ thống Yêu cầu + Thiết kế + Nhiệm vụ Kiro tạo ra requirements.md, design.md và tasks.md
Các đơn vị công việc Thực hiện các nhiệm vụ Bạn chạy từng nhiệm vụ từ IDE
Thực thi và xác thực Mã nguồn + xác thực Kiro thực hiện và bạn xác thực dựa trên tiêu chí chấp nhận

Nhưng phương pháp này hoạt động dù có hay không có công cụ. Kiro chỉ đơn giản là làm cho quá trình diễn ra nhanh hơn.

💡 Mẹo quan trọng: Các công cụ AI không thay thế tư duy phản biện của bạn. Chúng khuếch đại nó. Vấn đề không phải là tài liệu hóa chỉ để tài liệu hóa, mà là tư duy trước khi viết mã. Tài liệu là kết quả của quá trình tư duy đó.

SDD Trong Hành Động: Xây Dựng Ứng Dụng So Sánh CV

Để điều này không chỉ dừng lại ở lý thuyết, hãy cùng xem quy trình này được áp dụng như thế nào vào dự án so sánh CV.

Giai đoạn 1: Ghi lại ý định

Đây là lúc tất cả những gì chúng ta đã thảo luận phát huy ý nghĩa. Thay vì mở Kiro với một câu lệnh mơ hồ như “hãy tạo cho tôi một ứng dụng CV”, tôi đã viết một tệp tin với các câu chuyện người dùng và tiêu chí chấp nhận đã định nghĩa bối cảnh dự án, người dùng là ai, họ cần làm gì và làm thế nào để chúng ta biết nó hoạt động. Điều này trông như sau:


## Bối cảnh Dự án
**Người dùng chính:** Những người đang tích cực tìm kiếm việc làm
**Mục tiêu:** Cải thiện chất lượng CV để nâng cao hồ sơ chuyên nghiệp

### Câu chuyện 1: Tải CV để phân tích
**Là một** người tìm việc,
**Tôi muốn** tải lên CV của mình dưới định dạng PDF hoặc văn bản,
**Để** hệ thống có thể phân tích và so sánh nó với các mô tả công việc.

**Tiêu chí chấp nhận:**
KHI người dùng tải lên một tệp CV ở định dạng PDF,
HỆ THỐNG PHẢI trích xuất nội dung tài liệu một cách chính xác.
KHI người dùng tải lên một tệp CV ở định dạng văn bản,
HỆ THỐNG PHẢI trích xuất nội dung văn bản một cách chính xác.
KHI người dùng tải lên một định dạng tệp không được hỗ trợ,
HỆ THỐNG PHẢI hiển thị thông báo lỗi với danh sách các định dạng hợp lệ.

Tệp tin đó là điểm khởi đầu cho Kiro. Công việc tư duy vấn đề từ trước đó đã cung cấp cho công cụ ngữ cảnh cần thiết để tạo ra một thứ gì đó hữu ích.

Giai đoạn 2: Bản thiết kế hệ thống

Từ các trường hợp sử dụng, Kiro đã tạo ra ba tài liệu cùng nhau tạo thành bản thiết kế hoàn chỉnh của dự án:

  • <strong>requirements.md</strong>: Kiro đã lấy các câu chuyện người dùng và mở rộng chúng thành một tài liệu yêu cầu chính thức. Nó đã thêm một bảng thuật ngữ với các thuật ngữ miền (như “Critical_Gap” hoặc “Recommendation_Generator”), chi tiết các tiêu chí chấp nhận của từng câu chuyện, và thậm chí xác định các yêu cầu kỹ thuật không rõ ràng trong các câu chuyện gốc, như trích xuất văn bản từ PDF và phân tích có cấu trúc các mô tả công việc.
  • <strong>design.md</strong>: Với các yêu cầu rõ ràng, Kiro đã tạo ra thiết kế kỹ thuật: một sơ đồ kiến trúc với tất cả các thành phần, luồng dữ liệu (cách một tệp PDF di chuyển từ trình duyệt đến phân tích bằng AI), giao diện giữa các thành phần (Lambda nào nhận gì và trả về gì), và một chiến lược xử lý lỗi. Đây là nơi ý tưởng đã trở thành một bản thiết kế kỹ thuật cụ thể.
  • <strong>tasks.md</strong>: Cuối cùng, Kiro đã phân tách thiết kế thành các nhiệm vụ tăng dần. Mỗi nhiệm vụ tham chiếu các yêu cầu mà nó thực hiện, có các nhiệm vụ con rõ ràng và xây dựng dựa trên nhiệm vụ trước. Ví dụ: trước tiên là cơ sở hạ tầng (SAM template), sau đó là Lambda cho các URL ký trước (presigned URLs), rồi đến trích xuất PDF, và cứ thế cho đến khi có ứng dụng hoàn chỉnh.

Một chi tiết thú vị: Kiro ban đầu đề xuất tôi sử dụng Python cho các hàm Lambda. Nhưng cá nhân tôi rất thích Rust, vì vậy tôi đã yêu cầu nó thay đổi thiết kế để sử dụng Rust ở phần backend. Và nó đã làm được mà không gặp vấn đề gì, điều chỉnh kiến trúc, các phụ thuộc và các nhiệm vụ. Điều này quan trọng: công cụ đề xuất, nhưng bạn quyết định. Nếu có điều gì bạn muốn làm khác, thử nghiệm một ngôn ngữ bạn quan tâm hoặc sử dụng một công nghệ bạn muốn học, bạn hoàn toàn có thể làm được. Bản thiết kế thích ứng với các quyết định của bạn, chứ không phải ngược lại.

Kết quả là một kiến trúc rõ ràng:

(Hình ảnh minh họa kiến trúc ứng dụng so sánh CV: Một frontend dùng Astro, kết nối với các hàm serverless Rust trên AWS Lambda. Dữ liệu CV và công việc được xử lý qua Amazon S3 và Amazon Bedrock để phân tích AI. AWS Cognito quản lý xác thực người dùng.)

Một frontend trong [Astro](https://astro.build/) (một framework web hiện đại), các hàm serverless trong Rust triển khai với [AWS Lambda](https://aws.amazon.com/lambda/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) (các hàm chạy theo yêu cầu mà không cần quản lý máy chủ), phân tích CV với [Amazon Bedrock](https://aws.amazon.com/bedrock/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) (truy cập các mô hình AI tạo sinh) và lưu trữ tạm thời trong [Amazon S3](https://aws.amazon.com/s3/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) (lưu trữ đối tượng trên đám mây). Tất cả đều được định nghĩa trước khi viết dòng mã đầu tiên.

Giai đoạn 3: Thực thi các đơn vị công việc

Với bản thiết kế đã sẵn sàng, tôi bắt đầu thực hiện các nhiệm vụ trực tiếp từ IDE của Kiro. Nhiệm vụ đầu tiên là Kiro đã tạo ra monorepo, khởi tạo frontend trong Astro, cấu hình workspace của Rust và tạo tệp `template.yaml` cơ bản cho SAM.

Từ đó, kế hoạch triển khai bao gồm 21 nhiệm vụ xây dựng ứng dụng theo từng bước tăng dần: trước tiên là cơ sở hạ tầng trên AWS (S3, Cognito, API Gateway, Lambdas), sau đó là các hàm backend từng cái một (URL ký trước, trích xuất PDF, tích hợp với Bedrock, phân tích phản hồi), sau đó là toàn bộ frontend (xác thực, tải CV, trang kết quả), và cuối cùng là triển khai. Mỗi nhiệm vụ đều tham chiếu các yêu cầu mà nó thực hiện, vì vậy bạn luôn biết cái gì bạn đang xây dựng và tại sao.

Kết quả: một ứng dụng hoạt động nơi bạn tải CV của mình lên, dán một mô tả công việc, và hệ thống sẽ cho bạn biết mức độ tương thích của bạn và những gì bạn còn thiếu. Tất cả đều được xây dựng từ sáu câu chuyện người dùng được viết trong một tệp văn bản đơn giản.

Điều Thay Đổi Nếu Tôi Có Thể Quay Lại

Nếu tôi có thể quay lại thời điểm bắt đầu xây dựng những ứng dụng đầu tiên của mình, điều đầu tiên tôi sẽ thay đổi là: tôi sẽ ngừng mở trình soạn thảo mã làm bước đầu tiên.

Không phải vì viết mã là sai, rõ ràng rồi; cuối cùng thì đó là điều chúng ta đam mê. Mà bởi vì dành ít nhất 30 phút để suy nghĩ về cái gì bạn sẽ xây dựng trước khi nghĩ về làm thế nào, sẽ giúp bạn tiết kiệm hàng giờ thất vọng sau này.

Nếu phương pháp này hữu ích với bạn và bạn muốn thảo luận về cách áp dụng nó vào dự án của mình, hãy tìm tôi trên [LinkedIn](https://www.linkedin.com/in/ramses-mata/).

***

Tài Nguyên Tham Khảo

  • [Spec Driven Development – Kiro Blog](https://kiro.dev/blog/kiro-and-the-future-of-software-development/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el)
  • [Cách Bắt Đầu Với Kiro: Hướng Dẫn Bước Đầu Của Bạn](https://builder.aws.com/content/34X2JujaGkTJed5N2KeMYt1Mz9m/como-comenzar-con-kiro-tu-guia-de-primeros-pasos?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) – Nếu bạn muốn một hướng dẫn từng bước chi tiết hơn để bắt đầu với Kiro, Ana Cunha đã viết hướng dẫn này.
  • [Trang Chủ Kiro](https://kiro.dev/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el)
  • [Tầng Miễn Phí AWS (AWS Free Tier)](https://aws.amazon.com/free/?trk=3030e60a-17b3-4fdb-9862-d65f29e1a10c&sc_channel=el) – Bắt đầu sử dụng các dịch vụ AWS mà không tốn chi phí.