Sign in

Part of 10306103 หลักการเขียนโปรแกรมเบื้องต้น (Fundamentals of Programming)

2026-10-22 · updated 2026-10-30 · 21 min read

บทที่ 13 มาตรฐานการเขียนโค้ดและแนวคิดการจัดการเวอร์ชัน

ShareFacebookXLinkedInLINE

แผนบริหารการสอนประจำบทที่ 13

บทนี้ว่าด้วยมาตรฐานการเขียนโค้ด (coding standard) และแนวคิดการจัดการเวอร์ชัน (version control) ซึ่งเป็นบททบทวนและสรุปมาตรฐานการเขียนโค้ดที่ได้ฝึกสะสมต่อเนื่องมาตั้งแต่บทที่ 1 แล้วอธิบายแนวคิดของการบันทึกประวัติการเปลี่ยนแปลงของโค้ด เนื้อหาครอบคลุมมาตรฐานสี่ด้านคือ การจัดย่อหน้า (indentation) ให้สม่ำเสมอ การตั้งชื่อ (naming) ให้สื่อความหมายและคงรูปแบบเดียวกันทั้งไฟล์ การใส่คอมเมนต์ (commenting) อธิบายส่วนที่เข้าใจยาก และความสม่ำเสมอของรูปแบบทั้งไฟล์ จากนั้นอธิบายแนวคิดการจัดการเวอร์ชันและหลักการเขียนข้อความบันทึกการเปลี่ยนแปลง (commit message) ที่สื่อความหมาย ซึ่งตรงกับข้อความของ CLO5 ที่ระบุถึง Git commits ที่มีข้อความที่สื่อความหมายโดยตรง โดยใช้ Git เป็นตัวอย่างประกอบเชิงแนวคิด ไม่เน้นการลงมือใช้คำสั่งเป็นงานที่ต้องส่ง

ผลลัพธ์ข้อความหลักฐานCLO
LLO13.1ปฏิบัติตามมาตรฐานการเขียนโค้ด (การจัดย่อหน้า การตั้งชื่อ การใส่คอมเมนต์) อย่างสม่ำเสมองานข้อ 1 (ปฏิบัติการที่ 13 Lab A)CLO5
LLO13.2อธิบายแนวคิดการจัดการเวอร์ชัน (version control) และประโยชน์ของการบันทึกประวัติการเปลี่ยนแปลงของโค้ดงานข้อ 2 (ปฏิบัติการที่ 13 Lab B)CLO5
LLO13.3เขียนข้อความบันทึกการเปลี่ยนแปลง (commit message) ที่สื่อความหมายงานข้อ 3 (ปฏิบัติการที่ 13 Lab B)CLO5
LLO13.4ปฏิบัติตามมาตรฐานการเขียนโค้ด (การจัดย่อหน้า การตั้งชื่อสื่อความหมาย การใส่คอมเมนต์) ในงานโค้ดของบทนี้โค้ดทุกข้อที่ส่งในบทนี้CLO5

CLO ที่เกี่ยวข้อง (ข้อความจากหลักสูตร):

  • CLO5 ปฏิบัติตามมาตรฐานการเขียนโค้ด (Indentation, Naming, Commenting, Git commits ที่มีข้อความที่สื่อความหมาย)

บทที่ 13 เป็นจุดที่นำมาตรฐานการเขียนโค้ดซึ่งถูกกำหนดเป็นจุดตรวจของ CLO5 ในทุกบทมาอธิบายและสรุปอย่างเป็นระบบในที่เดียว แล้วต่อยอดด้วยแนวคิดการจัดการเวอร์ชันและการเขียนข้อความบันทึกการเปลี่ยนแปลงที่สื่อความหมาย จึงเป็นบทที่รวบรวมหลักฐานของ CLO5 ก่อนส่งต่อไปยังโครงงานบูรณาการในบทที่ 15 ที่ต้องส่งมอบโปรแกรมตามมาตรฐานการเขียนโค้ด งานทั้งสามข้อในบทนี้สะสมหลักฐานของ CLO5 ต่อเนื่องจากคุณภาพโค้ดในบทที่ 12 ทั้งนี้ CLO5 (มาตรฐานโค้ด) กำหนดให้คะแนนและตรวจทุกบท (นับในหมวดใบงานบทที่ 1–13 15% ผ่าน LLO1.4 และ LLO X.4 ของบทที่ 2–13) และบทที่ 13 เป็นจุดสรุปและทบทวน CLO5 ของรายวิชา (มติผู้สอน 21 ต.ค. 2569)

วิธีสอน

  1. ทบทวนมาตรฐานการเขียนโค้ดที่ใช้มาตั้งแต่บทที่ 1 ได้แก่ การจัดย่อหน้า 4 ช่องว่าง การตั้งชื่อแบบ snake_case ที่สื่อความหมาย และการใส่คอมเมนต์ส่วนหัว แล้วชี้ให้เห็นว่ามาตรฐานเหล่านี้คือเกณฑ์ของ CLO5 ที่สะสมผ่านทุกบท
  2. สาธิตการเทียบโค้ดชุดเดียวกันที่เขียนติดกันไม่ได้มาตรฐานกับฉบับที่ปรับให้ได้มาตรฐานแล้ว เพื่อให้เห็นผลของการจัดย่อหน้า การตั้งชื่อ และคอมเมนต์ต่อการอ่านและการบำรุงรักษา
  3. อธิบายแนวคิดการจัดการเวอร์ชันว่าช่วยบันทึกประวัติการเปลี่ยนแปลงของโค้ดเพื่อย้อนดูและย้อนกลับได้ โดยยกตัวอย่างลำดับคำสั่ง Git (git init, git add, git commit -m, git log --oneline) เป็นภาพประกอบเชิงแนวคิด
  4. เทียบข้อความ commit ที่สื่อความหมายกับข้อความที่กำกวม เพื่อชี้ว่าข้อความ commit เป็นส่วนหนึ่งของมาตรฐานโค้ดตาม CLO5
  5. มอบหมายให้ลงมือปฏิบัติตามใบงาน โดยกำหนดจุดตรวจระหว่างทางเพื่อให้ข้อมูลป้อนกลับทันทีทั้งด้านมาตรฐานโค้ดและการเขียนข้อความบันทึกการเปลี่ยนแปลง

สื่อการเรียนการสอน

  • เครื่องคอมพิวเตอร์ที่เข้าถึงแพลตฟอร์มการเรียนของรายวิชาสำหรับเขียน คอมไพล์ และรันโปรแกรมภาษา C (มาตรฐาน C11) บนเว็บ
  • เอกสารประกอบบทที่ 13 และสไลด์สรุปมาตรฐานการเขียนโค้ดและแนวคิดการจัดการเวอร์ชัน
  • ไฟล์ตัวอย่างโปรแกรม hello.c และชุดการเปลี่ยนแปลงตัวอย่างสำหรับฝึกเขียนข้อความ commit

การวัดผลและการประเมินผล

กำหนดส่ง: งานข้อ 1–3 ภายใน 23:59 น. ของวันก่อนวันปฏิบัติการในสัปดาห์ที่ 14 ส่วนชุดฝึกท้ายบทและแบบฝึกหัดวัดความเข้าใจของบทนี้ ภายใน 23:59 น. ของวันก่อนวันบรรยายในสัปดาห์ที่ 14 ดูวันที่จริงของตอนเรียนได้ในห้องเรียนออนไลน์ (มติผู้สอน 28 ต.ค. 2569)

ข้องานหลักฐานผลลัพธ์CLO
1รับโค้ดที่เขียนไม่ได้มาตรฐาน แล้วปรับการจัดย่อหน้า การตั้งชื่อ และคอมเมนต์ให้ได้มาตรฐานและสม่ำเสมอไฟล์ซอร์สโค้ด + ผลการคอมไพล์LLO13.1CLO5
2อธิบายแนวคิดการจัดการเวอร์ชันและประโยชน์ของการบันทึกประวัติการเปลี่ยนแปลง จากชุดการแก้ไขโค้ดที่กำหนดคำอธิบายสั้นของผู้เรียนLLO13.2CLO5
3เขียนข้อความ commit ที่สื่อความหมายของการเปลี่ยนแปลงแต่ละครั้งในชุดการแก้ไขที่กำหนดชุดข้อความ commit ที่ผู้เรียนเขียนLLO13.3CLO5

เงื่อนไขผ่าน: งานข้อ 3 ต่อยอดจากชุดการเปลี่ยนแปลงในงานข้อ 2 ดังนั้นต้องอธิบายแนวคิดและระบุการเปลี่ยนแปลงแต่ละครั้งในงานข้อ 2 ให้ครบก่อน จึงจะเขียนและประเมินคุณภาพข้อความ commit ในงานข้อ 3 ได้

คะแนนใบงาน (10 คะแนน)

ผลลัพธ์สิ่งที่ตรวจคะแนน
LLO13.1งานข้อที่ระบุผลลัพธ์นี้3
LLO13.2งานข้อที่ระบุผลลัพธ์นี้3
LLO13.3งานข้อที่ระบุผลลัพธ์นี้3
LLO13.4มาตรฐานโค้ด ตรวจจากโค้ดทุกข้อที่ส่ง1

ใบงานบทที่ 1–13 รวมกันคิดเป็น 15% ของคะแนนรายวิชา ชิ้นละเท่ากัน ส่งช้าหัก 10% ของคะแนนงานต่อสัปดาห์ที่ช้า สูงสุด 50% และรับงานถึงสิ้นสัปดาห์ที่ 15 งานที่ผู้สอนส่งกลับให้แก้นับเวลาจากการส่งครั้งแรก ดูคะแนนของตนเองได้ที่หน้า “คะแนนของฉัน” ในห้องเรียนออนไลน์ของรายวิชา

เกณฑ์ให้คะแนน

งานข้อ 1 ใช้เกณฑ์ผ่าน/ไม่ผ่าน ร่วมกับรายการตรวจ (checklist): จัดย่อหน้าสม่ำเสมอ 4 ช่องว่าง, ตั้งชื่อตัวแปรและฟังก์ชันให้สื่อความหมายตามรูปแบบเดียวกัน, มีคอมเมนต์อธิบายส่วนที่เข้าใจยาก, รูปแบบสม่ำเสมอทั้งไฟล์ และโปรแกรมยังคอมไพล์และทำงานถูกต้อง

เกณฑ์ผ่านยังไม่ผ่าน
งานข้อ 2อธิบายแนวคิดการจัดการเวอร์ชันได้ถูกต้องและระบุประโยชน์ของการบันทึกประวัติการเปลี่ยนแปลงอย่างน้อยสองข้ออธิบายแนวคิดไม่ได้ หรือระบุประโยชน์ไม่ครบ

งานข้อ 3 ใช้เกณฑ์ผ่าน/ไม่ผ่าน ร่วมกับรายการตรวจ: ข้อความ commit บอกชัดว่าการเปลี่ยนแปลงแต่ละครั้งทำอะไร, ไม่ใช้ข้อความกำกวมเช่น update หรือ fix เพียงลำพัง, และข้อความสอดคล้องกับการเปลี่ยนแปลงจริง

เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ

บทนำ

