Behavior Driven Development
นิยามพฤติกรรมของระบบด้วยภาษาที่ทุกฝ่ายเข้าใจตรงกัน
คืออะไร
หัวข้อที่มีชื่อว่า “คืออะไร”Behavior Driven Development (BDD) เป็นแนวปฏิบัติแบบ Agile ที่เน้นการสร้าง ความเข้าใจร่วมกัน (shared understanding) ระหว่างฝ่ายธุรกิจกับฝ่ายเทคนิค โดยอธิบายพฤติกรรมของระบบด้วยภาษาธรรมดาที่ทุกคนอ่านออก แทนที่จะเป็น spec ทางเทคนิคหรือ code ล้วน ๆ มันเป็น whole team activity ที่ดึงนักพัฒนา ผู้ทดสอบ (QA) และตัวแทนฝ่ายธุรกิจมาคุยกันตั้งแต่ก่อนเขียน code บรรทัดแรก
BDD ถือกำเนิดขึ้นราวปี 2003 โดย Dan North ขณะทำงานที่ ThoughtWorks เขาสังเกตว่าเวลาสอน Test Driven Development ให้ทีมต่าง ๆ ปัญหาซ้ำ ๆ ที่เจอคือความสับสนรอบคำว่า “test” — โปรแกรมเมอร์ไม่แน่ใจว่าจะเริ่ม test จากตรงไหน ควร test อะไรบ้าง ควร test มากแค่ไหนในแต่ละรอบ ควรตั้งชื่อ test อย่างไร และเมื่อ test ล้มเหลวควรตีความว่าอย่างไร North จึงเสนอให้เปลี่ยนคำศัพท์จาก “test” เป็น “behavior” — เขียน spec ในรูปประโยคที่ว่า class หนึ่ง ๆ should ทำอะไร ซึ่งช่วยให้โฟกัสอยู่ที่พฤติกรรมของหน่วย code นั้นโดยตรง เขาเริ่มเขียน framework JBehave แทนที่ JUnit เพื่อลบศัพท์แสงเรื่อง testing ออกไปทั้งหมด แล้วแทนที่ด้วยคำศัพท์ที่พูดถึงพฤติกรรมล้วน ๆ
ข้อเข้าใจผิดที่พบบ่อยคือคิดว่า BDD เป็นแค่ “TDD version ปรับปรุง” แต่จริง ๆ แล้ว BDD ผสาน TDD เข้ากับแนวคิดจาก Domain-Driven Design และ acceptance testing/ATDD โดยดึง Ubiquitous Language มาใช้เป็นแกนกลาง — คำศัพท์ที่ใช้ในเอกสาร requirement, ในบทสนทนากับ stakeholder และใน code ควรเป็นคำชุดเดียวกัน เพื่อไม่ต้อง “แปล” ไปมาระหว่างภาษาธุรกิจกับภาษาทางเทคนิค เมื่อ scenario ที่เขียนไว้ล้มเหลว นั่นคือสัญญาณตรง ๆ ว่าพฤติกรรมจริงของระบบยังไม่ตรงกับที่ตกลงกันไว้ ไม่ใช่แค่ “test พัง”
ทำอย่างไร
หัวข้อที่มีชื่อว่า “ทำอย่างไร”องค์ประกอบพื้นฐานของ BDD คือ User Stories, Scenarios, Steps และ Automation โดยใช้ภาษาที่มีจังหวะ (cadence) ตายตัว ภาษาเฉพาะทาง (domain-specific language) ที่นิยมใช้เขียน scenario คือ Gherkin
กระบวนการทำงานทั่วไปแบ่งเป็นสามช่วง ได้แก่ discovery ที่ทีมคุยกันเพื่อหาความเข้าใจร่วม (มักเรียกว่า Three Amigos — รวมนักพัฒนา ผู้ทดสอบ และตัวแทนฝ่ายธุรกิจ), formulation ที่แปลงบทสนทนาเป็น scenario ด้วย Gherkin และ automation ที่ผูก scenario เข้ากับ code จริงให้รันอัตโนมัติได้ ผลลัพธ์ที่ได้คือ Gherkin feature file ที่ทำหน้าที่เป็นทั้ง requirement, test และ living documentation ใน file เดียว
flowchart LR Discovery[Three Amigos พูดคุยหาความเข้าใจร่วม] --> Formulation[เขียน Scenario ด้วย Gherkin] Formulation --> Automation[ผูก Step กับ code] Automation --> Execution[รัน Suite อัตโนมัติ] Execution --> LivingDoc[Living Documentation] LivingDoc --> Discovery
User Stories — อะไรและทำไม
หัวข้อที่มีชื่อว่า “User Stories — อะไรและทำไม”BDD มักเริ่มจาก user story ซึ่งเป็นคำบรรยาย feature ระดับสูงจากมุมมองของผู้ใช้ปลายทาง เขียนด้วยภาษาธรรมดาให้สมาชิกที่ไม่ใช่สายเทคนิคเข้าใจได้ โดยมักมีจังหวะดังนี้:
โครงของ user story — เน้นว่าใคร ต้องการอะไร และเพื่ออะไร
# As a [ผู้ใช้/บทบาท], I want to [ทำบางสิ่ง], So that [เหตุผล]Feature: การยืมหนังสือ ในฐานะสมาชิกห้องสมุด ฉันต้องการยืม eBook เพื่อจะได้อ่าน eBook บนเครื่องอ่านของฉันScenarios — Given · When · Then
หัวข้อที่มีชื่อว่า “Scenarios — Given · When · Then”แต่ละ user story ถูกแตกออกเป็นหลาย scenario ที่บรรยายกรณีใช้งานเฉพาะของ feature โดยเขียนในจังหวะที่เรียกว่า Given-When-Then ซึ่ง Martin Fowler อธิบายไว้ว่าเป็นวิธีจัดโครงสร้างของ SpecificationByExample: Given อธิบายเงื่อนไขตั้งต้นก่อนพฤติกรรมจะเกิด, When อธิบายการกระทำหรือเหตุการณ์ที่จุดชนวนพฤติกรรมนั้น, และ Then อธิบายผลลัพธ์ที่คาดหวังหลังพฤติกรรมเกิดขึ้น การเขียนในรูปแบบนี้ทำให้ชัดเจนว่าพฤติกรรมของระบบควรเป็นอย่างไรภายใต้เงื่อนไขหนึ่ง ๆ
scenario ของระบบยืมหนังสือออนไลน์
Feature: การยืมออนไลน์ Scenario: ยืมหนังสือหนึ่งเล่ม Given คลังของห้องสมุดมีหนังสือที่ฉันต้องการยืม When ฉันยืมหนังสือเล่มนั้น Then จำนวนคงเหลือในคลังลดลง 1 เล่มAutomated testing — Gherkin สู่ code
หัวข้อที่มีชื่อว่า “Automated testing — Gherkin สู่ code”จุดเด่นสำคัญข้อหนึ่งของ BDD คือการนำไปใช้ในการทดสอบ ด้วยการใช้ library เชื่อม Gherkin เข้ากับ code test ที่ขับด้วยพฤติกรรมจึงถูกทำให้อัตโนมัติได้ Gherkin ยังรองรับตัวแปรในแต่ละขั้นของ scenario ผ่าน feature ที่เรียกว่า Scenario Outline:
Scenario Outline — รันชุดตัวอย่างหลายกรณีจากตารางเดียว
Scenario Outline: ตรวจวันหมดอายุการยืม Given ระยะเวลายืม <period> วัน When ฉันเปิดหนังสือในวันที่ <open> Then หนังสือควรหมดอายุในอีก <left> วัน
Examples: | period | open | left | | 7 | 2 | 5 | | 14 | 10 | 2 | | 21 | 18 | 3 |มี library จำนวนมากที่ช่วย map file Gherkin เข้ากับ code เพื่อทำ test อัตโนมัติ ที่พบบ่อยได้แก่ Cucumber-JVM/JBehave (Java), SpecFlow (C#/.NET), behave/pytest-bdd (Python) และ Cucumber (Ruby)
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”ตัวอย่างการผูก scenario ข้างต้นเข้ากับ step definition ใน C# ด้วย SpecFlow ซึ่งเป็น framework BDD ที่นิยมที่สุดในระบบนิเวศ .NET — SpecFlow แปล file .feature เป็น Gherkin แล้ว generate เมทอดที่ต้อง implement ให้ตรงกับแต่ละ step:
[Binding]public class LibraryLoanSteps{ private readonly LibraryCatalog _catalog; private int _remainingBeforeLoan;
public LibraryLoanSteps(LibraryCatalog catalog) { _catalog = catalog; }
[Given(@"คลังของห้องสมุดมีหนังสือที่ฉันต้องการยืม")] public void GivenBookIsAvailable() { _catalog.AddCopy(new BookId("book-1")); _remainingBeforeLoan = _catalog.RemainingCopies(new BookId("book-1")); }
[When(@"ฉันยืมหนังสือเล่มนั้น")] public void WhenIBorrowTheBook() { _catalog.Borrow(new BookId("book-1"), new MemberId("member-1")); }
[Then(@"จำนวนคงเหลือในคลังลดลง 1 เล่ม")] public void ThenRemainingCopiesDecreaseByOne() { var remaining = _catalog.RemainingCopies(new BookId("book-1")); Assert.Equal(_remainingBeforeLoan - 1, remaining); }}โครงสร้างนี้ทำให้ file .feature (ที่ product owner อ่านได้) กับ code step definition (ที่นักพัฒนาดูแล) แยกจากกันชัดเจน แต่ยังคง sync กันอยู่เสมอ เพราะ SpecFlow จะ fail การ build ทันทีถ้ามี step ใน file Gherkin ที่ยังไม่มี step definition รองรับ
ประโยชน์และข้อควรระวัง
หัวข้อที่มีชื่อว่า “ประโยชน์และข้อควรระวัง”ประโยชน์
- ร่วมมือและได้ฟีดแบ็กต่อเนื่อง — BDD ส่งเสริมให้นักพัฒนา ผู้ทดสอบ และฝ่ายธุรกิจร่วมกันนิยามและขัดเกลา scenario จนทุกคนเข้าใจตรงกันว่าซอฟต์แวร์ควรทำอะไร
- Living documentation — feature file ที่เขียนด้วย Gherkin ทำหน้าที่เป็นทั้ง spec และชุดทดสอบในตัวเดียว เมื่อ code เปลี่ยน scenario ที่ผูกไว้จะล้มเหลวทันทีถ้าพฤติกรรมไม่ตรงกับที่ตกลงกัน จึงจับปัญหาความเข้าใจผิดได้เร็วกว่ารอถึงรอบ QA
- ลดความกำกวมของคำว่า “test” — การพูดถึง “พฤติกรรม” แทน “การทดสอบ” ช่วยให้ทีมโฟกัสที่ผลลัพธ์เชิงธุรกิจ ไม่ใช่แค่ coverage ตัวเลข
ข้อควรระวัง
- Scenario ระเบิดจำนวน (scenario explosion) — ถ้าไม่ระวังการออกแบบ scenario จะเพิ่มจำนวนแบบทวีคูณตามเงื่อนไข ทำให้ suite รันช้าและดูแลยาก ควรเลือก scenario ที่สื่อความหมายทางธุรกิจจริง ๆ ไม่ใช่ไล่ทุก combination
- ใช้ Gherkin เป็นแค่ wrapper ของ UI automation — ถ้าเขียน step ผูกกับปุ่มและ selector บนหน้าจอโดยตรง scenario จะเปราะบางและหลุดจากภาษาธุรกิจ ทำให้เสียจุดประสงค์หลักของ BDD ไป
- ข้าม Three Amigos — ถ้าให้นักพัฒนาคนเดียวเขียนทั้ง feature file และ step definition โดยไม่คุยกับฝ่ายธุรกิจ BDD จะเหลือแค่ framework test ที่หน้าตาแปลกกว่าเดิม ไม่ได้ความเข้าใจร่วมกันตามเจตนารมณ์เดิม
- ต้นทุนการดูแล step definitions — ทุก step ต้องมี code รองรับ และเมื่อ scenario จำนวนมากขึ้น การ refactor ให้ step ใช้ซ้ำได้จึงสำคัญไม่แพ้การ refactor code production