<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>User Acceptance Testing · Nhân Tài Đức</title>
    <link>https://jared.lynskey.co.nz/vi/tags/user-acceptance-testing/</link>
    <description>Những câu chuyện ngắn về kỹ thuật phần mềm và lãnh đạo đội ngũ kỹ sư — performance review, tuyển dụng và mở rộng team, CI/CD, giám sát DevOps và AI agent. Viết từ Seoul.</description>
    <generator>Hugo</generator>
    <language>vi</language>
    <copyright>© 2026 Nhân Tài Đức</copyright>
    <lastBuildDate>Fri, 23 Oct 2026 00:00:00 +1300</lastBuildDate>
    <atom:link href="https://jared.lynskey.co.nz/vi/tags/user-acceptance-testing/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Kiểm thử chấp nhận người dùng (UAT): cách tôi tổ chức và xử lý góp ý</title>
      <link>https://jared.lynskey.co.nz/vi/posts/2023/2023-08-27-user-acceptance-testing/</link>
      <guid isPermaLink="true">https://jared.lynskey.co.nz/vi/posts/2023/2023-08-27-user-acceptance-testing/</guid>
      <pubDate>Sun, 27 Aug 2023 11:30:03 +0000</pubDate>
      <dc:creator>Jared Lynskey</dc:creator>
      <category>User Acceptance Testing</category>
      <category>UAT</category>
      <category>Software Solutions</category>
      <description>Kiểm thử chấp nhận người dùng (UAT) là bước kiểm tra cuối cùng trước khi ra mắt, khi người dùng thật thử phần mềm với công việc hằng ngày của họ. Cách tôi tổ chức một vòng UAT: mời ai, viết kịch bản thế nào, ghi nhận và phân loại góp ý ra sao, và khi nào thì nghiệm thu.</description>
      <content:encoded><![CDATA[<p>Kiểm thử chấp nhận người dùng (User Acceptance Testing – UAT) là giai đoạn kiểm thử cuối cùng trước khi phát hành. Ở giai đoạn này, chính những người sẽ dùng phần mềm hằng ngày đem nó vào công việc thường ngày của họ để thử, và xác nhận rằng nó đáp ứng đúng điều họ cần. Kiểm thử đơn vị (unit test) và QA kiểm tra xem phần mềm có chạy đúng như bản đặc tả (spec) hay không. Còn UAT kiểm tra xem bản đặc tả đó có đúng ngay từ đầu hay không. Một vòng UAT kết thúc bằng việc nghiệm thu (sign-off) theo các tiêu chí đã thống nhất từ lúc bắt đầu. Bất cứ điều gì không khớp với mong đợi của người dùng, dù về mặt kỹ thuật có phải là lỗi hay không, đều được ghi lại, phân loại, rồi hoặc được sửa, hoặc được chủ động dời sang sau.</p>
<p>Những lỗi đáng xấu hổ nhất mà tôi từng để lọt lên production đều có chung một điểm: bộ kiểm thử lúc đó báo xanh hết. Mã chạy đúng y như bản đặc tả, chỉ có điều bản đặc tả lại không khớp với thứ người dùng thực sự cần. UAT sinh ra để lấp đúng khoảng trống đó.</p>

<h4 class="relative group">Vì sao tôi không thể tự kiểm thử tính năng của mình
    <div id="vì-sao-tôi-không-thể-tự-kiểm-thử-tính-năng-của-mình" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#v%c3%ac-sao-t%c3%b4i-kh%c3%b4ng-th%e1%bb%83-t%e1%bb%b1-ki%e1%bb%83m-th%e1%bb%ad-t%c3%adnh-n%c4%83ng-c%e1%bb%a7a-m%c3%acnh" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Đến lúc một tính năng làm xong, tôi đã đi qua luồng thao tác suôn sẻ (happy path) của nó cả trăm lần. Tôi biết phải bấm nút nào, vì chính tay tôi làm ra cái nút đó. Chính sự quen thuộc ấy khiến tôi thành người kiểm thử tệ nhất có thể. Nó cũng là lý do QA chỉ giải quyết được một nửa vấn đề, vì QA vẫn kiểm thử dựa trên bản đặc tả. UAT là giai đoạn duy nhất mà câu hỏi đổi từ &ldquo;có chạy đúng như thiết kế không?&rdquo; sang &ldquo;thiết kế như vậy đã đúng chưa?&rdquo;</p>

<h4 class="relative group">UAT, QA và kiểm thử beta không phải là một
    <div id="uat-qa-và-kiểm-thử-beta-không-phải-là-một" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#uat-qa-v%c3%a0-ki%e1%bb%83m-th%e1%bb%ad-beta-kh%c3%b4ng-ph%e1%ba%a3i-l%c3%a0-m%e1%bb%99t" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Nhiều người dùng lẫn lộn ba khái niệm này, và điều đó gây ra không ít nhầm lẫn về chuyện ai phải làm việc gì.</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left"></th>
					<th style="text-align: left">QA</th>
					<th style="text-align: left">UAT</th>
					<th style="text-align: left">Beta</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">Câu hỏi</td>
					<td style="text-align: left">Có chạy đúng như đặc tả không?</td>
					<td style="text-align: left">Có dùng được với chính những người sẽ dùng nó không?</td>
					<td style="text-align: left">Đưa ra ngoài thực tế thì trụ được đến đâu?</td>
			</tr>
			<tr>
					<td style="text-align: left">Ai tham gia</td>
					<td style="text-align: left">Kiểm thử viên (tester), lập trình viên</td>
					<td style="text-align: left">Người dùng thật hoặc người đại diện cho họ, chủ sở hữu nghiệp vụ (business owner)</td>
					<td style="text-align: left">Một nhóm nhỏ khách hàng thật</td>
			</tr>
			<tr>
					<td style="text-align: left">Ở đâu</td>
					<td style="text-align: left">Môi trường kiểm thử</td>
					<td style="text-align: left">Staging, với dữ liệu sát thực tế</td>
					<td style="text-align: left">Production</td>
			</tr>
			<tr>
					<td style="text-align: left">Phát hiện ra</td>
					<td style="text-align: left">Lỗi so với đặc tả</td>
					<td style="text-align: left">Khoảng vênh giữa đặc tả và công việc thực tế</td>
					<td style="text-align: left">Những bất ngờ về tải, thiết bị và dữ liệu</td>
			</tr>
			<tr>
					<td style="text-align: left">Kết thúc bằng</td>
					<td style="text-align: left">Vượt qua các ca kiểm thử (test case)</td>
					<td style="text-align: left">Nghiệm thu</td>
					<td style="text-align: left">Quyết định mở rộng triển khai</td>
			</tr>
	</tbody>
</table>
<p>UAT nằm giữa hai giai đoạn kia. Nếu QA vẫn còn tìm ra lỗi làm ứng dụng sập (crash) thì vẫn còn quá sớm để làm UAT. Người dùng sẽ mất cả vòng kiểm thử để vấp hết lỗi này đến lỗi khác, và chẳng bao giờ đi được tới câu hỏi mà bạn thực sự muốn có câu trả lời.</p>

<h4 class="relative group">Trước khi bắt đầu một vòng UAT
    <div id="trước-khi-bắt-đầu-một-vòng-uat" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tr%c6%b0%e1%bb%9bc-khi-b%e1%ba%aft-%c4%91%e1%ba%a7u-m%e1%bb%99t-v%c3%b2ng-uat" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Việc đầu tiên là lên kế hoạch: phạm vi, tiến độ, ai tham gia, và thế nào thì được tính là &ldquo;đạt&rdquo;. Tiêu chí thành công mà mơ hồ thì vòng UAT sẽ cứ kéo dài hết tuần này sang tuần khác.</p>
<p>Tôi cũng đặt ra tiêu chí đầu vào (entry criteria). Tên nghe thì to tát, nhưng thực ra chỉ là một danh sách kiểm tra ngắn. QA đã đạt và không còn lỗi nghiêm trọng nào đang mở. Môi trường staging có dữ liệu trông giống thật, chứ không phải mấy tài khoản kiểu &ldquo;test test 123&rdquo;. Những người tham gia đã dành riêng thời gian trong lịch cho việc này, chứ không phải &ldquo;lúc nào rảnh thì làm&rdquo;. Điều cuối cùng là quan trọng nhất. UAT mà bị nhét vào giữa công việc chính của ai đó thì chỉ nhận được chừng mười phút chú tâm thật sự.</p>
<p>Tiếp theo là chọn những người giống với người dùng thật của bạn. Đồng nghiệp không dính dáng gì đến quá trình làm ra tính năng là lựa chọn tốt; một nhóm nhỏ các bên liên quan (stakeholder) ở bên ngoài, sẵn lòng hợp tác và hiểu sản phẩm làm ra để giải quyết việc gì, thì còn tốt hơn nữa. Với phần lớn tính năng, năm đến tám người là quá đủ. Đông hơn thế thì chủ yếu bạn chỉ nhận lại những góp ý trùng lặp.</p>

<h4 class="relative group">Viết kịch bản sao cho người ta làm theo được
    <div id="viết-kịch-bản-sao-cho-người-ta-làm-theo-được" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#vi%e1%ba%bft-k%e1%bb%8bch-b%e1%ba%a3n-sao-cho-ng%c6%b0%e1%bb%9di-ta-l%c3%a0m-theo-%c4%91%c6%b0%e1%bb%a3c" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Hãy viết kịch bản xoay quanh công việc hằng ngày thay vì các trường hợp biên (edge case), vì QA đã xử kỹ mấy trường hợp đó rồi. Một kịch bản UAT tốt đọc lên giống một ngày thứ Ba bình thường như bao ngày khác, chứ không phải một bài kiểm thử áp lực (stress test).</p>
<p>Mỗi kịch bản có một mục tiêu và một điểm xuất phát, và cố ý không ghi các bước thực hiện. Nếu bạn viết &ldquo;bấm New Invoice, rồi bấm Add Client&rdquo;, thì thứ bạn đang kiểm tra là người ta có biết làm theo hướng dẫn hay không, chứ không phải sản phẩm có dễ hiểu hay không. Với một tính năng lập hoá đơn, kịch bản có thể trông như thế này:</p>
<blockquote><p><strong>Kịch bản 4: Lập hoá đơn cho khách hàng mới theo một phần công việc</strong></p>
<p>Bạn vừa làm xong nửa đầu phần thi công hoàn thiện nội thất cho một khách hàng mới là Harbour Café. Hãy lập hoá đơn cho 50% của khoản $12,000 đã thoả thuận, hạn thanh toán trong 14 ngày, rồi gửi đến email kế toán của họ.</p>
<p><strong>Kết quả mong đợi:</strong> khách hàng nhận được hoá đơn $6,000 với đúng hạn thanh toán, và hoá đơn hiện trạng thái chưa thanh toán trên trang tổng quan (dashboard) của bạn.</p>
</blockquote><p>Thường thì mười đến mười lăm kịch bản kiểu này là đủ bao quát một tính năng. Tôi ngồi dự vài buổi đầu, nói càng ít càng tốt, và quan sát xem người ta ngập ngừng ở đâu. Một khoảnh khắc ngập ngừng trước khi bấm nút cho bạn biết nhiều hơn bất cứ điều gì được viết trong phiếu góp ý.</p>

<h4 class="relative group">Ghi nhận góp ý UAT
    <div id="ghi-nhận-góp-ý-uat" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ghi-nh%e1%ba%adn-g%c3%b3p-%c3%bd-uat" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Trong suốt vòng kiểm thử, bất cứ điều gì không khớp với mong đợi của người dùng đều được ghi lại, kể cả những chỗ về mặt kỹ thuật là &ldquo;chạy đúng như thiết kế&rdquo;. Nếu ai đó mong đợi một đằng mà nhận được một nẻo, thì đó vẫn là thông tin đáng giá, bất kể bản đặc tả nói gì.</p>
<p>Việc ghi nhận không cần công cụ gì đặc biệt. Một bảng tính dùng chung, hoặc một board riêng trong công cụ quản lý issue mà bạn đang dùng, là đủ, miễn là mục nào cũng có cùng vài trường thông tin sau:</p>
<table>
	<thead>
			<tr>
					<th style="text-align: left">Trường</th>
					<th style="text-align: left">Ví dụ</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td style="text-align: left">Kịch bản</td>
					<td style="text-align: left">4: Lập hoá đơn cho khách hàng mới theo một phần công việc</td>
			</tr>
			<tr>
					<td style="text-align: left">Điều tôi mong đợi</td>
					<td style="text-align: left">Nhập 50% và hệ thống tự tính ra số tiền</td>
			</tr>
			<tr>
					<td style="text-align: left">Điều thực tế xảy ra</td>
					<td style="text-align: left">Phải tự tính tay ra $6,000; không có lựa chọn nhập theo phần trăm</td>
			</tr>
			<tr>
					<td style="text-align: left">Mức độ nghiêm trọng (theo cảm nhận của người kiểm thử)</td>
					<td style="text-align: left">Gây khó chịu, nhưng không chặn công việc</td>
			</tr>
			<tr>
					<td style="text-align: left">Ảnh chụp màn hình hoặc video quay màn hình</td>
					<td style="text-align: left">Đã đính kèm</td>
			</tr>
	</tbody>
</table>
<p>&ldquo;Điều tôi mong đợi&rdquo; là trường quan trọng nhất. Thiếu nó, bạn sẽ nhận được những góp ý kiểu &ldquo;màn hình hoá đơn khó hiểu quá&rdquo;, mà chẳng ai biết phải làm gì với góp ý đó.</p>

<h4 class="relative group">Phân loại góp ý
    <div id="phân-loại-góp-ý" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ph%c3%a2n-lo%e1%ba%a1i-g%c3%b3p-%c3%bd" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Cuối mỗi ngày, hoặc cuối mỗi vòng nếu vòng đó nhỏ, tôi cùng người phụ trách sản phẩm (product owner) rà lại toàn bộ nhật ký góp ý và xếp từng mục vào một trong bốn nhóm.</p>
<p>Lỗi (bug) là thứ bị hỏng, như tổng tiền tính sai hay một trang báo lỗi. Nếu nghiêm trọng thì phải sửa trước khi nghiệm thu, còn không thì xếp lịch sửa sau.</p>
<p>Yêu cầu thay đổi (change request) nghĩa là tính năng chạy đúng như đặc tả, nhưng bản đặc tả lại sai, giống như chuyện thiếu lựa chọn nhập theo phần trăm ở trên. Đây chính là loại góp ý mà UAT sinh ra để tìm, và cũng là loại khó xử lý nhất, vì sửa nó đồng nghĩa với việc mở rộng phạm vi. Người quyết định là product owner: sửa ngay, hay chấp nhận và xếp lịch làm sau.</p>
<p>Vấn đề về câu chữ hoặc hướng dẫn sử dụng nghĩa là tính năng không có gì sai, nhưng người dùng không hiểu nó. Nhiều khi chỉ cần sửa một nhãn, thêm một dòng gợi ý, hoặc một câu trong tài liệu hướng dẫn là xong. Rẻ, và đáng làm.</p>
<p>Không sửa (won&rsquo;t fix) dành cho những ý tưởng nằm ngoài phạm vi, hoặc sở thích của một người đi ngược với tất cả những người còn lại. Hãy ghi lại lý do, và báo lại cho người đã nêu ý kiến. Người kiểm thử mà góp ý xong không bao giờ nhận được hồi âm thì sang vòng sau sẽ thôi góp ý.</p>
<p>Điều tôi cố tránh nhất là coi mục nào cũng là lỗi phải sửa trước khi ra mắt. Đó là cách một vòng kiểm thử hai tuần biến thành hai tháng. Mục tiêu của việc xử lý góp ý UAT không phải là đưa danh sách về con số không, mà là mục nào cũng đã có một quyết định đi kèm.</p>

<h4 class="relative group">Nghiệm thu
    <div id="nghiệm-thu" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#nghi%e1%bb%87m-thu" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Sau vòng kiểm thử, hãy sửa những gì cần sửa, và nếu thay đổi nhiều thì chạy thêm một vòng ngắn nữa, đừng mặc định là mọi thứ đã ổn. Sau đó lấy xác nhận nghiệm thu đàng hoàng, đối chiếu với các tiêu chí đã thống nhất từ đầu. Nghĩa là phải có một người cụ thể, có tên tuổi đàng hoàng, nói &ldquo;Được, phát hành đi&rdquo;, kèm danh sách các mục đã dời lại, chứ không phải một emoji giơ ngón cái trong nhóm chat.</p>

<h4 class="relative group">Những sai lầm tôi từng mắc khi tổ chức UAT
    <div id="những-sai-lầm-tôi-từng-mắc-khi-tổ-chức-uat" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#nh%e1%bb%afng-sai-l%e1%ba%a7m-t%c3%b4i-t%e1%bb%abng-m%e1%ba%afc-khi-t%e1%bb%95-ch%e1%bb%a9c-uat" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Làm quá muộn. Nếu UAT bắt đầu hai ngày trước một ngày ra mắt đã chốt cứng, thì yêu cầu thay đổi nào cũng biến thành một cuộc tranh cãi xem có nên lùi ngày hay không, và câu trả lời lúc nào cũng là không. Hãy chừa thời gian để còn xử lý những gì mình phát hiện ra.</p>
<p>Kiểm thử với sai người. Nhân viên nội bộ đã quá quen sản phẩm sẽ hành xử y như đội phát triển. Họ biết thừa mọi thứ nằm ở đâu.</p>
<p>Coi im lặng là đồng ý. Nếu một người kiểm thử không ghi nhận gì cả, nhiều khả năng là họ chưa thực sự kiểm thử. Hãy hỏi han họ trước khi tính họ là &ldquo;đạt&rdquo;.</p>
<p>Và để UAT trở thành một ô cần tích cho xong ở cuối sprint. Tốt hơn hết là coi nó như cửa ải cuối cùng: khoảnh khắc cuối trước khi ra mắt, khi có một người không phải bạn thử dùng thứ bạn làm ra.</p>

<h4 class="relative group">UAT mang lại cho bạn điều gì
    <div id="uat-mang-lại-cho-bạn-điều-gì" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#uat-mang-l%e1%ba%a1i-cho-b%e1%ba%a1n-%c4%91i%e1%bb%81u-g%c3%ac" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>Chủ yếu là bắt được vấn đề khi sửa vẫn còn rẻ: ngay trước khi ra mắt, thay vì phải tung bản vá kèm lời xin lỗi sau đó. Ngoài ra còn vài cái lợi ít ai để ý hơn. Việc đào tạo và hỗ trợ người dùng nhẹ nhàng hơn, vì các luồng thao tác đã khớp với cách mọi người thực sự làm việc. Và các bên liên quan từng tham gia kiểm thử sẽ xác nhận nghiệm thu nhanh hơn, vì đến lúc đó sản phẩm cũng phần nào là của họ. Những bản phát hành mà tôi thấy có một vòng UAT tử tế thường là những lần phát hành êm ả nhất.</p>

<h4 class="relative group">Tóm lại
    <div id="tóm-lại" class="anchor"></div>
    
    <span
        class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none">
        <a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#t%c3%b3m-l%e1%ba%a1i" aria-label="Cọc dấu">#</a>
    </span>
    
</h4>
<p>UAT là lúc người dùng thật kiểm tra xem phần mềm có làm đúng điều họ cần hay không, trước khi phát hành. Chỉ bắt đầu khi QA đã sạch lỗi. Mời năm đến tám người giống với người dùng của bạn, viết kịch bản dưới dạng mục tiêu hằng ngày thay vì từng bước thao tác, và ghi lại mọi khoảng vênh giữa điều họ mong đợi và điều thực tế xảy ra. Xếp từng góp ý vào một trong bốn nhóm: lỗi, yêu cầu thay đổi, vấn đề câu chữ, hoặc không sửa. Mục nào cũng phải có quyết định, và kết thúc bằng lời nghiệm thu của một người cụ thể.</p>
]]></content:encoded>
      <media:content url="https://jared.lynskey.co.nz/en/posts/2023/2023-08-27-user-acceptance-testing/featured.jpeg" medium="image" type="image/jpeg" />
    </item>
  </channel>
</rss>