มาตรฐานการเขียนโค้ดคือข้อตกลงร่วมกันเรื่องรูปแบบของโค้ด เพื่อให้โค้ดอ่านง่าย บำรุงรักษาง่าย และทำงานร่วมกันเป็นทีมได้ มาตรฐานสี่ด้านที่ใช้ในรายวิชานี้ตั้งแต่บทที่ 1 ได้แก่ การจัดย่อหน้าให้สม่ำเสมอ การตั้งชื่อให้สื่อความหมาย การใส่คอมเมนต์อธิบายส่วนที่เข้าใจยาก และความสม่ำเสมอของรูปแบบทั้งไฟล์ บทนี้รวบรวมมาตรฐานเหล่านี้ไว้ในที่เดียวเพื่อสรุปและประเมิน จากนั้นอธิบายแนวคิดการจัดการเวอร์ชัน ซึ่งเป็นแนวทางบันทึกประวัติการเปลี่ยนแปลงของโค้ด ทำให้ย้อนดูได้ว่าแต่ละเวอร์ชันเปลี่ยนอะไรและย้อนกลับได้เมื่อจำเป็น ข้อความของ CLO5 ระบุถึงการปฏิบัติตามมาตรฐานการเขียนโค้ดและ Git commits ที่มีข้อความที่สื่อความหมาย บทนี้จึงตอบ CLO5 โดยตรง โดยเน้นที่แนวคิดและข้อความบันทึกการเปลี่ยนแปลง ส่วนการลงมือใช้เครื่องมืออย่าง Git เป็นการศึกษาเพิ่มเติม

มาตรฐานการเขียนโค้ดและแนวคิดการจัดการเวอร์ชันในบทนี้เป็นพื้นฐานที่ส่งต่อไปยังบทถัดไป โครงงานบูรณาการในบทที่ 15 ต้องส่งมอบโปรแกรมที่มีคุณภาพตามมาตรฐานการเขียนโค้ด บทนี้จึงเป็นการเตรียมความพร้อมทั้งด้านรูปแบบโค้ดและแนวคิดการจัดการเวอร์ชัน

สิ่งที่ได้จากบทนี้ใช้ต่อในบท
มาตรฐานการเขียนโค้ดแบบสรุป (การจัดย่อหน้า การตั้งชื่อ คอมเมนต์ ความสม่ำเสมอ)บท 15 (โครงงานบูรณาการ)
แนวคิดการจัดการเวอร์ชันและประโยชน์ของการบันทึกประวัติบท 15 (โครงงานบูรณาการ)
การเขียนข้อความ commit ที่สื่อความหมายบท 15 (โครงงานบูรณาการ)

ความรู้พื้นฐาน เครื่องมือ และรุ่นซอฟต์แวร์

บทนี้ต้องใช้สภาพแวดล้อมสำหรับเขียน คอมไพล์ และรันโปรแกรมภาษา C และต้องมีความรู้เรื่องโครงสร้างโปรแกรมภาษา C จากบทที่ 1 รวมถึงมาตรฐานการตั้งชื่อแบบ snake_case และการจัดย่อหน้า 4 ช่องว่างที่ใช้มาตั้งแต่บทที่ 1 ตารางด้านล่างแสดงรุ่นที่ใช้ตรวจชุดสอนพร้อมใช้ครั้งนี้ แยกจากบันทึกตัวอย่างเดิมซึ่งระบุ GCC 13.3.0 และ Git 2.43.0

เครื่องมือรุ่นที่ทดสอบหน้าที่
คอมไพเลอร์ GCC6.3.0 (MinGW-w64 Windows), 12.2.0 (Debian Linux)ตรวจโปรแกรมภาษา C ในชุดสอนฉบับนี้
Git สำหรับสาธิตเสริม2.51.0.windows.1 และ 2.39.5 (Linux)ตรวจสามสถานะ diff และการบันทึกเฉพาะที่เลือก
มาตรฐานภาษาC11 (-std=c11)กำหนดไวยากรณ์ภาษา C ที่ใช้อ้างอิง
⚠️Warning

บันทึกต้นฉบับระบุการทดสอบด้วย GCC 13.3.0 และ Git 2.43.0 ส่วนชุดสอนฉบับนี้ตรวจซ้ำด้วยเครื่องมือตามตาราง ไม่อ้างว่าได้รันรุ่นเดิมซ้ำ รหัส commit (hash) ที่แสดงในตัวอย่างเดิมเป็นภาพประกอบ ไม่ใช่ผลทดสอบรอบปัจจุบัน และไม่จำเป็นต้องเปลี่ยนทุกครั้งถ้าวัตถุ commit เหมือนกันทุกส่วน หากใช้เครื่องมือหรือระบบปฏิบัติการอื่น ข้อความบางส่วนอาจต่างกันเล็กน้อย แต่แนวคิดและซอร์สโค้ดภาษา C มาตรฐานใช้ได้เหมือนกัน

วิธีใช้ชุดสอนบทที่ 13

ทบทวนจาก บทที่ 12 การวัดประสิทธิภาพและคุณภาพโค้ด ว่าความเร็วกับความถูกต้องต้องมีหลักฐาน บทนี้เพิ่มการอ่านโค้ด การรักษาพฤติกรรม และการบันทึกสิ่งที่เปลี่ยนให้ตรวจย้อนหลังได้

อ่านข้อตกลงของโปรแกรมก่อนเทียบฉบับ แล้วทดลองกรณีขอบเขต เขียนสิ่งที่พบในใบงาน และให้เพื่อนตรวจ diff งานหลักยังเป็น Lab A–B ตาม LLO13.1–13.3 ไม่เพิ่มข้อบังคับติดตั้ง Git หรือส่งลิงก์คลังออนไลน์

ใบงานในหน้านี้เป็นตารางสำหรับคัดลงสมุดหรือเอกสาร ไม่ใช่ช่องกรอกที่เว็บไซต์บันทึกคำตอบอัตโนมัติ คะแนนและเกณฑ์ผ่านในตัวอย่างเป็นข้อมูลสมมติสำหรับฝึกเขียนโปรแกรม ไม่ใช่นโยบายตัดเกรดของรายวิชา

13.1 มาตรฐานการเขียนโค้ด

ระดับที่ 1: โค้ดที่ดีไม่ได้วัดจากการทำงานถูกต้องเพียงอย่างเดียว แต่ยังต้องอ่านง่ายและบำรุงรักษาง่าย มาตรฐานการเขียนโค้ด (coding standard) คือข้อตกลงร่วมเรื่องรูปแบบของโค้ดที่ช่วยให้บรรลุเป้าหมายนี้

ระดับที่ 2: มาตรฐานหลักที่ใช้ในรายวิชานี้มีสี่ด้าน ด้านแรกคือการจัดย่อหน้า (indentation) โดยเยื้องบรรทัดในบล็อกเดียวกันเท่ากัน 4 ช่องว่าง เพื่อให้เห็นโครงสร้างของเงื่อนไขและการวนซ้ำชัดเจน ด้านที่สองคือการตั้งชื่อ (naming) ตัวแปรและฟังก์ชันให้สื่อความหมาย ใช้รูปแบบ snake_case อย่างคงเส้นคงวา เช่น width และ area แทนชื่อย่ออย่าง a หรือ c ด้านที่สามคือการใส่คอมเมนต์ (commenting) อธิบายเฉพาะส่วนที่เข้าใจยากหรือเจตนาของโค้ด ไม่ใช่อธิบายสิ่งที่อ่านจากโค้ดได้อยู่แล้ว และด้านที่สี่คือความสม่ำเสมอ (consistency) ของรูปแบบทั้งไฟล์

ระดับที่ 3: ความสม่ำเสมอเป็นหัวใจของมาตรฐานโค้ด เพราะแม้แต่ละรูปแบบจะมีทางเลือกได้หลายแบบ แต่การใช้รูปแบบเดียวกันตลอดทั้งไฟล์และทั้งโครงการช่วยให้ผู้อ่านคาดเดาโครงสร้างได้และลดความสับสน มาตรฐานทั้งสี่ด้านนี้เป็นเกณฑ์ของ CLO5 ที่ฝึกสะสมมาตั้งแต่บทที่ 1 จนถึงบทนี้ เหตุผลเชิงคุณภาพคือโค้ดที่อ่านง่ายทำให้แก้ไขและต่อยอดได้เร็ว ลดข้อผิดพลาด และทำงานเป็นทีมได้ราบรื่น

คำถามตรวจความเข้าใจ 13.1: มาตรฐานการเขียนโค้ดสี่ด้านในรายวิชานี้มีอะไรบ้าง และเหตุใดความสม่ำเสมอของรูปแบบจึงสำคัญ

ใบงาน 1: ตกลงพฤติกรรมก่อนทำให้โค้ดอ่านง่าย

สมมติฟังก์ชันนับคะแนนที่มากกว่าหรือเท่ากับ threshold โดยไม่แก้ข้อมูลต้นทาง ผู้เรียกส่งจำนวนสมาชิกตั้งแต่ 0 ถึง 8 และอาร์เรย์ที่อ่านได้ครบจำนวนนั้น คะแนนและ threshold อยู่ในช่วง 0–100

เมื่อ count เป็น 0 ฟังก์ชันต้องคืน 0 โดยไม่อ่านสมาชิก กรณีนี้อาร์เรย์ตัวอย่างยังมีพื้นที่จริงหนึ่งช่อง แต่กำหนดจำนวนสมาชิกที่ใช้งานเป็น 0 การมีพื้นที่กับการมีข้อมูลที่ต้องประมวลผลเป็นคนละเรื่อง

กรณีที่ต้องตรวจข้อมูลthresholdcountผลที่ตนคาดเหตุผล
ต่ำกว่า/เท่ากับ/สูงกว่า49, 50, 51503
สมาชิกเดียวตรงเกณฑ์50501
ไม่มีสมาชิกที่ใช้งานไม่อ่านสมาชิก500
เกณฑ์ต่ำสุด0, 0, 003
เกณฑ์สูงสุด100, 991002

กำหนดผลก่อนรันแล้วบันทึกผลจริงแยกกัน การรันแล้วนำผลนั้นมาตั้งเป็นคำตอบคาดหวังทันทีอาจทำให้บั๊กกลายเป็นเกณฑ์ตรวจของตนเอง

ใบงาน 2: คอมเมนต์ต้องช่วยตรวจข้อตกลง

คอมเมนต์ที่ดีทำให้ทราบสิ่งที่ชื่อยังบอกไม่หมด เช่น ใครตรวจช่วงข้อมูลแล้ว เหตุใดค่าที่เท่ากับเกณฑ์จึงนับผ่าน หรือฟังก์ชันแก้ข้อมูลต้นทางหรือไม่ ส่วนชื่อควรทำให้เห็นหน้าที่หลักโดยไม่ต้องอาศัยคำอธิบายทุกบรรทัด

ข้อความที่พบข้อมูลที่ผู้อ่านได้เพิ่มตรงกับโค้ดหรือไม่ควรเก็บ/แก้/ลบ พร้อมเหตุผล
เพิ่มตัวนับหนึ่ง บน ++passed_count
ผู้เรียกส่งสมาชิกที่อ่านได้ครบ count ตัว
นับเฉพาะคะแนนมากกว่าเกณฑ์ แต่โค้ดใช้ >=
คะแนนนี้เป็นข้อมูลสมมติสำหรับทดสอบ

คำอธิบายว่า “ผู้เรียกตรวจแล้ว” ต้องมีหลักฐานในจุดเรียกหรือข้อตกลง ไม่ใช้คอมเมนต์เพื่อทำให้เชื่อว่ามีการตรวจทั้งที่ไม่มี ถ้าเปลี่ยนหน้าที่รับข้อมูล ต้องตรวจว่าคอมเมนต์ยังตรงกับหน้าที่นั้นด้วย

การเยื้อง 4 ช่องและ snake_case เป็นข้อตกลงของรายวิชา ส่วน C11 เป็นมาตรฐานภาษา การจัดรูปแบบตามข้อตกลงไม่ได้ทำให้โค้ดผิดไวยากรณ์กลายเป็นถูก และคอมไพล์ผ่านก็ไม่ได้ยืนยันว่าตั้งชื่อสื่อความหมาย

13.2 ตัวอย่างก่อน–หลังปรับมาตรฐาน

ระดับที่ 1: โค้ดที่ทำงานได้อย่างเดียวกันอาจอ่านง่ายต่างกันมาก ขึ้นกับการจัดย่อหน้า การตั้งชื่อ และคอมเมนต์

ระดับที่ 2: โค้ดต่อไปนี้เป็นฉบับก่อนปรับมาตรฐาน เขียนติดกันในบรรทัดเดียว ตั้งชื่อตัวแปรเป็นอักษรเดี่ยวที่ไม่สื่อความหมาย และไม่มีคอมเมนต์

C
/* ก่อน: ชื่อไม่สื่อความหมาย ไม่จัดย่อหน้า ไม่มีคอมเมนต์ */
#include <stdio.h>
int main(void){int a=5,b=3,c;c=a*b;printf("%d\n",c);return 0;}

เมื่อปรับให้ได้มาตรฐานทั้งสี่ด้าน จะได้ฉบับหลังที่ตั้งชื่อสื่อความหมาย จัดย่อหน้า 4 ช่องว่าง และมีคอมเมนต์อธิบายเจตนาของการคำนวณ

C
/* หลัง: ตั้งชื่อสื่อความหมาย จัดย่อหน้า 4 ช่องว่าง มีคอมเมนต์ */
#include <stdio.h>
 
int main(void) {
    int width = 5;
    int height = 3;
    int area = width * height;   /* คำนวณพื้นที่สี่เหลี่ยม */
    printf("%d\n", area);
    return 0;
}

ระดับที่ 3: ฉบับหลังอ่านแล้วเข้าใจเจตนาได้ทันทีว่าโปรแกรมคำนวณพื้นที่สี่เหลี่ยมจากความกว้างและความสูง ขณะที่ฉบับก่อนต้องไล่อ่านทีละตัวอักษรเพื่อเดาว่าตัวแปรแต่ละตัวหมายถึงอะไร ผลต่อการบำรุงรักษาคือเมื่อมีผู้อื่นหรือแม้แต่ผู้เขียนเองกลับมาแก้ไขในภายหลัง ฉบับที่ได้มาตรฐานจะแก้ไขได้เร็วและพลาดน้อยกว่า เมื่อทำงานเป็นทีมมาตรฐานที่สม่ำเสมอยังช่วยให้สมาชิกอ่านโค้ดของกันและกันได้โดยไม่ต้องปรับความเคยชินใหม่ทุกครั้ง

คำถามตรวจความเข้าใจ 13.2: การตั้งชื่อตัวแปรว่า area ดีกว่า c ในแง่มาตรฐานโค้ดอย่างไร

ตัวอย่างคู่: เปลี่ยนชื่อและโครงสร้างโดยรักษาคำตอบ

สร้างไฟล์ compact_count.c ฉบับตั้งต้นนี้จงใจเขียนให้อ่านยากสำหรับการเปรียบเทียบ ไม่ใช่รูปแบบแนะนำให้เลียนแบบ ตัวแปร n คือจำนวนสมาชิก ส่วน t คือเกณฑ์ที่นับรวมค่าที่เท่ากันด้วย

C
/* compact_count.c : intentionally compact exercise input */
#include <stdio.h>
int f(const int a[],int n,int t){int p=0;for(int i=0;i<n;++i){if(a[i]>=t){++p;}}return p;}
int main(void){const int a[]={40,60,50,80,70};printf("passed=%d\n",f(a,5,50));return 0;}

สร้าง readable_count.c อีกไฟล์ แยกหน้าที่การนับออกจากการแสดงผล ชื่อฟังก์ชันสื่อว่าคืนจำนวนที่ผ่าน ส่วนคอมเมนต์ระบุข้อตกลงของผู้เรียก ไม่ทวนทุกคำสั่งในลูป

C
/* readable_count.c : retain the counting rule while improving names */
#include <stdio.h>
 
/* Caller supplies count readable elements; count is 0..8. */
int count_passed(const int scores[], int count, int threshold)
{
    int passed_count = 0;
    for (int i = 0; i < count; ++i) {
        if (scores[i] >= threshold) {
            ++passed_count;
        }
    }
    return passed_count;
}
 
int main(void)
{
    const int scores[] = {40, 60, 50, 80, 70};
    const int passing_threshold = 50;
    const int passed_count = count_passed(scores, 5, passing_threshold);
 
    printf("passed=%d\n", passed_count);
    return 0;
}

คอมไพล์เป็นคนละชื่อเพื่อไม่รันไฟล์เก่าทับกัน ทั้งคู่ควรแสดง passed=4 สำหรับข้อมูลสาธิตนี้ จากนั้นเทียบฟังก์ชันกับใบงาน 1 ผลเดียวกันเพียงข้อมูลชุดนี้ยังไม่พิสูจน์ว่าทุกอินพุตให้ผลเท่ากัน

BASH
gcc -std=c11 -Wall -Wextra -Wpedantic compact_count.c -o compact_count
gcc -std=c11 -Wall -Wextra -Wpedantic readable_count.c -o readable_count
./compact_count
./readable_count

คำสั่งรันข้างต้นเป็นแบบเชลล์บน Linux/macOS ถ้าใช้ PowerShell กับ GCC บน Windows ให้สร้างชื่อที่ลงท้าย .exe และรันด้วย .\compact_count.exe หรือ .\readable_count.exe ตามไฟล์ที่สร้าง

จุดที่เปลี่ยนเดิมใหม่เหตุใดช่วยอ่านควรเปลี่ยนผลหรือไม่
ชื่อฟังก์ชันfcount_passed
ชื่อตัวนับppassed_count
รูปแบบหนึ่งบรรทัดบล็อกเยื้อง 4 ช่อง
เงื่อนไขนับรวมค่าเท่ากับนับรวมค่าเท่ากับ

ตัวอย่างตรวจซ้ำ: จัดรูปแบบแล้วอย่าทำค่าขอบเขตหาย

ไฟล์ count_regression.c รวมกรณีตรวจที่กำหนดคำตอบไว้ก่อน ฟังก์ชันนับใช้กติกาเดียวกับฉบับอ่านง่าย ส่วน main เทียบผลและคืนสถานะไม่เป็นศูนย์เมื่อพบความผิดพลาด จึงใช้ได้แม้กำหนด NDEBUG

C
/* count_regression.c : explicit regression checks, independent of assert */
#include <stdio.h>
 
int count_passed(const int scores[], int count, int threshold)
{
    int passed_count = 0;
    for (int i = 0; i < count; ++i) {
        if (scores[i] >= threshold) {
            ++passed_count;
        }
    }
    return passed_count;
}
 
struct CountCase {
    int scores[8];
    int count;
    int threshold;
    int expected;
};
 
int main(void)
{
    const struct CountCase cases[] = {
        {{0}, 0, 50, 0},
        {{49, 50, 51}, 3, 50, 2},
        {{50}, 1, 50, 1},
        {{49}, 1, 50, 0},
        {{51}, 1, 50, 1},
        {{0, 100, 50, 49}, 4, 50, 2},
        {{0, 0, 0}, 3, 0, 3},
        {{100, 99}, 2, 100, 1}
    };
    const int case_count = (int)(sizeof cases / sizeof cases[0]);
    int failed_count = 0;
 
    for (int i = 0; i < case_count; ++i) {
        const int actual = count_passed(cases[i].scores,
                                        cases[i].count,
                                        cases[i].threshold);
        if (actual != cases[i].expected) {
            printf("FAIL case=%d expected=%d actual=%d\n",
                   i + 1, cases[i].expected, actual);
            ++failed_count;
        } else {
            printf("PASS case=%d\n", i + 1);
        }
    }
    printf("failed=%d\n", failed_count);
    return failed_count == 0 ? 0 : 1;
}

ก่อนรัน เลือกสองกรณีที่แยกเงื่อนไข >= กับ > ได้ แล้วคาดว่าถ้าเผลอเปลี่ยนเครื่องหมายจะเกิดอะไรขึ้น ทดลองเฉพาะสำเนาสำหรับค้นบั๊ก จากนั้นกลับมาใช้ฉบับถูกต้อง ไม่ปนฉบับผิดกับไฟล์ส่งงาน

กรณีตรวจนี้เป็นหลักฐานเฉพาะขอบเขตที่ตรวจ ไม่รับรองอินพุตที่ละเมิดข้อตกลง เช่น count เกินพื้นที่อาร์เรย์ ฟังก์ชันนี้ยังไม่มีหน้าที่รับข้อความจากผู้ใช้หรือรายงานข้อมูลผิดช่วง

13.3 แนวคิดการจัดการเวอร์ชัน

ระดับที่ 1: การจัดการเวอร์ชัน (version control) คือแนวทางบันทึกประวัติการเปลี่ยนแปลงของโค้ด ทำให้ย้อนดูได้ว่าแต่ละช่วงเปลี่ยนอะไร และย้อนกลับไปยังเวอร์ชันก่อนหน้าได้เมื่อจำเป็น เครื่องมือที่ใช้กันทั่วไปตัวหนึ่งคือ Git

ระดับที่ 2: โดยแนวคิด การบันทึกเวอร์ชันหนึ่งครั้งเรียกว่า commit ซึ่งเก็บสถานะของไฟล์ ณ ช่วงนั้นพร้อมข้อความอธิบายการเปลี่ยนแปลง ตัวอย่างลำดับคำสั่งของ Git เพื่อประกอบความเข้าใจมีดังนี้ โดยทั่วไปเริ่มจากสร้างคลังเก็บ (repository) เตรียมไฟล์ที่จะบันทึก แล้วบันทึกเป็นเวอร์ชันพร้อมข้อความ

BASH
git init -b main
git add hello.c
git commit -m "เพิ่มโปรแกรม hello เวอร์ชันแรก"

ระดับที่ 3: คำสั่ง git log --oneline แสดงประวัติ commit บรรทัดละรายการ โดยขึ้นต้นด้วยรหัส commit แบบย่อตามด้วยข้อความ รหัส commit (hash) อ้างถึงวัตถุ commit ถ้า tree, parent, ข้อมูลผู้เขียน/ผู้บันทึก เวลา หรือข้อความเปลี่ยน รหัสโดยทั่วไปก็เปลี่ยน แต่ถ้าวัตถุ commit เหมือนกันทุกส่วนจะได้รหัสเดียวกัน การเก็บประวัติเป็นลำดับเช่นนี้ทำให้ตรวจสอบได้ว่าโค้ดพัฒนามาอย่างไร และเป็นเหตุผลที่งานจริงใช้การจัดการเวอร์ชันเพื่อทำงานร่วมกันและกู้คืนเวอร์ชันเก่าได้ บทนี้เน้นที่แนวคิดและข้อความบันทึกการเปลี่ยนแปลง ส่วนการลงมือใช้คำสั่ง Git อย่างละเอียดเป็นการศึกษาเพิ่มเติม ไม่ใช่งานที่ต้องส่ง

คำถามตรวจความเข้าใจ 13.3: การจัดการเวอร์ชันช่วยการพัฒนาโปรแกรมอย่างไร และข้อความประกอบ commit มีไว้เพื่ออะไร

13.4 ข้อความ commit ที่สื่อความหมาย

ระดับที่ 1: ข้อความ commit ที่ดีบอกได้ว่าการเปลี่ยนแปลงครั้งนั้นทำอะไร เพื่อให้อ่านประวัติแล้วเข้าใจได้โดยไม่ต้องเปิดดูโค้ดทั้งหมด

ระดับที่ 2: ข้อความที่สื่อความหมายควรระบุการกระทำและสิ่งที่เปลี่ยนอย่างชัดเจน เช่น "แก้ข้อความทักทายเป็น Hello, World" ซึ่งอ่านแล้วทราบทันทีว่าเปลี่ยนอะไร ส่วนข้อความกำกวมอย่าง "update" หรือ "fix" เพียงลำพัง ไม่ได้บอกว่าปรับปรุงหรือแก้ไขส่วนใด เมื่อประวัติยาวขึ้นจะยากต่อการค้นหาว่าการเปลี่ยนแปลงแต่ละครั้งเกิดอะไรขึ้น

TEXT
ดี:   แก้ข้อความทักทายเป็น Hello, World
กำกวม: update

ระดับที่ 3: ข้อความ commit เป็นส่วนหนึ่งของมาตรฐานการเขียนโค้ดตาม CLO5 โดยตรง เพราะช่วยให้ทีมและผู้ตรวจอ่านประวัติการพัฒนาแล้วเข้าใจที่มาของแต่ละเวอร์ชัน แนวทางที่ดีคือเขียนข้อความให้สั้น กระชับ และสื่อถึงเจตนาของการเปลี่ยนแปลง เช่นเริ่มด้วยคำกริยาที่บอกการกระทำ และหลีกเลี่ยงข้อความที่กว้างเกินไปจนไม่สื่อความ การฝึกเขียนข้อความ commit ที่สื่อความหมายตั้งแต่ต้นจึงเป็นนิสัยที่ส่งเสริมคุณภาพของงานในระยะยาว

คำถามตรวจความเข้าใจ 13.4: ข้อความ commit ว่า fix ด้อยกว่าข้อความที่สื่อความหมายอย่างไร

13.5 กรณีศึกษาต่อเนื่อง: ทำให้โปรแกรมคะแนนอ่านตามกติกาได้

มาตรฐานการเขียนโค้ดช่วยให้ผู้อ่านเห็นเจตนาและตรวจข้อผิดพลาดได้ง่ายขึ้น แต่การจัดย่อหน้าสวยไม่รับรองว่าคำนวณถูก และชื่อที่ยาวก็ไม่ได้สื่อความเสมอไป ให้เริ่มจากคำศัพท์ของโจทย์ เช่น คะแนน จำนวนรายการ และคะแนนที่ผ่าน แทนชื่อ a, b, x โดยไม่ต้องเพิ่มคำที่ไม่ช่วยแยกความหมาย

13.5.1 ก่อนและหลังต้องรักษาพฤติกรรมเดียวกัน

C
#include <stdio.h>
 
int count_passed(const int scores[], int count, int threshold)
{
    int passed_count = 0;
    for (int i = 0; i < count; ++i) {
        if (scores[i] >= threshold) {
            ++passed_count;
        }
    }
    return passed_count;
}
 
int main(void)
{
    const int scores[] = {40, 60, 50, 80, 70};
    const int passing_threshold = 50;
 
    printf("passed=%d\n",
           count_passed(scores, 5, passing_threshold));
    return 0;
}

ผลคือ passed=4 ตัวอย่างเปลี่ยนค่าที่มีความหมายเชิงกติกาอย่าง 50 เป็น passing_threshold ไม่ใช่เปลี่ยนเลขทุกตัวเป็นชื่อยาวทั้งหมด ตัวนับเริ่มศูนย์และเงื่อนไขเพิ่มทีละหนึ่งยังอ่านได้ตรง ความตั้งใจคือทำให้ผู้ตรวจรู้ว่าเกณฑ์อยู่ที่ใดและเปลี่ยนได้โดยไม่ต้องตามหาเลข 50 ทุกแห่ง

สมมติฉบับเดิมใช้ชื่อ p แทนจำนวนที่ผ่าน ก่อนปรับต้องมีผลทดสอบเก็บไว้ เมื่อเปลี่ยนชื่อและแยกฟังก์ชันแล้วใช้ข้อมูลเดิมตรวจอีกครั้ง หากถือโอกาสเปลี่ยนจาก >= เป็น > ด้วย จะเป็นการเปลี่ยนพฤติกรรมตรงค่าขอบเขต ไม่ควรบันทึกว่าเป็นเพียงจัดรูปแบบ

13.5.2 คอมเมนต์ที่บอกเหตุผลมีประโยชน์กว่าทวนคำสั่ง

คอมเมนต์ “เพิ่ม count หนึ่ง” บน ++count; มักไม่ได้บอกข้อมูลใหม่ แต่ “นับเฉพาะคะแนนที่ผ่านการตรวจช่วงแล้ว” อธิบายข้อตกลงซึ่งผู้อ่านอาจมองไม่เห็นจากบรรทัดเดียว คอมเมนต์ควรปรับเมื่อกติกาเปลี่ยน ไม่ปล่อยให้ชื่อและข้อความเล่าคนละพฤติกรรม

ไม่ใส่ข้อมูลส่วนบุคคลจริงลงหัวไฟล์เพื่อทำตัวอย่างชื่อผู้เขียนหรือรหัสผู้เรียน ใช้ข้อความสมมติหรือข้อมูลที่ผู้เรียนกรอกเฉพาะตามช่องส่งงานที่กำหนด การสื่อสารตัวตนเพื่อประเมินในรายวิชาไม่ใช่เหตุผลให้เผยแพร่ข้อมูลเหล่านั้นในคลังสาธารณะ

13.6 เข้าใจเวอร์ชันผ่านเหตุการณ์ก่อนใช้คำสั่ง

13.6.1 สำเนาสุดท้ายหลายชื่อทำให้ตรวจประวัติยากอย่างไร

ถ้ามี final.c, final2.c และ final_really.c ชื่อไฟล์ไม่บอกว่าฉบับใดแก้กรณีคะแนนเท่ากับ 50 หรือฉบับใดผ่านการทดสอบ การบันทึกเวอร์ชันควรตอบได้ว่าสถานะใดเปลี่ยนเรื่องอะไร มีเหตุผลใด และตรวจด้วยหลักฐานใด

ใช้ลำดับสมมติ V1 รับข้อมูลและแสดงได้ V2 เพิ่มตรวจช่วง และ V3 แยกฟังก์ชันโดยผลเดิมไม่เปลี่ยน แต่ละเวอร์ชันควรมีขอบเขตที่อธิบายได้ ถ้ารวมการจัดหน้า เปลี่ยนสูตร และลบกรณีทดสอบไว้ในก้อนเดียว จะยากต่อการแยกว่าสิ่งใดทำให้ผลเปลี่ยน

13.6.2 working tree, staging และ commit เป็นคนละสถานะ

ใน Git ไฟล์ที่แก้ในพื้นที่ทำงานยังไม่ใช่สิ่งที่จะอยู่ใน commit ทั้งหมดโดยอัตโนมัติ staging เลือกสถานะที่จะบันทึก และ commit บันทึก snapshot ที่เลือกไว้ ถ้าแก้ไฟล์เพิ่มเติมหลัง stage การเปลี่ยนล่าสุดนั้นอาจยังไม่เข้า commit ต้องตรวจสถานะอีกครั้ง

ข้อเท็จจริงนี้อ้างอิงจาก Pro Git: Recording Changes to the Repository บทนี้เน้นแนวคิดและการเขียนบันทึก การทดลองคำสั่ง Git เป็นทางเลือกเมื่อเครื่องมือพร้อม ไม่ใช่ข้อกำหนดใหม่ให้ผู้เรียนติดตั้ง Git เปิดบัญชี หรือสร้าง repository เพื่อผ่านงานหลัก

ใบงาน 3: จำลองสถานะด้วยบัตรสามใบ

ใช้กระดาษสามใบแทน commit ล่าสุด, staging และ working tree เริ่มจาก hello.c ที่พิมพ์ Hello ทุกใบ แก้เฉพาะบัตร working tree ให้พิมพ์ Hello, World แล้วคัดไป staging เมื่อจำลองการเลือกบันทึก

จากนั้นแก้ working tree ให้พิมพ์ Welcome โดยไม่คัดไป staging อีกครั้ง เมื่อจำลอง commit แบบปกติด้วยสิ่งที่เลือกไว้ ให้เติมตารางว่าแต่ละพื้นที่เก็บข้อความใด ห้ามแก้บัตรอื่นพร้อมกันโดยไม่อธิบายเหตุการณ์

เหตุการณ์commit ล่าสุดstagingworking treeถ้าบันทึกตอนนี้ได้ข้อความใด
เริ่มจากฉบับแรกHelloHelloHello
แก้ครั้งแรก
เลือกบันทึกครั้งแรก
แก้เพิ่มโดยยังไม่เลือก
commit ตามที่เลือกไว้

Git เก็บภาพสถานะที่เลือกใน index หรือ staging area สำหรับการ commit แบบปกติในบทนี้ จึงมีไฟล์เดียวที่ทั้ง staged และมีการแก้เพิ่มซึ่งยังไม่ staged ได้

แนวคิดนี้ตรวจได้จาก Pro Git เรื่องการบันทึกการเปลี่ยนแปลง

คำอธิบายนี้ใช้กับ git commit -m โดยไม่ระบุ path หรือ -a ซึ่งมีวิธีเลือกเนื้อหาต่างกันตาม คู่มือ git commit เริ่มจากรูปแบบเดียวให้เข้าใจก่อน ไม่ต้องทดลองตัวเลือกอื่นเพื่อส่งงานหลัก

13.7 เวิร์กช็อปขยาย: ตรวจการเปลี่ยนและเขียนข้อความที่ตรวจย้อนกลับได้

13.7.1 แยกการเปลี่ยนสามประเภท

เริ่มด้วยโค้ดโปรแกรมคะแนนหนึ่งฉบับ ทำสำเนางานทดลองสำหรับการจัดรูปแบบ การแยกฟังก์ชัน และการแก้บั๊ก แต่ละส่วนต้องบอกว่าพฤติกรรมควรเปลี่ยนหรือไม่ การจัดย่อหน้าอย่างเดียวควรรักษาผลเดิม ส่วนการแก้บั๊กที่ขอบเขตต้องมีกรณีที่ผลก่อนแก้ผิดและหลังแก้ถูกตามข้อกำหนด

เขียนบันทึกการเปลี่ยนแบบ “ตรวจคะแนนนอกช่วงก่อนสะสมผลรวม” แล้วขยายคำอธิบายว่าก่อนแก้ค่าติดลบถูกนำไปรวม หลังแก้ปฏิเสธก่อนเปลี่ยนยอด และตรวจด้วยข้อมูลใด หลีกเลี่ยงข้อความ fix หรือ update เพียงคำเดียว เพราะไม่ช่วยเลือกเวอร์ชันเมื่อมีปัญหาภายหลัง

13.7.2 ซ้อมตรวจ diff ด้วยตาราง แม้ไม่ใช้ Git

ทำตารางสามช่อง ได้แก่บรรทัดก่อนแก้ บรรทัดหลังแก้ และเหตุผล ให้เพื่อนตรวจว่าแต่ละการเปลี่ยนเกี่ยวข้องกับวัตถุประสงค์เดียวกันหรือไม่ หากพบเลขเกณฑ์เปลี่ยนในงานที่อ้างว่าแก้ชื่ออย่างเดียว ให้แยกออกและถามว่ามีข้อกำหนดรองรับหรือไม่

ผู้ที่เลือกทดลอง Git สามารถใช้เครื่องมือที่ได้รับอนุญาตเพื่อดูสถานะและ diff แต่ควรเข้าใจผลก่อนสั่งบันทึก ไม่ใส่รหัสผ่าน โทเคน หรือข้อมูลผู้เรียนจริงในตัวอย่างไฟล์ประวัติ ผู้ที่ไม่ใช้ Git ให้ส่งตารางเวอร์ชันพร้อมไฟล์ฉบับที่กำหนดตามงานเดิมได้

ท้ายงานเลือกเวอร์ชันที่ต้องส่งโดยตรวจว่าสอดคล้องกับผลทดสอบและคำอธิบาย ไม่ใช่เลือกไฟล์ที่มีเวลาแก้ล่าสุดเพียงอย่างเดียว บันทึกความแตกต่างที่สำคัญกับข้อจำกัดที่ยังเหลือไว้ การส่งมอบที่ชัดเจนช่วยให้ผู้รับประเมินงานและทำซ้ำได้โดยไม่ต้องเดา

ใบงาน 5: ให้ข้อความบันทึกตรงกับขอบเขตที่เปลี่ยน

พิจารณาว่าจะเก็บพฤติกรรมเดิมหรือเปลี่ยนตามข้อกำหนดก่อนเลือกชื่อบันทึก การแยกฟังก์ชันที่ได้คำตอบเดิมเป็นการปรับโครงสร้าง ส่วนการเพิ่มการปฏิเสธอินพุตผิดช่วงเป็นพฤติกรรมใหม่ แม้ทั้งคู่ทำให้โค้ดอ่านง่ายขึ้น

การแก้ในตัวอย่างประเภทผลเดิมควรคงหรือเปลี่ยนหลักฐานที่ต้องมีควรรวมกับงานใด
เยื้องบล็อก 4 ช่องโดยคำสั่งเดิม
เปลี่ยน p เป็น passed_count ทุกจุด
แยกการนับเป็นฟังก์ชันโดยเงื่อนไขเดิม
เปลี่ยน >= เป็น >
เพิ่มตรวจคะแนนนอกช่วง
เปลี่ยนข้อความผลลัพธ์

ถ้าผู้ตรวจพบเงื่อนไขเปลี่ยนในงานที่ระบุว่าเปลี่ยนชื่ออย่างเดียว ให้เทียบข้อกำหนดและทดสอบขอบเขต อย่าแก้ข้อความบันทึกให้คลุมเครือเพื่อซ่อนการเปลี่ยนพฤติกรรม แยกงานที่มีเหตุผลต่างกันให้ติดตามง่าย

ใบงาน 6: อ่าน diff ก่อนเขียนหัวเรื่องและเหตุผล

ข้อความบันทึกควรบอกการกระทำกับสิ่งที่เปลี่ยน ส่วนรายละเอียดอธิบายเหตุผลและหลักฐานที่จำเป็น ใช้ภาษาไทยหรืออังกฤษที่ทีมอ่านตรงกัน ไม่กำหนดคำนำหน้าแบบใดเป็นเงื่อนไขใหม่ของงานนี้

ข้อความตั้งต้นสิ่งที่ยังไม่ทราบข้อความที่ตนเขียนใหม่ตรงกับ diff ใด
update
ทำให้ดีขึ้น
fix score
จัดรูปแบบและเปลี่ยนกติกาและเพิ่มเมนู

เขียนร่างแยกหัวเรื่อง เหตุผล และผลตรวจ ถ้ายังไม่ได้รัน ให้ระบุว่ายังต้องตรวจ ไม่เขียนว่า “ผ่าน” โดยอ้างเพียงคอมไพล์สำเร็จ ข้อความต้องไม่บอกว่าแก้บั๊กเมื่อจริง ๆ แค่เปลี่ยนชื่อ

TEXT
หัวเรื่อง: <การกระทำและสิ่งที่เปลี่ยน>
 
เหตุผล: <ปัญหาหรือข้อกำหนดที่ทำให้เปลี่ยน>
ตรวจ: <ข้อมูลที่ใช้และผลที่สังเกตจริง หรือสิ่งที่ยังต้องตรวจ>

คู่มือ git commit แนะนำหัวเรื่องสั้นแล้วเว้นบรรทัดก่อนรายละเอียด รายวิชานี้ประเมินความชัดและความตรงกับงาน ไม่ตัดสินด้วยจำนวนอักษรหรือรูปแบบคำนำหน้าอย่างเดียว

commit hash มาจากเนื้อหาของวัตถุ commit ซึ่งมี tree, parent ตามกรณี ข้อมูลผู้เขียน/ผู้บันทึก เวลา และข้อความ จึงไม่ใช่เลขสุ่มหรือแค่ checksum ของไฟล์ .c ถ้าวัตถุเดียวกันก็ได้รหัสเดียวกัน ไม่จำเป็นต้องต่างทุกครั้ง

ข้อเท็จจริงเรื่องวัตถุ commit ตรวจจาก Pro Git: Git Objects ในกิจกรรมให้สนใจลำดับและข้อความ ไม่คัดลอกรหัสตัวอย่างมาอ้างว่าเป็นผลที่เครื่องของตนสร้าง

13.8 ตัวอย่างเปรียบเทียบ: ประวัติที่อธิบายเหตุผลกับประวัติที่บอกแค่ว่าเปลี่ยน

เปรียบเทียบบันทึก “แก้ไฟล์” กับ “ปฏิเสธขนาดชุดศูนย์ก่อนหาร” ข้อความแรกบอกเพียงการกระทำทั่วไป ส่วนข้อความหลังช่วยให้ค้นเวอร์ชันที่เกี่ยวข้องเมื่อผู้ใช้รายงานปัญหาตัวหารศูนย์ได้ ชื่อไฟล์กับรายละเอียดทุกบรรทัดอยู่ใน diff แล้ว ข้อความบันทึกควรเพิ่มเจตนาที่ดูจาก diff อย่างเดียวอาจไม่ชัด

ตัวอย่างรายละเอียดที่มีประโยชน์คือ “ก่อนแก้รับ 17 และ 0 แล้วเข้าสู่การหาร หลังแก้รายงาน range error ก่อนคำนวณ ตรวจด้วยกรณี 17/3, 0/3 และ 17/0” ต้องเป็นผลที่ทดลองจริง หากยังไม่รันให้เขียนสิ่งที่ต้องตรวจ ไม่ทำเครื่องหมายว่าผ่านล่วงหน้า

สมมติ stage ฉบับที่แก้เงื่อนไขแล้ว ต่อมาแก้ข้อความแสดงแต่ยังไม่ stage เพิ่ม commit ที่สร้างจะยังมีข้อความเก่าตาม snapshot ที่เลือกไว้ เหตุการณ์นี้ช่วยอธิบายว่าทำไมต้องตรวจสิ่งที่จะบันทึก ไม่ใช้เพียงการเปิดไฟล์ปัจจุบันเป็นหลักฐานของสิ่งที่อยู่ในประวัติ

เหตุการณ์พื้นที่ทำงานสิ่งที่เลือกบันทึก
แก้เงื่อนไขมีเงื่อนไขใหม่ยังไม่เลือก
stageมีเงื่อนไขใหม่เลือกเงื่อนไขใหม่
แก้ข้อความเพิ่มมีข้อความใหม่ด้วยยังเป็น snapshot ก่อนแก้ข้อความ
ตรวจและ stage ตามเจตนาตรงฉบับที่จะส่งพร้อมบันทึกตามที่ตรวจ

การสาธิตตารางนี้ทำได้โดยไม่สั่ง Git จริง ให้ผู้เรียนถือกระดาษแทนแต่ละสถานะและย้ายสำเนาเมื่อเลือกบันทึก ผู้ที่ใช้เครื่องมือจริงให้เทียบกับสถานะที่เครื่องมือแสดง ไม่ต้องทดลองคำสั่งลบหรือย้อนประวัติที่อาจทำงานหายเพื่อเข้าใจแนวคิดพื้นฐาน

ท้ายงานแยกข้อความบันทึกของการแก้บั๊กกับการจัดรูปแบบ ถ้าบันทึกเดียวต้องเล่าเรื่องที่ไม่เกี่ยวกันหลายประโยค ให้พิจารณาแบ่งขอบเขต เพื่อให้ผู้อ่านประวัติรู้ว่าการเปลี่ยนใดจำเป็นต่อพฤติกรรมที่กำลังตรวจ

กิจกรรมเสริม Git: ดูสิ่งที่แก้และสิ่งที่จะบันทึกคนละมุม

ทดลองในโฟลเดอร์ว่างสำหรับสาธิตชื่อ ch13-git-demo เท่านั้น เริ่มด้วย hello.c ฉบับ Hello จาก Lab B ไม่ใช้คลังงานอื่นเป็นสนามทดลอง ผู้ที่ไม่ใช้ Git ทำกิจกรรมด้วยตารางสามสถานะได้ครบตามงานเดิม

BASH
git init -b main
git add hello.c
git commit -m "Add initial hello program"
git status --short

หลัง commit แรก ให้แก้ hello.c เป็น Hello, World และเลือกด้วย git add hello.c แล้วแก้ข้อความอีกครั้งเป็น Welcome โดยยังไม่ add ซ้ำ ใช้คำสั่งต่อไปนี้เพื่อเทียบสองช่วงก่อนตัดสินใจบันทึก

BASH
git status --short
git diff -- hello.c
git diff --cached -- hello.c

git diff ในเหตุการณ์นี้เทียบ working tree กับ staging ส่วน git diff --cached เทียบ staging กับ commit ล่าสุด อย่าคาดว่าคำสั่งแรกจะแสดงทุกสิ่งที่จะอยู่ใน commit รวมถึงไฟล์ใหม่ที่ยังไม่ถูกติดตาม

หลักฐานเปรียบเทียบอะไรข้อความก่อนข้อความหลังเห็นการแก้ครั้งใด
git diff
git diff --cached
เปิดไฟล์ปัจจุบัน

ถ้าขอบเขตที่เลือกไว้ถูกแล้ว ให้บันทึกด้วย git commit -m "Change greeting to Hello, World" โดยยังไม่ add รอบที่สอง จากนั้นดู git show HEAD:hello.c, ไฟล์ปัจจุบัน และ git log --oneline แล้วอธิบายว่าทำไมข้อความจึงต่างกัน

การ commit อยู่ในคลังบนเครื่อง ไม่ได้ส่งไปเว็บโดยอัตโนมัติ กิจกรรมนี้ไม่ใช้ remote หรือ push ถ้าเครื่องยังไม่มีข้อมูลผู้เขียน Git ให้ตั้งค่าตามแนวทางที่ผู้สอนกำหนดก่อน ไม่คัดลอกชื่อหรืออีเมลของผู้อื่นจากตัวอย่าง

ใบงาน 4: เลือกหลักฐานที่จะเก็บในประวัติ

ซอร์ส .c และเอกสารวิธีรันช่วยทำซ้ำได้ ส่วนไฟล์ปฏิบัติการสร้างใหม่จากซอร์สได้ คลังตัวอย่างนี้จึงตั้งใจเก็บซอร์สกับคำอธิบาย และไม่เก็บผล build พิจารณาแยกไฟล์หลักฐานผลรันออกจากไฟล์โปรแกรมที่สร้างโดยคอมไพเลอร์

ตัวอย่าง .gitignore สำหรับโฟลเดอร์สาธิตใช้ชื่อไฟล์และโฟลเดอร์เฉพาะที่สร้างเอง ไม่ใช้รูปแบบกว้างจนซ่อนไฟล์หลักฐานของโจทย์โดยไม่ตั้งใจ

TEXT
# Generated files in this demonstration
/hello
/hello.exe
*.o
build/

ตาม คู่มือ gitignore รูปแบบเหล่านี้ใช้กับไฟล์ที่ยังไม่ถูกติดตาม ถ้าเคยบันทึก hello.exe แล้ว การเพิ่มบรรทัด ignore ไม่ทำให้ไฟล์นั้นหายจากประวัติหรือหยุดติดตามทันที

ไฟล์สมมติเก็บเป็นหลักฐานหรือสร้างใหม่ได้ควรเลือกบันทึกหรือไม่เหตุผล
hello.c
README.md พร้อมวิธีคอมไพล์
hello.exe ที่เพิ่งสร้าง
notes.md ที่อธิบายผลทดลอง
ไฟล์ที่มีรหัสผ่าน

ตรวจรายชื่อจริงก่อนเลือกแต่ละไฟล์ การ ignore เป็นเครื่องมือช่วยจัดรายการ ไม่ใช่ระบบลบความลับหรือรับประกันว่าไฟล์ทั้งหมดปลอดภัยสำหรับเผยแพร่

13.9 อ่านโค้ดที่ผิดและทำความเข้าใจข้อความวินิจฉัย

ตัวอย่างต่อไปนี้เป็นโค้ดฝึกแยกจากงานที่ต้องส่ง แสดงข้อผิดพลาดที่สัมพันธ์กับเนื้อหาบท พร้อมข้อความวินิจฉัยจริง วิธีอ่าน และฉบับแก้ คำว่า diagnostic ใช้รวมข้อความ error, warning และ note จึงไม่ควรเรียกทุกบรรทัดว่า error หรือถือว่าการไม่มี error แปลว่าโปรแกรมถูกตามโจทย์

ที่มาของ log: ผู้เขียนทดสอบด้วย GCC 11.4.0 บน Ubuntu ผ่าน Linux environment เมื่อ 24 ตุลาคม 2569 ใช้ C11 และตัวเลือกดังนี้ ชื่อไฟล์ เลขบรรทัด คอลัมน์ ถ้อยคำ และคำเตือนที่เปิดใช้อาจต่างจากแพลตฟอร์มการเรียน นักศึกษาไม่จำเป็นต้องเปลี่ยนเครื่องมือหรือการติดตั้งตามชุดทดสอบของผู้เขียน

TEXT
-std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0

ข้อความรูปแบบ bad.c:5:17 อ่านว่าไฟล์ bad.c บรรทัด 5 คอลัมน์ 17 ส่วน ^ และ ~ ช่วยชี้บริเวณที่ตรวจพบ จุดนี้อาจเป็นปลายเหตุจากบรรทัดก่อนหน้า error ทำให้การสร้างโปรแกรมล้มในกรณีนั้น warning เตือนความเสี่ยงแม้คำสั่งสร้างอาจจบสำเร็จ และ note ให้บริบท เช่น declaration เดิม ต้องอ่านคู่กัน (GCC: Diagnostics)

ตัวอย่างที่ผิด 1: จัดย่อหน้าเหมือนมี block แต่ความหมายต่างกัน

ประเภท: คำเตือนพร้อมผลการทำงานที่ผิดเจตนา

ไม่มีปีกกาจึงมีเพียง puts แรกอยู่ใต้ if แต่ puts ที่สองเยื้องเหมือนอยู่ในเงื่อนไขด้วย รูปแบบโค้ดทำให้ผู้อ่านเข้าใจผิดและเกิดการรายงาน Eligible สำหรับคะแนนที่ไม่ผ่าน ปัญหานี้เป็นทั้งความอ่านง่ายและตรรกะ ไม่ใช่เรื่องความสวยงามอย่างเดียว

โค้ดที่ผิด — ไม่ใช้แทนฉบับแก้

C
#include <stdio.h>
int main(void)
{
    int score = 20;
    if (score >= 50)
        puts("PASS");
        puts("Eligible");
    return 0;
}

คำสั่งสร้างและข้อความที่ได้จริง

TEXT
gcc -std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0 bad.c -o bad
TEXT
bad.c: In function 'main':
bad.c:5:5: warning: this 'if' clause does not guard... [-Wmisleading-indentation]
    5 |     if (score >= 50)
      |     ^~
bad.c:7:9: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if'
    7 |         puts("Eligible");
      |         ^~~~

สถานะจบของคำสั่งสร้างที่ตัวเก็บผลอ่านได้: 0 ขั้นสร้างสำเร็จ จากนั้นจึงตรวจพฤติกรรมขณะรันหรือใช้ชุดทดสอบตามประเภทข้างต้น

ผลจากการรันฉบับผิด

stdout:

TEXT
Eligible

stderr ว่าง ไม่มี runtime diagnostic จากระบบในการทดลองนี้ ต้องใช้การเทียบผลกับข้อกำหนดเป็นหลักฐาน

สถานะจบที่ตัวเก็บผลอ่านได้: 0

ผลตามข้อกำหนดที่ใช้เทียบ:

TEXT
FAIL

อ่านข้อความว่าแจ้งอะไรและผิดอย่างไร

this if clause does not guard กับ note ที่ตามมาชี้คำสั่งที่ไม่ได้ถูกควบคุมแต่จัดย่อหน้าชวนให้เข้าใจว่าใช่ อ่านสองตำแหน่งร่วมกับปีกกาที่มีจริง ไม่แก้ด้วยการขยับตัวอักษรเพียงอย่างเดียวเมื่อเจตนาคือต้องควบคุมทั้งคู่

โค้ดที่แก้แล้ว

C
#include <stdio.h>
int main(void)
{
    int score = 20;
    if (score >= 50) {
        puts("PASS");
        puts("Eligible");
    } else {
        puts("FAIL");
    }
    return 0;
}

เหตุผลของการแก้และสิ่งที่ต้องตรวจซ้ำ

ใส่ block ให้ทั้งสองข้อความอยู่ใต้เงื่อนไขและเพิ่มผลกรณีไม่ผ่าน ทดสอบข้อมูลทั้งสองสาขาก่อนจัดรูปแบบและหลังปรับโครงสร้าง เพื่อยืนยันว่า refactor ไม่แอบเปลี่ยนข้อกำหนด

ผลตรวจฉบับแก้จริง: คอมไพล์ด้วยตัวเลือกเดิมและเพิ่ม -Werror เพื่อให้ชุดทดสอบผู้เขียนไม่ยอมรับ warning ไม่มีข้อความวินิจฉัยและคำสั่งสร้างจบด้วยสถานะ 0 จากนั้นรันได้ stdout ดังนี้ และ stderr ว่าง

TEXT
FAIL

ตัวอย่างที่ผิด 2: ชื่อซ้ำใน block ทำให้อัปเดตคนละตัวแปร

ประเภท: คำเตือนพร้อมผลการทำงานที่ผิดเจตนา

total ภายใน block เป็นอีกตัวที่บังชื่อภายนอก การเพิ่มคะแนนจึงเกิดกับตัวใน ส่วน total ภายนอกยังเป็น 0 ภาษาอนุญาตการประกาศซ้อนเช่นนี้ได้บางกรณี แต่ชื่อและขอบเขตทำให้ตรรกะของตัวสะสมผิด

ตัวเลือกเพิ่มเติมของกรณีนี้: -Wshadow

โค้ดที่ผิด — ไม่ใช้แทนฉบับแก้

C
#include <stdio.h>
int main(void)
{
    int total = 0;
    int score = 80;
    if (score >= 0) {
        int total = 0;
        total += score;
        printf("inside=%d\n", total);
    }
    printf("outside=%d\n", total);
    return 0;
}

คำสั่งสร้างและข้อความที่ได้จริง

TEXT
gcc -std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0 -Wshadow bad.c -o bad
TEXT
bad.c: In function 'main':
bad.c:7:13: warning: declaration of 'total' shadows a previous local [-Wshadow]
    7 |         int total = 0;
      |             ^~~~~
bad.c:4:9: note: shadowed declaration is here
    4 |     int total = 0;
      |         ^~~~~

สถานะจบของคำสั่งสร้างที่ตัวเก็บผลอ่านได้: 0 ขั้นสร้างสำเร็จ จากนั้นจึงตรวจพฤติกรรมขณะรันหรือใช้ชุดทดสอบตามประเภทข้างต้น

ผลจากการรันฉบับผิด

stdout:

TEXT
inside=80
outside=0

stderr ว่าง ไม่มี runtime diagnostic จากระบบในการทดลองนี้ ต้องใช้การเทียบผลกับข้อกำหนดเป็นหลักฐาน

สถานะจบที่ตัวเก็บผลอ่านได้: 0

ผลตามข้อกำหนดที่ใช้เทียบ:

TEXT
inside=80
outside=80

อ่านข้อความว่าแจ้งอะไรและผิดอย่างไร

declaration ... shadows a previous local พร้อม [-Wshadow] บอกว่าชื่อใหม่บัง declaration เดิม อ่าน note เพื่อหา total ตัวนอก คำเตือนนี้ต้องเปิด -Wshadow ตามการทดลอง ไม่รับประกันว่า platform จะเปิดตัวเลือกเดียวกัน

โค้ดที่แก้แล้ว

C
#include <stdio.h>
int main(void)
{
    int total = 0;
    int score = 80;
    if (score >= 0) {
        total += score;
        printf("inside=%d\n", total);
    }
    printf("outside=%d\n", total);
    return 0;
}

เหตุผลของการแก้และสิ่งที่ต้องตรวจซ้ำ

ถ้าเจตนาคือสะสมใน total เดิม ให้ลบ declaration ซ้ำใน block หากเป็นข้อมูลคนละความหมายให้เปลี่ยนชื่อให้สื่อบทบาทแล้วออกแบบการส่งค่าชัดเจน ไม่ปิด -Wshadow เพื่อซ่อนความกำกวม

ผลตรวจฉบับแก้จริง: คอมไพล์ด้วยตัวเลือกเดิมและเพิ่ม -Werror เพื่อให้ชุดทดสอบผู้เขียนไม่ยอมรับ warning ไม่มีข้อความวินิจฉัยและคำสั่งสร้างจบด้วยสถานะ 0 จากนั้นรันได้ stdout ดังนี้ และ stderr ว่าง

TEXT
inside=80
outside=80

ลำดับการอ่าน log เมื่อลองโปรแกรมของบทนี้

  1. ระบุว่าเกิดในขั้น compile, link, run หรือ test และแยกข้อความจากระบบออกจากข้อความที่โปรแกรมพิมพ์เอง
  2. อ่าน diagnostic แรกกับบริบทบรรทัดก่อนหน้า แล้วใช้ note เพื่อเทียบ declaration หรือชนิดข้อมูล อย่าแก้ทุกข้อความตามลำดับโดยไม่หาสาเหตุร่วม
  3. แก้ทีละสาเหตุ สร้างโปรแกรมใหม่ และตรวจว่ากำลังรันผล build ใหม่ การเติมวงเล็บ ปิด warning หรือลบ test อาจทำให้ log เงียบโดยยังผิดโจทย์
  4. ใช้ข้อมูลเดิมที่ทำให้ผิดทดสอบซ้ำ แล้วเพิ่มกรณีขอบเขตที่สัมพันธ์กับบท การรันจบสถานะศูนย์เพียงครั้งเดียวไม่แทนการตรวจข้อกำหนดครบถ้วน

ความหมายตามภาษาอ้างจากร่างมาตรฐาน C11 โดยข้อความ diagnostic เฉพาะถ้อยคำเป็นของเครื่องมือที่ใช้ ไม่ได้กำหนดให้ compiler ทุกตัวพิมพ์เหมือนกัน (WG14 N1570, GCC: Warning Options)

ปฏิบัติการที่ 13 มาตรฐานการเขียนโค้ดและข้อความบันทึกการเปลี่ยนแปลง

ปฏิบัติการนี้แบ่งเป็นสองส่วน ส่วนแรกฝึกปรับโค้ดที่เขียนไม่ได้มาตรฐานให้เป็นไปตามมาตรฐานทั้งสี่ด้าน ส่วนที่สองฝึกทำความเข้าใจแนวคิดการจัดการเวอร์ชันและเขียนข้อความ commit ที่สื่อความหมายจากสถานการณ์การแก้ไขโค้ดที่กำหนด ทั้งสองส่วนทำแยกกันได้ แต่ควรทำตามลำดับเพื่อให้เห็นภาพตั้งแต่การจัดรูปแบบโค้ดไปจนถึงการบันทึกประวัติเวอร์ชัน

ℹ️Note

ไฟล์ซอร์สโค้ดในปฏิบัติการนี้ให้ตั้งชื่อเป็นภาษาอังกฤษแบบ snake_case และบันทึกไว้ในโฟลเดอร์ของผู้เรียนเอง โค้ดตัวอย่างทดสอบด้วย gcc 13.3.0 และผลลัพธ์ประกอบแนวคิดการจัดการเวอร์ชันสร้างด้วย Git 2.43.0 รหัส commit ที่แสดงเป็นเพียงตัวอย่าง จะต่างกันทุกครั้งที่ทำซ้ำ

Lab A: ปรับโค้ดให้ได้มาตรฐาน

สถานการณ์ รับโค้ดที่เขียนติดกันในบรรทัดเดียว ตั้งชื่อตัวแปรไม่สื่อความหมาย และไม่มีคอมเมนต์ แล้วปรับให้เป็นไปตามมาตรฐานทั้งสี่ด้าน คือจัดย่อหน้า 4 ช่องว่าง ตั้งชื่อให้สื่อความหมาย ใส่คอมเมนต์อธิบายเจตนา และรักษารูปแบบให้สม่ำเสมอ

เป้าหมาย ฝึก LLO13.1 คือปรับโค้ดให้ได้มาตรฐานการเขียนโค้ดอย่างสม่ำเสมอ

ขั้นปฏิบัติ

  1. สร้างไฟล์ชื่อ code_before.c แล้วพิมพ์โค้ดฉบับก่อนปรับมาตรฐานต่อไปนี้
C
/* ก่อน: ชื่อไม่สื่อความหมาย ไม่จัดย่อหน้า ไม่มีคอมเมนต์ */
#include <stdio.h>
int main(void){int a=5,b=3,c;c=a*b;printf("%d\n",c);return 0;}
  1. คัดลอกเป็นไฟล์ใหม่ชื่อ code_after.c แล้วปรับให้ได้มาตรฐาน ได้แก่ แยกบรรทัดและจัดย่อหน้า 4 ช่องว่าง เปลี่ยนชื่อตัวแปรให้สื่อความหมาย และเพิ่มคอมเมนต์อธิบายเจตนาของการคำนวณ
C
/* code_after.c : คำนวณพื้นที่สี่เหลี่ยมตามมาตรฐานการเขียนโค้ด */
#include <stdio.h>
 
int main(void) {
    int width = 5;
    int height = 3;
    int area = width * height;   /* คำนวณพื้นที่สี่เหลี่ยม */
    printf("%d\n", area);
    return 0;
}
  1. คอมไพล์และรันฉบับที่ปรับแล้วด้วยคำสั่ง
BASH
gcc -std=c11 -Wall code_after.c -o code_after
./code_after

ผลที่บันทึกในตัวอย่างเดิม (ชุดสอนฉบับนี้ตรวจซ้ำด้วย GCC ตามตาราง)

TEXT
15

ฉบับที่ปรับแล้วตั้งชื่อ width, height และ area ให้สื่อความหมายแทนอักษรเดี่ยว จัดย่อหน้า 4 ช่องว่างในบล็อกของ main และมีคอมเมนต์ส่วนหัวกับคอมเมนต์อธิบายการคำนวณ โปรแกรมคอมไพล์ผ่านโดยไม่มีการแจ้งเตือนและคำนวณพื้นที่ 5 * 3 ได้ผลเท่ากับ 15

ตัดสินใจเอง A.1 นำโค้ดจากบทก่อนของตนเองมาหนึ่งไฟล์ แล้วตรวจกับมาตรฐานทั้งสี่ด้าน จุดใดยังไม่เป็นไปตามมาตรฐานให้ปรับแก้ เช่น จัดย่อหน้าให้สม่ำเสมอ เปลี่ยนชื่อตัวแปรที่ย่อเกินไปให้สื่อความหมาย และเพิ่มคอมเมนต์ในส่วนที่เข้าใจยาก จากนั้นคอมไพล์ยืนยันว่าโปรแกรมยังทำงานถูกต้องเหมือนเดิม

ผลลัพธ์ที่คาดหวัง A.1 โค้ดฉบับปรับแล้วอ่านง่ายขึ้น เป็นไปตามมาตรฐานทั้งสี่ด้าน และคอมไพล์ได้ผลการทำงานเท่าเดิมกับฉบับก่อนปรับ (ผลที่คาดว่าจะเห็นสำหรับโค้ดที่ผู้เรียนเลือกเอง ยังไม่ได้ทดสอบในเอกสารนี้ เพราะขึ้นกับไฟล์ที่แต่ละคนนำมา)

จุดตรวจ A จัดย่อหน้าสม่ำเสมอ 4 ช่องว่าง ตั้งชื่อตัวแปรและฟังก์ชันสื่อความหมายตามรูปแบบเดียวกัน มีคอมเมนต์อธิบายส่วนที่เข้าใจยาก รูปแบบสม่ำเสมอทั้งไฟล์ และโปรแกรมยังคอมไพล์ผ่านไม่มีการแจ้งเตือนและทำงานถูกต้อง

ปัญหาที่พบบ่อย

อาการสาเหตุวิธีแก้
ย่อหน้าในไฟล์ไม่เท่ากัน บางบรรทัดใช้แท็บ บางบรรทัดใช้ช่องว่างผสมแท็บกับช่องว่างในไฟล์เดียวกันเลือกใช้การเยื้อง 4 ช่องว่างให้เหมือนกันทั้งไฟล์
คอมเมนต์ซ้ำกับสิ่งที่โค้ดบอกอยู่แล้วใส่คอมเมนต์อธิบายทุกบรรทัดแม้ส่วนที่อ่านเข้าใจง่ายใส่คอมเมนต์เฉพาะส่วนที่เข้าใจยากหรือเจตนาของโค้ด
ตั้งชื่อย่อเกินไปจนไม่สื่อความหมายใช้อักษรเดี่ยวกับตัวแปรที่มีความหมายเฉพาะตั้งชื่อสื่อความหมายแบบ snake_case เช่น width, area

เปิดหลังผู้เรียนปรับโค้ดด้วยตนเองแล้ว

ตัวอย่างขยาย Lab A: การตรวจอินพุตเป็นอีกขอบเขตงาน

ไฟล์ checked_count.c เพิ่มหน้าที่รับจำนวน 1–8 แล้วรับคะแนนจำนวนเท่านั้น คะแนนอยู่ในช่วง 0–100 ใช้เกณฑ์สมมติ 50 โปรแกรมคืนสถานะไม่เป็นศูนย์เมื่ออ่านไม่ได้หรือข้อมูลผิดช่วง จึงไม่บันทึกการเปลี่ยนนี้ว่า “จัดย่อหน้า” อย่างเดียว

C
/* checked_count.c : validate the input before calling the counter */
#include <stdio.h>
 
int count_passed(const int scores[], int count, int threshold)
{
    int passed_count = 0;
    for (int i = 0; i < count; ++i) {
        if (scores[i] >= threshold) {
            ++passed_count;
        }
    }
    return passed_count;
}
 
int main(void)
{
    int scores[8];
    int count;
    const int passing_threshold = 50;
 
    if (scanf("%d", &count) != 1) {
        puts("Input error");
        return 1;
    }
    if (count < 1 || count > 8) {
        puts("Range error");
        return 1;
    }
    for (int i = 0; i < count; ++i) {
        if (scanf("%d", &scores[i]) != 1) {
            puts("Input error");
            return 1;
        }
        if (scores[i] < 0 || scores[i] > 100) {
            puts("Range error");
            return 1;
        }
    }
    printf("passed=%d\n",
           count_passed(scores, count, passing_threshold));
    return 0;
}

อินพุตทดลองใช้จำนวนเต็มที่แทนด้วย int ได้และคั่นด้วยช่องว่าง การตรวจ scanf ในตัวอย่างเป็นการตรวจการแปลงที่จำเป็น ไม่ใช่ตัวแยกวิเคราะห์ข้อความที่ปฏิเสธอักขระส่วนเกินทุกแบบ เช่น 50x จึงอยู่นอกข้อตกลงอินพุตนี้

อินพุตสำหรับตรวจจุดที่ต้องตรวจผลที่คาดผลจริงสถานะจบ
3 49 50 51ขอบเกณฑ์
1 0ค่าต่ำสุด
1 100ค่าสูงสุด
0จำนวนผิดช่วง
2 50 101คะแนนผิดช่วง
2 50 xอ่านคะแนนไม่ได้

แยกหลักฐานสองชุด: ฉบับปรับชื่อรักษาคำตอบเดิม กับฉบับเพิ่มตรวจอินพุตมีพฤติกรรมใหม่ ใช้ชุดนี้เป็นตัวช่วยฝึกตรวจของตนเอง งานส่งและเกณฑ์ประเมินยังตาม Lab A เดิม

Lab B: แนวคิดการจัดการเวอร์ชันและข้อความ commit ที่สื่อความหมาย

สถานการณ์ พิจารณาการพัฒนาโปรแกรม hello.c ที่มีการเปลี่ยนแปลงสองครั้ง คือสร้างเวอร์ชันแรก แล้วแก้ไขข้อความทักทาย ทำความเข้าใจว่าการจัดการเวอร์ชันบันทึกการเปลี่ยนแปลงเหล่านี้อย่างไร และเขียนข้อความ commit ที่สื่อความหมายสำหรับแต่ละการเปลี่ยนแปลง

เป้าหมาย ฝึก LLO13.2 และ LLO13.3 คือเข้าใจแนวคิดการจัดการเวอร์ชัน และเขียนข้อความ commit ที่สื่อความหมาย

ขั้นปฏิบัติ

  1. พิจารณาโค้ดเวอร์ชันแรกของ hello.c
C
/* hello.c : โปรแกรมทักทายเวอร์ชันแรก */
#include <stdio.h>
 
int main(void) {
    printf("Hello\n");
    return 0;
}
  1. จากนั้นโปรแกรมถูกแก้ไขให้พิมพ์ข้อความ Hello, World แทน เป็นการเปลี่ยนแปลงครั้งที่สอง
C
/* hello.c : แก้ข้อความทักทาย */
#include <stdio.h>
 
int main(void) {
    printf("Hello, World\n");
    return 0;
}
  1. ระบุว่าการเปลี่ยนแปลงแต่ละครั้งทำอะไร แล้วเขียนข้อความ commit ที่สื่อความหมายสำหรับแต่ละครั้ง ตัวอย่างเช่น การสร้างเวอร์ชันแรกใช้ข้อความ "เพิ่มโปรแกรม hello เวอร์ชันแรก" และการแก้ไขครั้งที่สองใช้ข้อความ "แก้ข้อความทักทายเป็น Hello, World"

  2. เพื่อประกอบความเข้าใจ ตัวอย่างต่อไปนี้แสดงว่าการจัดการเวอร์ชันด้วย Git บันทึกการเปลี่ยนแปลงทั้งสองเป็นประวัติอย่างไร (เป็นภาพประกอบแนวคิด ไม่ใช่ขั้นตอนที่ต้องลงมือทำและส่ง)

TEXT
9240d7b แก้ข้อความทักทายเป็น Hello, World
11fb2fc เพิ่มโปรแกรม hello เวอร์ชันแรก

ประวัติด้านบนแสดงการบันทึกสองครั้ง โดยรายการบนสุดเป็นการเปลี่ยนแปลงล่าสุด รหัสที่นำหน้าแต่ละบรรทัดคือ commit hash แบบย่อซึ่งต่างกันทุกครั้งที่ทำซ้ำ ข้อความที่ตามมาคือข้อความ commit ที่ผู้พัฒนาเขียนไว้ การเขียนข้อความให้สื่อความหมายจึงทำให้อ่านประวัติแล้วเข้าใจการพัฒนาได้ทันที

ตัดสินใจเอง B.1 ออกแบบการเปลี่ยนแปลง hello.c ของตนเองเพิ่มอีกหนึ่งอย่าง เช่น เพิ่มการพิมพ์ชื่อโปรแกรมอีกบรรทัด แล้วเขียนข้อความ commit ที่สื่อความหมายของการเปลี่ยนแปลงนั้น พร้อมอธิบายสั้น ๆ ว่าการบันทึกเวอร์ชันช่วยติดตามการพัฒนาอย่างไร

ผลลัพธ์ที่คาดหวัง B.1 ได้ข้อความ commit ที่สื่อถึงการเปลี่ยนแปลงที่ออกแบบไว้อย่างชัดเจน พร้อมคำอธิบายประโยชน์ของการจัดการเวอร์ชัน (ผลที่คาดว่าจะเห็นสำหรับการเปลี่ยนแปลงที่ผู้เรียนออกแบบเอง ยังไม่ได้ทดสอบในเอกสารนี้ เพราะขึ้นกับสิ่งที่แต่ละคนออกแบบ)

จุดตรวจ B อธิบายแนวคิดการจัดการเวอร์ชันได้ ระบุการเปลี่ยนแปลงแต่ละครั้งได้ และเขียนข้อความ commit ที่สื่อความหมายสำหรับการเปลี่ยนแปลงอย่างน้อยสองรายการ

ปัญหาที่พบบ่อย

อาการสาเหตุวิธีแก้
ประวัติอ่านแล้วไม่ทราบว่าแต่ละครั้งทำอะไรใช้ข้อความ commit กำกวมเช่น update หรือ fixเขียนข้อความระบุการกระทำและสิ่งที่เปลี่ยนให้ชัด
ข้อความ commit ยาวเกินไปจนไม่สื่อประเด็นใส่รายละเอียดทั้งหมดในบรรทัดเดียวเขียนให้สั้น กระชับ เริ่มด้วยคำกริยาที่บอกการกระทำ
ระบุการเปลี่ยนแปลงไม่ตรงกับสิ่งที่แก้จริงเขียนข้อความก่อนตรวจสิ่งที่เปลี่ยนเทียบโค้ดก่อน–หลัง แล้วจึงสรุปเป็นข้อความ commit

เปิดหลังผู้เรียนส่งงานแล้ว

ใบงานปิด Lab B: ส่งมอบเวอร์ชันที่อธิบายได้

เลือกการเปลี่ยนอย่างน้อยสองครั้งตาม Lab B เดิม ระบุฉบับก่อน–หลังและข้อความบันทึกของแต่ละครั้ง พร้อมประโยชน์ของการเก็บประวัติอย่างน้อยสองข้อ กรณีไม่ใช้ Git ให้ทำตารางเวอร์ชันแทนภาพประวัติจากเครื่องมือ

เวอร์ชันสิ่งที่เปลี่ยนพฤติกรรมคงเดิมหรือใหม่หลักฐานตรวจข้อความบันทึก
V1
V2
V3 ที่เลือกทำเพิ่ม

ก่อนส่ง ให้เพื่อนสุ่มถามว่าชื่อใดแสดงหน้าที่ คอมเมนต์ใดอธิบายเหตุผล กรณีใดตรวจค่าเท่ากับเกณฑ์ และหลักฐานใดตรงกับฉบับส่ง ถ้าตอบไม่ได้ให้กลับไปอ่านซอร์สหรือผลจริง ไม่เติมคำตอบจากความจำของไฟล์อื่น

ตรวจออกจากบทด้วยคำถามหกข้อ: การจัดรูปแบบต่างจากแก้บั๊กอย่างไร, กรณีใดจับการเปลี่ยนเครื่องหมายได้, staging เก็บเมื่อใด, diff สองชนิดต่างกันอย่างไร, commit ส่งไปเว็บหรือยัง และข้อความใดค้นเหตุผลย้อนหลังได้

นำรายการตรวจและบันทึกเวอร์ชันไปใช้ต่อใน บทที่ 14 และเก็บหลักฐานสำหรับโครงงานบทที่ 15 โดยยังอ้างอิง LLO และงานส่งของแต่ละบทตามที่ประกาศ

เก็บกวาด

เมื่อจบปฏิบัติการ ให้ลบไฟล์ปฏิบัติการที่สร้างจากการคอมไพล์ (เช่น code_after) และเก็บเฉพาะไฟล์ซอร์สโค้ด .c พร้อมบันทึกผลการรันและชุดข้อความ commit ที่เขียนไว้ เพื่อให้โฟลเดอร์งานสะอาดและมีเฉพาะสิ่งที่ต้องส่ง

สรุป

บทนี้สรุปมาตรฐานการเขียนโค้ดที่ฝึกสะสมมาตั้งแต่บทที่ 1 ไว้ในที่เดียว ได้แก่ การจัดย่อหน้า 4 ช่องว่างให้สม่ำเสมอ การตั้งชื่อตัวแปรและฟังก์ชันให้สื่อความหมายแบบ snake_case การใส่คอมเมนต์อธิบายส่วนที่เข้าใจยาก และความสม่ำเสมอของรูปแบบทั้งไฟล์ โดยเทียบโค้ดฉบับก่อนและหลังปรับมาตรฐานให้เห็นผลต่อการอ่านและการบำรุงรักษา จากนั้นอธิบายแนวคิดการจัดการเวอร์ชันว่าช่วยบันทึกประวัติการเปลี่ยนแปลงของโค้ดเพื่อย้อนดูและย้อนกลับได้ พร้อมหลักการเขียนข้อความ commit ที่สื่อความหมาย เช่น "แก้ข้อความทักทายเป็น Hello, World" ที่ดีกว่าข้อความกำกวมอย่าง update หรือ fix มาตรฐานโค้ดและแนวคิดการจัดการเวอร์ชันเหล่านี้ตอบ CLO5 โดยตรงและเป็นพื้นฐานของโครงงานบูรณาการในบทถัดไป

สิ่งที่ส่งต่อไปยังบทถัดไป

สิ่งที่ส่งต่อค่า/รูปแบบใช้ในบท
มาตรฐานการเขียนโค้ดแบบสรุปการจัดย่อหน้า 4 ช่องว่าง, ตั้งชื่อ snake_case สื่อความหมาย, คอมเมนต์, ความสม่ำเสมอบท 15 (โครงงานบูรณาการ)
แนวคิดการจัดการเวอร์ชันการบันทึกประวัติการเปลี่ยนแปลงเพื่อย้อนดู/ย้อนกลับบท 15 (โครงงานบูรณาการ)
ข้อความ commit ที่สื่อความหมายระบุการกระทำและสิ่งที่เปลี่ยนอย่างชัดเจนบท 15 (โครงงานบูรณาการ)

ตัวอย่างคำสั่ง Git (ประกอบแนวคิด)

ตารางด้านล่างสรุปคำสั่ง Git ที่ยกเป็นตัวอย่างประกอบแนวคิดการจัดการเวอร์ชันในบทนี้ เพื่อประกอบความเข้าใจ ไม่ใช่งานที่ต้องลงมือทำและส่ง

คำสั่งหน้าที่
git init -b mainสร้างคลังเก็บ Git ในโฟลเดอร์งานโดยตั้งชื่อสาขาหลักเป็น main
git add ไฟล์เตรียมไฟล์ที่แก้ไขให้พร้อมบันทึกใน commit ถัดไป
git commit -m "ข้อความ"บันทึกไฟล์ที่เตรียมไว้เป็นเวอร์ชันหนึ่งพร้อมข้อความอธิบาย
git log --onelineแสดงประวัติ commit บรรทัดละรายการ (รหัสย่อ + ข้อความ)

แบบฝึกหัดท้ายบท

ตอนที่ 1 ฝึกทบทวน (15 ข้อ ตรวจคำตอบให้ทันที)

ตอนที่ 2 แบบฝึกหัดเขียนตอบ (5 ข้อ)

กลุ่ม ก (เข้าใจ)

  • ก1 (LLO13.1) จงอธิบายมาตรฐานการเขียนโค้ดสี่ด้านที่ใช้ในรายวิชานี้ พร้อมยกตัวอย่างของแต่ละด้าน
  • ก2 (LLO13.3) จงอธิบายว่าข้อความ commit ที่สื่อความหมายต่างจากข้อความกำกวมอย่าง update หรือ fix อย่างไร และเหตุใดจึงสำคัญต่อการอ่านประวัติ

กลุ่ม ข (ประยุกต์)

  • ข1 (LLO13.1) จงรับโค้ดภาษา C ที่เขียนติดกันไม่ได้มาตรฐานหนึ่งโปรแกรม แล้วปรับให้ได้มาตรฐานทั้งสี่ด้าน คือจัดย่อหน้า ตั้งชื่อสื่อความหมาย ใส่คอมเมนต์ และรักษารูปแบบให้สม่ำเสมอ จากนั้นคอมไพล์ยืนยันว่ายังทำงานถูกต้อง
  • ข2 (LLO13.2) จงพิจารณาโปรแกรมภาษา C ที่มีการแก้ไขอย่างน้อยสองครั้ง แล้วเขียนข้อความ commit ที่สื่อความหมายสำหรับแต่ละการเปลี่ยนแปลง พร้อมอธิบายว่าการจัดการเวอร์ชันช่วยติดตามการพัฒนาอย่างไร

กลุ่ม ค (วิเคราะห์)

  • ค1 (LLO13.3) จากประวัติ commit ที่มีข้อความกำกวมหลายรายการ จงวิเคราะห์ว่าเหตุใดจึงยากต่อการค้นหาการเปลี่ยนแปลง และเสนอข้อความ commit ที่สื่อความหมายกว่าสำหรับแต่ละรายการ

การศึกษาค้นคว้าเพิ่มเติม

  1. ศึกษาแนวทางการเขียนโปรแกรมให้อ่านง่ายและการตั้งชื่อที่สื่อความหมายเพิ่มเติมจาก Kernighan และ Ritchie (1988) แล้วทดลองปรับโปรแกรมของตนเองจากบทก่อนให้เป็นไปตามมาตรฐานทั้งสี่ด้าน
  2. ทบทวนไวยากรณ์ภาษา C ตามมาตรฐาน C11 และแยกจากข้อตกลงรูปแบบของรายวิชา เช่น การเยื้อง 4 ช่องกับ snake_case ไม่ใช่ข้อบังคับทั่วไปของภาษา C
  3. ศึกษาการใช้เครื่องมือจัดการเวอร์ชันอย่าง Git เพิ่มเติมเป็นทางเลือก แล้วฝึกเขียนข้อความ commit ที่สื่อความหมายในแต่ละการเปลี่ยนแปลง เพื่อสร้างนิสัยการจัดการเวอร์ชันที่ดี (เป็นการศึกษาเสริม ไม่ใช่ส่วนที่ต้องส่งในบทนี้)

เอกสารอ้างอิง

International Organization for Standardization. (2011). ISO/IEC 9899:2011 — Information technology — Programming languages — C. ISO.

Kernighan, B. W., & Ritchie, D. M. (1988). The C programming language (2nd ed.). Prentice Hall.

ตำราหลักภาษาไทยของรายวิชา. (ผู้สอนเติมรายละเอียดบรรณานุกรม — เพิ่มตามมติผู้สอน 21 ต.ค. 2569).

แหล่งปฐมภูมิที่ตรวจประกอบการปรับปรุง 23 ตุลาคม 2569

ใช้เอกสารข้างต้นตรวจหลักการก่อนเรียบเรียงส่วนขยายและสร้างข้อมูลสมมติ ตัวอย่างใหม่ที่เป็นโปรแกรม C ครบไฟล์ตรวจด้วย GCC 12.2.0 (Debian Linux) และ GCC 6.3.0 (MinGW-w64), C11 และคำเตือน -Wall -Wextra -Wpedantic เมื่อ 23 ตุลาคม 2569 แยกจากผลทดสอบ GCC 13.3.0 ของตัวอย่างเดิม ค่ารูปแบบและผลคำนวณตรวจจากการรัน ส่วนรหัส commit และรายละเอียดข้อความสถานะอาจต่างตามข้อมูลของวัตถุและรุ่นเครื่องมือ ไม่ใช้รหัสตัวอย่างเป็นเกณฑ์ผ่าน

By Watcharin Sarachai