3 คะแนน โดย GN⁺ 2024-02-02 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • คอมมิต “Convert template to US-ASCII to fix error” ของ Dan Carley ที่เกิดขึ้นระหว่างทำงานกับ GOV.UK แสดงให้เห็นว่าการเปลี่ยนแปลงโค้ดเล็ก ๆ ก็สามารถกลายเป็นเอกสารระยะยาวของ codebase ได้ผ่าน ข้อความคอมมิตที่ละเอียด
  • ข้อความที่ดีจะทิ้งไว้ว่าเหตุใดจึงเปลี่ยน มากกว่าว่าเปลี่ยนอะไร โดยกรณีนี้บันทึกข้อผิดพลาด invalid byte sequence in US-ASCII ที่เกิดขึ้นเมื่อรัน bundle exec rake และเงื่อนไขการทำซ้ำอย่างเป็นรูปธรรม
  • มีทั้งสตริงข้อผิดพลาดและกระบวนการสืบค้นบันทึกไว้ด้วย ทำให้คนที่เจอปัญหาเดียวกันในภายหลังสามารถค้นหา บันทึกการแก้ไขก่อนหน้า ได้ด้วย git log --grep หรือการค้นหาคอมมิตบน GitHub
  • ข้อความยังรวมขั้นตอนการใช้เครื่องมือ Unix เช่น find -exec, file --mime, iconv ทำให้ผู้รีวิวและผู้อ่านภายหลังตามลำดับการแก้ปัญหาได้
  • ไม่ใช่ทุกคอมมิตจำเป็นต้องยาวขนาดนี้ แต่ข้อความที่ทิ้งบริบท กระบวนการสืบค้น และแม้แต่อารมณ์ไว้ จะช่วยสร้าง ความเข้าใจร่วมกันต่อ codebase และความไว้วางใจในทีม

คอมมิตที่ทำให้การเปลี่ยนแปลงเล็ก ๆ กลายเป็นเอกสารระยะยาว

  • หากเขียนให้ดี ข้อความคอมมิต Git สามารถเป็น เครื่องมือทำเอกสารที่ทรงพลัง ซึ่งคงอยู่ตลอดอายุของ codebase ได้
  • คอมมิตที่ยกเป็นตัวอย่างเป็นการเปลี่ยนแปลงในช่วงที่ Government Digital Service ทำงานกับ GOV.UK
  • ผู้เขียนคือ Dan Carley และหัวข้อคือ “Convert template to US-ASCII to fix error
  • ด้วยวิธีการพัฒนาแบบเปิดเผยของ GDS แม้แต่กรณีภายในองค์กรเช่นนี้ก็สามารถแชร์ออกสู่ภายนอกได้

บริบทสำคัญกว่าความยาว

  • คอมมิตนี้มีข้อความยาวเมื่อเทียบกับปริมาณการเปลี่ยนแปลงโค้ด แต่คุณค่าหลักไม่ได้อยู่ที่ความยาวเอง แต่อยู่ที่ บริบทที่เป็นประโยชน์
  • การเปลี่ยนแปลงแบบเดียวกันในที่อื่นอาจถูกทิ้งไว้สั้น ๆ ว่า change whitespace, fix bug
  • Dan ทิ้งบันทึกอย่างละเอียดเพื่อให้เพื่อนร่วมงานรอบตัวและผู้อ่านในภายหลังเข้าใจสาเหตุของปัญหาและกระบวนการแก้ไข

ไม่ใช่แค่ว่าเปลี่ยนอะไร แต่ทำไมจึงเปลี่ยน

  • ข้อความคอมมิตที่ดีอธิบายไม่เพียงสิ่งที่เปลี่ยน แต่ยังอธิบาย เหตุผลที่เปลี่ยน ด้วย
  • คอมมิตนี้บันทึกว่า หลังจากเพิ่มเทสต์ใน feature branch เพื่อให้ตรงกับเนื้อหาของ /etc/nginx/router_routes.conf ผลลัพธ์ต่างกันขึ้นอยู่กับวิธีรัน
    • หากรันด้วย bundle exec rake spec หรือ bundle exec rspec modules/router/spec จะทำงานปกติ
    • หากรันด้วย bundle exec rake แต่ละบล็อก should จะล้มเหลว
    • ข้อผิดพลาดคือ ArgumentError: invalid byte sequence in US-ASCII
  • หากไม่มีคำอธิบายเช่นนี้ ก็มีความเป็นไปได้สูงว่าจะต้องเดาเองว่าเกิดข้อผิดพลาดการ parse ในเครื่องมือใด
  • บริบทของงานดั้งเดิมอาจเลือนหายได้ง่ายเมื่อคนลืม ย้ายทีม หรือออกจากองค์กร

บันทึกข้อผิดพลาดที่ค้นหาได้

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

ทิ้งกระบวนการแก้ปัญหาไว้เป็นเรื่องเล่า

  • ข้อความถูกจัดโครงสร้างให้ติดตามได้ว่าปัญหาดูเป็นอย่างไร ตรวจสอบตามลำดับใด และสุดท้ายแก้อย่างไร
  • ตัวอย่างเช่น มีเนื้อหาระบุว่าเมื่อลบ matcher .with_content(//) ข้อผิดพลาดก็หายไป, ในไฟล์ spec ไม่มีอักขระแปลก ๆ และสามารถทำซ้ำได้เมื่อ require Puppet ใน interpreter เดียวกัน
  • ข้อความคอมมิตไม่ได้ทำเอกสารให้ไฟล์ ฟังก์ชัน หรือโค้ดหนึ่งบรรทัดโดยเฉพาะ แต่ทำเอกสารให้ การเปลี่ยนแปลงนั้นเอง จึงเป็นตำแหน่งที่เหมาะสำหรับบันทึกเส้นทางที่ codebase ผ่านมา

ผลพลอยได้ที่ช่วยขยายความรู้ของทีม

  • Dan บันทึกคำสั่งที่รันในแต่ละขั้นตอนการสืบค้น ซึ่งอาจเป็นวิธีเผยแพร่ความรู้ภายในทีมอย่างเบา ๆ
  • ผู้อ่านสามารถเรียนรู้วิธีใช้เครื่องมือ Unix ได้จากข้อความคอมมิตเพียงอย่างเดียว
    • สามารถส่งอาร์กิวเมนต์ -exec ให้ find เพื่อรันคำสั่งกับแต่ละไฟล์ที่พบได้
    • หากใส่ \+ ท้ายคำสั่ง แทนที่จะรันทีละครั้งต่อไฟล์ จะส่งชื่อไฟล์หลายชื่อให้คำสั่ง file ครั้งเดียว
    • file --mime บอก MIME type ของไฟล์
    • มีเครื่องมือชื่อ iconv อยู่
  • ไม่ใช่แค่คนที่รีวิวการเปลี่ยนแปลงเท่านั้น แต่คนที่ค้นพบคอมมิตนี้ในภายหลังก็ได้รับข้อมูลเดียวกัน
  • เมื่อมีเวลาและคอมมิตสะสมมากพอ ข้อความแบบนี้สามารถกลายเป็น เครื่องขยายความรู้ ของทีมได้

บันทึกที่สร้างความเห็นอกเห็นใจและความไว้วางใจ

  • ท้ายคอมมิตมีประโยคว่า “Now the tests work! One hour of my life I won't get back..”
  • ประโยคนี้ถ่ายทอดทั้งความหงุดหงิดของนักพัฒนาที่ไล่ตามบั๊กซับซ้อนอยู่หนึ่งชั่วโมง และความพอใจเมื่อแก้ได้
  • แม้ในกรณีที่โค้ดแฮ็กระยะสั้นหรือโค้ดต้นแบบถูกนำเข้าโปรดักชันและหยั่งรากอยู่ในระบบ ข้อความเช่นนี้ก็ช่วยเตือนให้ระลึกว่าเบื้องหลังทุกการเปลี่ยนแปลง เคยมีคนที่ตัดสินใจอย่างดีที่สุดภายใต้ข้อมูลที่มีในตอนนั้น

ไม่ใช่ทุกคอมมิตจำเป็นต้องยาว

  • กรณีนี้เป็นตัวอย่างแบบสุดโต่ง และโดยเฉพาะอย่างยิ่ง ไม่จำเป็นต้องคาดหวังรายละเอียดระดับเดียวกันจากทุกคอมมิตที่มีขนาดเท่านี้
  • ถึงอย่างนั้น นี่ก็เป็นตัวอย่างที่ดีของการอธิบายบริบทเบื้องหลังการเปลี่ยนแปลง ทำให้คนอื่นได้เรียนรู้ และมีส่วนช่วยสร้าง mental model ร่วมกัน ต่อ codebase ของทีม
  • หากสนใจข้อความคอมมิตที่ดีและเครื่องมือสำหรับจัดโครงสร้างการเปลี่ยนแปลง สามารถดูแหล่งข้อมูลต่อไปนี้

1 ความคิดเห็น

 
GN⁺ 2024-02-02
ความคิดเห็นจาก Hacker News
  • ไม่ว่าจะมองว่าดีหรือแย่ ในฐานะผู้ร่วมก่อตั้ง GitHub และผู้เขียนหนังสือ Git อย่าง Pro Git ก็เห็นว่า ข้อความคอมมิตของ Git เป็นช่องทางเฉพาะตัวสำหรับการทำเอกสารประกอบโค้ด แต่ไม่มีประสิทธิภาพมาก
    ปัญหาหลักคือเครื่องมือส่วนใหญ่ เช่น Git, GitHub มัก แสดงแค่บรรทัดแรก เท่านั้น ตัวอย่างคอมมิตก็เห็นเพียงบรรทัดทั่วไปอย่าง “US-ASCII error” ส่วนที่เหลือซึ่งบทความชื่นชม แทบไม่มีใครเห็นในเครื่องมือสมัยใหม่
    Git ออกแบบข้อความคอมมิตให้เป็น เนื้อหาอีเมล ที่ทุกคนในโปรเจ็กต์อ่าน แต่ทุกวันนี้ส่วนใหญ่ไม่ได้ทำหน้าที่แบบนั้นแล้ว ถ้าไม่ได้ถกกันเป็นชุดแพตช์ใน mailing list ก็แทบไม่มีใครอ่านเกิน 50 ตัวอักษรแรกของหัวข้อ
    ใน git blame ต่อให้ตามหาข้อความที่เกี่ยวข้องด้วย -w -C -C -C หรือ -C สองตัว ก็ยังเห็นแค่บรรทัดแรก สุดท้ายต้องหา SHA แล้วใช้ git show เพื่ออ่านข้อความยาวอยู่ดี หนึ่งในข้อไม่พอใจที่ใหญ่ที่สุดเกี่ยวกับ Git คือ ถึงจะเขียนดีแค่ไหน ข้อมูลก็หาเจอกลับมาได้ยากมาก
    ถ้าดูประวัติของโปรเจ็กต์ Git จะเห็นว่าข้อความคอมมิตแทบทุกครั้งยอดเยี่ยมมาก แต่ถึงจะรัน blame กับไฟล์เดียว ก็ยังตามบริบทของการพัฒนาฟังก์ชันได้ยากมาก เอกสารที่ Jeff King เขียนไว้ตลอด 10 ปีที่ผ่านมาอยู่ในระดับอัจฉริยะ แต่แทบไม่มีใครได้ซาบซึ้งกับมันเลย ซึ่งเป็นเรื่องน่าเศร้า
    ไม่รู้ว่าทางออกที่ถูกต้องคืออะไร แต่ในชุมชนส่วนใหญ่ การเขียนเอกสารที่ยอดเยี่ยมลงในข้อความคอมมิต น่าเศร้าที่เกือบจะเป็นการเสียเวลา เพราะมันค้นหายากเกินไป

    • ในฐานะคนที่มีส่วนร่วมกับ Git มาตั้งแต่ก่อนมี GitHub และดูแลโค้ดเก่าอยู่ ก็ไม่เห็นด้วยเลย ใช้ git blame, git log, git show ในเทอร์มินัลตลอด การไล่ตามประวัติไฟล์นั้นง่าย และใช้ git log -G หาได้ภายในไม่กี่วินาทีว่าเพิ่มหรือลบบางอย่างเมื่อไร
      สิ่งที่ยากคือพอหาคอมมิตเจอแล้ว แต่ข้อความมีแค่ “bleh” หรือ “add a thing” ทั้งที่ถ้านักพัฒนาใช้เวลา 60 วินาทีเขียนว่าเหตุใดจึงทำแบบนั้นก็คงพอแล้ว
      ในทางกลับกัน เวลาเจอข้อความคอมมิตที่อธิบายอย่างละเอียดว่าทำไมการเปลี่ยนแปลงนั้นจึงเกิดขึ้น ก็รู้สึกดีมาก ข้อความคอมมิตที่ดีเพียงอันเดียวช่วยประหยัดงานไปได้หลายชั่วโมงหรือหลายวัน
      GitHub ก็มีส่วนทำให้ปัญหาข้อความคอมมิตแย่ลงด้วย ถ้าโชคดีก็อาจมีรายละเอียดอยู่ในคำอธิบาย PR แต่ไม่ได้อยู่ข้าง ๆ commit log โดยตรง และส่วนใหญ่ PR ก็โยงไปลิงก์ Jira, Jira ก็โยงไปบทสนทนาใน Slack, Slack ก็โยงไป Google document อีกที
      วงการนี้ทำเอกสารได้แย่มาก แต่คนอย่าง Jeff King ก็กำลังต่อสู้อย่างถูกทาง ท้ายที่สุดมันไม่ใช่ปัญหาทางเทคนิค แต่เป็นปัญหาของคน การเขียนเอกสารไม่มีรางวัลทันที จึงให้ความรู้สึกเหมือนงานเพิ่ม และผลตอบแทนจะมาปรากฏหลังจากนั้นหลายวัน หลายสัปดาห์ หรือหลายเดือน
      ได้โปรดเขียนข้อความคอมมิตดี ๆ กันเถอะ แค่ใช้เวลา 1 นาทีเขียนว่าทำไปทำไม ก็จะช่วยให้ทุกคอมมิตไม่กลายเป็นการอธิบายรั้วของ Chesterton แบบบ้าบอ ถ้าใส่ไว้ในข้อความคอมมิตที่หาเจอง่าย ทั้งตัวคุณในอนาคตและผมจะขอบคุณ
      เพิ่มเติมคือ ผมก็ไม่เห็นด้วยกับคำกล่าวที่ว่าข้อความคอมมิตหายาก ผมแทบไม่เคยลำบากในการตามประวัติของบรรทัดโค้ด ฟังก์ชัน หรือไฟล์ และถึงข้อความคอมมิตจะไม่ถูกกลับมาอ่านอีก มันก็ยังมีคุณค่าตั้งแต่ตอนเขียน เพราะการเขียนข้อความดี ๆ ทำให้ผมตรวจสอบได้ว่าผมเขียนโค้ดตรงตามที่ตั้งใจจริงหรือไม่ และมันก็มีคุณค่าต่อผู้รีวิวโค้ดด้วย
    • คำพูดที่ว่า “Git ออกแบบข้อความคอมมิตให้เป็นเนื้อหาอีเมลที่ทุกคนในโปรเจ็กต์อ่าน” ฟังแล้วเชื่อยาก ในความเป็นจริงมันน่าจะใกล้เคียงกับการที่ คนที่สนใจหัวข้อคอมมิตหรือไฟล์ที่เปลี่ยนแปลง มาอ่านข้อความเนื้อหามากกว่า ไม่เห็นว่าทำไมคนอื่นต้องมาอ่านเอกสารประวัติถาวรนี้ด้วย
      ที่บอกว่าหาตัวเลือกของ git blame ยาก ก็ฟังเหมือนมุกตลก IDE ที่ดีควรแสดงข้อมูล blame ติดไว้กับแต่ละบรรทัด และกดปุ่มเดียวเพื่อดู diff ได้ รวมถึงควร recursive blame ต่อได้จากบรรทัดบริบทหรือบรรทัดที่ถูกลบใน diff นั้น เครื่องมืออย่าง Tig ก็ทำแบบนั้นได้พอดี
      ยอมรับว่า GitHub ทำให้การดูข้อความคอมมิตยากขึ้น
      เอกสารที่แนบมากับคอมมิตไม่ได้เขียนขึ้นมาเพื่อความสนุก แต่มันช่วยลดความเสี่ยงในการรับแพตช์จากคนที่ภายหลังอาจไม่อยู่แล้ว และช่วยเปิดเผยแนวคิดที่เกี่ยวข้องเพื่อให้คนอื่นทำงานต่อยอดได้ ถ้าซ่อนความคิดไว้ ก็จะสะสมความเป็นเจ้าของโค้ดแบบผูกขาด ซึ่งโดยมากไม่ใช่เรื่องดี ข้อความคอมมิตยังทำหน้าที่เป็นหลักฐานของงานที่ทำ และอาจสำคัญขึ้นเมื่อมีแพตช์จำนวนมาก สำหรับโปรเจ็กต์เชิงพาณิชย์ ความสำคัญบางส่วนอาจน้อยลง
    • ผมไม่ค่อยเก่ง Git บนเทอร์มินัล แต่ถ้าใช้ IntelliJ หรือ Magit ของ Emacs ก็หาคอมมิตทั้งหมดที่เปลี่ยนไฟล์นั้นได้ง่าย และไล่อ่านข้อความคอมมิตเต็ม ๆ ได้สะดวก ถ้าใช้ เครื่องมือที่เหมาะสม ก็ไม่ได้ยาก และคิดว่าแทบทุกคนก็น่าจะมีเครื่องมือคล้าย ๆ กันไม่ใช่หรือ จะยึดติดกับ Git CLI จนต้องจำคำสั่งกับแฟลกเป็นร้อย ๆ ไปทำไม ก็ไม่เข้าใจเหมือนกัน
    • นี่คือความล้มเหลวของ GitHub และบริการทำนองเดียวกัน GitHub พยายามทำให้เรียบง่าย เพราะเหมือนคิดว่าผู้ใช้ไม่สามารถอนุมานประวัติคอมมิตได้ และนี่ก็เป็นหนึ่งในผลลัพธ์นั้น โดยเฉพาะความสับสนใน private GitHub repository บางครั้งก็น่าเหลือเชื่อ
      จริง ๆ แล้วก็แทบไม่มีที่อื่นให้เก็บเอกสารแบบนี้ มันไม่เหมาะจะอยู่ในคอมเมนต์โค้ด แต่ตอนนี้คนจำนวนหนึ่งกลับคิดว่า Git ก็คือ GitHub และจุดประสงค์เดียวของ Git คือเอาการเปลี่ยนแปลงขึ้น GitHub
      Git เองก็ไม่ได้ดีนัก แต่ก็ยังแย่น้อยกว่าสิ่งอื่นมาก เราควรกลับไปสู่พื้นฐานและเข้าใจ จุดประสงค์ที่แท้จริงของ version control อีกครั้ง
    • ถึงอย่างนั้นมันก็ยอดเยี่ยมสำหรับ การศึกษาประวัติ เพราะเป็นหนึ่งในเอกสารไม่กี่ประเภทที่อยู่รอดไปพร้อมกับโค้ดตลอดกาล GitHub หรือรูปแบบรวมศูนย์อื่น ๆ ไม่ใช่รูปแบบข้อมูลเปิดที่ผู้คนสำรอง แปลง หรือย้ายได้สะดวก ดังนั้นเวลาโปรเจ็กต์ย้ายที่ ก็มักทิ้งข้อมูลเหล่านั้นไว้ข้างหลัง
      เพราะแบบนั้นมันอาจไม่ได้ช่วยชุมชนปัจจุบันมากนัก แต่จะช่วยคนที่ต้องดีบักในอีกหลายปีข้างหน้าได้
  • โดยรวมเห็นด้วยกับเจตนาหลัก แต่ถ้าวาง BLUF ที่ชัดเจนกว่านี้ไว้ข้างหน้าจะดีกว่า เช่นเขียนว่า “Fix test issues caused by non-breaking space character \xa0”
    จะได้รู้ทันทีว่าปัญหาคืออะไร และถ้าอยากรู้เพิ่มก็ยังเลือกอ่านด้านล่างต่อได้

    • คิดว่าข้อความนี้ดีกว่ามาก ถ้าดู diff บน GitHub ก็จะค่อนข้างชัดด้วยว่ามีอะไรเปลี่ยนไป เพราะถ้าเป็นชุดการเปลี่ยนแปลงที่ดูเหมือนเดิมทุกอย่าง ก็แทบจะมีได้แค่ว่ามีการเพิ่มหรือลบอักขระที่มองไม่เห็น
      เพราะงั้นสำหรับการค้นย้อนหลังในประวัติ แค่มี ข้อความบรรทัดแรก ที่ดีก็เพียงพอแล้ว เรื่องสั้น ๆ ว่าตามหาต้นตอของบั๊กจนไปถึงนาร์เนียแล้วกลับมา ผมว่าไม่ค่อยเกี่ยวเท่าไร แต่อย่างน้อยก็ไม่ได้คัดค้านถ้าจะระบายไว้ในคำอธิบาย PR หรือข้อความขยายของคอมมิต
    • คอมมิตเมสเสจในอุดมคติก็ประมาณนั้นแหละ เนื้อหาที่เหลือในบทความเป็นแค่เรื่องเล่าว่าค้นพบได้อย่างไรเท่านั้น ผมไม่คิดว่าเนื้อหาที่อธิบายขั้นตอนการทำงานจำเป็นต้องอยู่ใน Git commit message ข้อความนั้นบอกแล้วว่าทำไปทำไม และมีการเปลี่ยนอะไร แค่นั้นก็พอ
    • ชอบแนวคิดนี้มาก วาง สิ่งที่นำไปใช้ได้จริงที่สุดหรือสำคัญที่สุด ไว้บนสุดเสมอ แล้วค่อยตามด้วยบริบท ต้องเคารพเวลาของคนอื่นและอย่าฝังประเด็นสำคัญไว้ลึก ๆ
  • ผมเคยรู้สึกภูมิใจกับการเขียนคอมมิตเมสเสจที่ยอดเยี่ยม แต่ไม่ค่อยมั่นใจเท่าไรในคุณค่าที่มันมอบให้คนอื่น เวลาเจอข้อความ error แปลก ๆ หรือเพิ่มฟีเจอร์ใหม่ หรือจริง ๆ แล้วแทบทุกกรณี ผมไม่คิดว่าคนส่วนใหญ่จะค้นคอมมิตเมสเสจ
    ฟังดูเศร้านิดหน่อย แต่ยิ่งสงสัยมากขึ้นว่าคอมมิตเมสเสจที่สวยงามนั้นใกล้เคียงกับ ความหลงตัวเอง ของโปรแกรมเมอร์อยู่พอสมควร คนที่ชื่นชมมันมากที่สุดก็มักเป็นคนเขียนเอง ส่วนคนอื่นก็ผ่านไปโดยไม่ทันสังเกต
    บางครั้งก็มีพื้นที่สำหรับความประณีตแบบนั้นอยู่ แต่ผมไม่แน่ใจว่ามันมีคุณค่าเชิงปฏิบัติมากนัก ถ้าคนอื่นคอมมิตว่า “fix whitespace issue” ตอนนี้ผมก็ไม่ค่อยใส่ใจแล้ว และคิดว่านั่นทำให้ผมเป็นเพื่อนร่วมงานที่ดีขึ้น
    โปรเจกต์อย่าง Git หรือ Linux ที่มีทีมกระจายตัวขนาดใหญ่และคอมมิตจำนวนมหาศาลอาจต่างออกไป โปรเจกต์ที่ผมคุ้นเคยมีผู้ร่วมพัฒนา 1 ถึง 100 คน และส่วนใหญ่อยู่ในองค์กรเดียวกัน

    • คอมมิตเมสเสจมีคุณค่าแม้คนเดียวที่จะได้เห็นมันตลอดไปคือตัวคุณเอง เวลาทำ binary search เพื่อไล่หาปัญหา ข้อความของคอมมิตที่เจอในที่สุดมีประโยชน์มาก ถ้าไม่ใช่แค่ “fixed thing” มันก็คงมีประโยชน์ยิ่งกว่าเดิม นั่นยังหมายความว่าคุณมีโน้ตของคอมมิตที่พอจะค้นกลับมาได้เมื่อเจอปัญหาคล้ายกันอีกครั้ง
    • อาจฟังดูแปลก แต่ถ้าเป็นโปรเจกต์ที่ผมมีส่วนร่วมจริงจัง ผมจะพยายามอย่างน้อยไล่ดูทุกคอมมิต สำหรับโอเพนซอร์สแล้ว คอมมิตเมสเสจนั้นอยู่ถาวร และอาจถูกทำดัชนีได้ทั้งโดยการค้นหาโค้ดและเสิร์ชเอนจินทั่วไป เพียงแต่ทุกวันนี้ GitHub บล็อกบอตมากขึ้นเรื่อย ๆ เลยอาจไม่เป็นแบบนั้นเท่าเดิม
      เวลา Google หรือ Stack Overflow ไม่มีคำตอบ ผมก็จะไปหาบน GitHub ว่ามี PR หรือคอมมิตเมสเสจที่พูดถึงเรื่องคล้ายกันไหม รวมถึงรีโพส่วนตัวที่ผมเข้าถึงได้ด้วย ซึ่งช่วยผมมานับครั้งไม่ถ้วน คอมมิตเมสเสจที่ดีมีคุณค่ามากกว่าความหลงตัวเองอย่างแน่นอน ถ้านักพัฒนาหลายคนไม่อ่าน ก็เป็นการเสียโอกาสของพวกเขาเอง และหวังว่าเมื่อมีประสบการณ์มากขึ้น วันหนึ่งพวกเขาจะเข้าใจ จะสอนนักพัฒนาจูเนียร์เรื่องวิธีค้นหา หรือส่งบทความต้นฉบับให้พวกเขาอ่านก็ได้
    • ผมเคยโดนคอมมิตเมสเสจที่สั้นเกินไปเล่นงานมาหลายครั้ง เวลาใครถามว่า “ทำไมถึงทำแบบนี้?” แล้วผมไปเปิดดูประวัติ Git ก็เจอข้อความที่ตัวเองเขียนไว้เมื่อ 3 ปีก่อนว่า “it should be done this way”
      หลังจากนั้นผมก็พยายามเขียนคอมมิตเมสเสจอย่างน้อยให้ตัวผมในอนาคตนึกออกได้ว่าทำไมตอนนั้นถึงต้องเปลี่ยน
    • ถ้าคุณไม่ git blame ก่อนจะเปลี่ยนโค้ดสักบรรทัด ก็แปลว่าคุณกำลังทำผิดอยู่
      หลายครั้งผมกำลังจะแก้บั๊กที่ดูชัดเจน แต่พอก่อนคอมมิตได้กลับไปดูคอมมิตก่อนหน้า ก็พบว่า “บั๊ก” นั้นใส่มาโดยตั้งใจ และงาน JIRA ที่ลิงก์ไว้ก็อธิบายไว้อย่างดีว่าทำไมการแก้ที่ดูชัดเจนของผมจะไปทำให้บั๊กเมื่อ 2 ปีก่อนกลับมาอีก
    • ผมใช้ฟังก์ชัน git blame ใน IDE บ่อยมากเพื่อดูว่าเกิดอะไรขึ้น พอเจอคอมมิตเมสเสจดี ๆ ก็รู้สึกขอบคุณ
  • บรรทัดแรกของคอมมิตเมสเสจสำคัญที่สุด เพราะ git log ใช้มันเพื่อรับมือกับ รั้วของเชสเตอร์ตัน ได้ ซึ่งในกรณีนี้ผมคิดว่าผู้เขียนพลาดเต็ม ๆ
    ประเด็นสำคัญคือบรรทัดแรกควรใส่เหตุผลว่าทำไปทำไม ไม่ใช่ใส่ว่าทำอะไรไปบ้าง คนที่สนใจก็ไปดูโค้ดหรือ diff เองได้ว่าอะไรเปลี่ยน
    เช่นจะเขียนว่า “nginx .conf files must be in us-ascii” แล้วตามด้วย “changed blahblah.erb to remove nonbreaking space character” จากนั้นค่อยต่อด้วยคอมมิตเมสเสจส่วนที่เหลือที่ค่อนข้างดีอยู่แล้วก็ได้
    ควรคิดแบบเขียนข่าว สมมุติว่าผู้อ่านอาจหยุดอ่านตรงไหนก็ได้ แล้วเรียงลำดับจากสิ่งที่สำคัญที่สุดไปหาสิ่งที่สำคัญน้อยลง พร้อมเพิ่มรายละเอียดมากขึ้นเรื่อย ๆ

    • บรรทัดแรกควร สรุปสิ่งที่เปลี่ยนไป ก่อน เพื่อให้หาคอมมิตที่เป็นปัญหาเจอได้
      แม้แต่พาดหัวข่าวก็อธิบายว่าเกิดอะไรขึ้น ไม่ใช่ว่าทำไม
      ในกรณีนี้ บรรทัดแรกของต้นฉบับเหมาะแล้ว พอไล่ดู git log ก็พอจะข้ามคอมมิตนี้ไปได้ เพราะมีแนวโน้มสูงว่ามันไม่ได้เปลี่ยนพฤติกรรมเชิงฟังก์ชันของการทดสอบ
    • คอมมิตเมสเสจของโปรเจกต์ทั่ว ๆ ไปไม่ใช่ที่สำหรับสอนใครเรื่องกฎของ nginx
      “nginx .conf files must be in us-ascii” อาจเหมาะเป็นหัวข้อบั๊กหรือชื่อ PR แต่ก็อาจสอดคล้องกับหลายคอมมิตที่ทำคนละอย่างกัน และไม่ได้บอกจริง ๆ ว่าเกิดอะไรขึ้น อาจเป็นการแปลงไฟล์ให้เป็น US-ASCII, การสร้างเครื่องมือสำหรับแปลง, การอัปเดตเอกสาร, การเขียนเทสต์ หรือหลายอย่างรวมกันก็ได้ ถ้าเริ่มจาก อะไร แทนที่จะเป็น ทำไม ก็จะลดความสับสนนั้นได้
    • จะบอกว่าแก่นสำคัญคือ บางครั้งมีการแสดงแค่บรรทัดแรก เพราะงั้นควรใส่ข้อความที่มีความหมายไว้ในบรรทัดแรก ไม่ใช่หรือ
      จะเป็น “The files must be in us-ascii” หรือ “Changed the files to us-ascii” ก็ไม่ได้ต่างกันมาก ทั้งสองแบบต่างก็สื่อชัดว่ามีการเปลี่ยนไฟล์ให้เป็น US-ASCII
  • ข้อเสียของการทำเอกสารแบบนี้คือ ข้อความคอมมิต ที่เขียนไปแล้วแทบจะแก้ไม่ได้อีก
    แน่นอนว่าทำได้ด้วย rebase แต่ถ้าเป็นสิ่งที่เขียนไว้เมื่อ 1 ปีก่อนและถูกรวมเข้า main ไปแล้ว จะถึงขั้นแก้มันจริง ๆ แล้วสร้างความลำบากให้ feature branch ของทุกคนหรือ
    ถ้าเทียบกับเอกสารที่เก็บไว้ในไฟล์ .md, Wiki, หรือ Confluence เนื้อหาที่เพื่อนร่วมงานเขียนสามารถให้ฉันปรับปรุงได้ และสิ่งที่ฉันเขียนก็ให้เพื่อนร่วมงานคนอื่นมาปรับปรุงได้เช่นกัน
    ในกรณีนี้บั๊กอาจถูกแก้แล้วและอาจไม่เกิดขึ้นอีก แต่เวลาคอมมิตคอมโพเนนต์ใดสักตัวก็มักมีแรงจูงใจให้อธิบายการออกแบบของมัน ซึ่งตอนนี้ฉันหลีกเลี่ยงแล้ว ถ้าคอมโพเนนต์นั้นเปลี่ยนไปในภายหลังเพราะข้อกำหนดทางธุรกิจเปลี่ยนล่ะ เอกสารในคอมมิตจะเหลือแค่อธิบายความต่างหรือไม่ ถ้าเป็นอย่างนั้น สมาชิกทีมใหม่ที่ต้องการเข้าใจระบบก็ต้องไปอ่านข้อความคอมมิตหลายอันแล้วรวมความเข้าใจเองในหัว

    • นั่นไม่ใช่ข้อเสีย คอมมิตคือ บันทึกประวัติศาสตร์ ดังนั้นเมื่อย้อนกลับมาดูอีก 3 ปีให้หลัง สิ่งที่อยากรู้คือในบริบทตอนนั้นจุดประสงค์ของมันคืออะไร ไม่ใช่อยากเห็นประวัติศาสตร์ที่ถูกขัดเกลาใหม่
      การเอาไปเทียบกับไฟล์ .md, Wiki, หรือ Confluence ก็เหมือนเอาจักรยานไปเทียบกับห่าน
      ข้อพิจารณาหรือการแลกเปลี่ยนที่มีตอนสร้างคอมโพเนนต์นั้น หรือแม้แต่ข้อเท็จจริงที่ว่าไม่มีสิ่งเหล่านั้นเลย มักมีประโยชน์ต่อการทำความเข้าใจข้อบกพร่องดั้งเดิม วิวัฒนาการหลังจากนั้น และข้อบกพร่องที่เกิดจากกรณีการใช้งานที่เปลี่ยนไป
      ถ้าสมาชิกทีมใหม่ต้องการเข้าใจระบบ ก็แค่ดูแลเอกสาร “สถานะปัจจุบัน” แยกไว้ เอกสารนั้นไม่จำเป็นต้องลงรายละเอียดถึงการแลกเปลี่ยนเชิง implementation หรือความจริงที่ว่าฉบับร่างแรกถูกเขียนขึ้นภายใต้แรงกดดันด้านเวลา
    • ผมกลับมองว่าการที่ข้อความคอมมิตแก้ไขไม่ได้เป็นข้อดี หลังจากเกิดเหตุไปแล้วมันอาจแก้ยาก แต่การไล่ตามประวัติของโค้ดเบสทีละขั้นนั้นเปิดเผยอะไรได้มากจริง ๆ
    • ข้อความคอมมิตไม่ใช่เอกสารที่ควรถูกอัปเดตเมื่อเวลาผ่านไป แต่เป็น บันทึกประวัติของการเปลี่ยนแปลงเพียงครั้งเดียว การมารู้ทีหลังว่าพลาดรายละเอียดสำคัญบางอย่างไปเป็นเรื่องน่าเสียดาย แต่โดยรวมแล้วผมคิดว่าสิ่งสำคัญคือมันต้องไม่เปลี่ยนแปลงเด็ดขาด
    • ผมคิดว่าความผิดพลาดของ Git คือเอา log ที่ไม่เปลี่ยนแปลงของสิ่งที่เปลี่ยนไป กับเรื่องเล่าที่ ideally ควรแก้ไขได้ของสิ่งที่ถูกรวมเข้าไป มาปะปนกัน เลยเกิดการถกเถียงเรื่องการ squash, reorder และ merge ของคอมมิต
      การ squash คอมมิตทำให้บันทึกดีขึ้นในฐานะเรื่องเล่าของการเพิ่มฟีเจอร์ ขณะที่ merge รักษา log ที่ไม่เปลี่ยนแปลงของการเปลี่ยนโค้ดจริงไว้ และ reorder ก็ทำทั้งสองอย่างอย่างละครึ่ง
      ไม่มีเหตุผลว่าทำไมจะมีทั้งสองแบบพร้อมกันไม่ได้ ก็เราเป็นคนที่เขียนโปรแกรมคอมพิวเตอร์กันอยู่แล้ว จะสร้างให้เป็นแบบที่ต้องการก็ได้
      ถ้าผมจะเขียน Git ใหม่ ผมจะแยกคอมมิตออกเป็นสองส่วน ประวัติการเปลี่ยนแปลงจะคงความไม่เปลี่ยนแปลงไว้ในโครงสร้างแบบ Merkle DAG เหมือน Git ส่วนข้อความคอมมิตจะเก็บไว้ใน data store ที่เกี่ยวข้องแยกต่างหาก เพื่อให้เป็น log ที่สมเหตุสมผลและแก้ไขได้สำหรับอธิบาย workflow จะจัดกลุ่มคอมมิตตามแท็กฟีเจอร์ แก้คำผิด และเปลี่ยนข้อความได้ตามต้องการ โดยยังคงเก็บ log ด้านล่างนั้นไว้เหมือนเดิม นั่นคือ “สิ่งที่เปลี่ยนจริงในโค้ด”
    • จะเสริมด้วย git notes ก็ได้ เพียงแต่ถ้าข้อความยาวขนาดนั้นก็ดูไม่น่ามีใครสังเกตเห็น
  • มีอยู่จุดหนึ่งที่ผมไม่เห็นด้วย คือประโยคที่ว่า “ผมไม่ได้คาดหวังรายละเอียดระดับนี้จากทุกคอมมิต โดยเฉพาะคอมมิตขนาดประมาณนี้”
    จากประสบการณ์ของผม ตรงกันข้ามเลย ของเล็ก ๆ ที่ดูไม่มีพิษมีภัยมักต้องการคำอธิบายที่ยาวกว่าเมื่อเทียบกัน
    เมื่อวานผมเขียนไว้สามย่อหน้าว่าทำไมถึงเพิ่ม --limit=999 ให้ gh pr list เพราะมันชวนสับสน ภายในอาร์กิวเมนต์ --jq ก็มี limit( อยู่แล้ว และถ้าถือว่า PR ทั้งหมดมีจำนวนอนันต์ ยิ่งค่ามาก ผลลัพธ์สุดท้ายก็ยิ่งน้อยลงจริง ๆ
    ผมยังเขียน code comment ไว้ด้วย และน่าจะใช้เวลาคิดกับเกลามันมากกว่าตอนลงมือเขียนเสียอีก เวลามีใครบอกเป็นนัยว่างานนี้คือการปั๊มโค้ดออกมามั่ว ๆ ก็อยากให้จำตัวอย่างนี้ไว้เป็นตัวอย่างถัดไป

    • เห็นด้วยว่าของเล็ก ๆ ที่ดูไม่มีพิษมีภัยมักต้องการคำอธิบายยาวกว่า แต่ผมคิดว่าข้อความคอมมิตในลิงก์นั้นยาวเกินไป มันทำให้เสียเวลาผู้อ่าน หรือทำให้ตาพร่าจากกำแพงข้อความ ไม่จำเป็นต้องบันทึกทั้งเส้นทางทั้งหมดเพื่อจะทำเอกสารว่าเจออะไรและเพราะอะไร
      แค่ “This was a non-ascii whitespace character that caused ArgumentError: invalid byte sequence in US-ASCII when running bundle exec rake” ก็น่าจะพอแล้ว มีทั้งคีย์เวิร์ดสำหรับค้นหาปัญหาคล้ายกันในภายหลัง มีสาเหตุรากของปัญหา และไม่ยาวเกินไปจนคนมักจะไถผ่าน
    • ถ้าเป็นคอมมิตที่เพิ่ม language binding ต่อให้มีการเพิ่มหรือลบเกิน 100 บรรทัด ก็อาจเขียนแค่ว่า “Add X function” ได้ เพราะมันแค่ทำตามแพตเทิร์นที่มีอยู่แล้ว แต่สำหรับการเปลี่ยนแปลงแบบในลิงก์ คำอธิบายหลายย่อหน้ามีประโยชน์ชัดเจน
    • ผมก็เขียน code comment ในแพตเทิร์นคล้ายกัน ส่วนแกนเล็ก ๆ ของโค้ดที่ “น่าสนใจ” จะมีสัดส่วน comment ต่อ code ตั้งแต่ 1:1 ขึ้นไป และด้วยเหตุนี้โค้ดเบสส่วนที่เหลือจึงสามารถคงไว้เป็น boilerplate ที่น่าเบื่อแต่ self-explanatory โดยไม่ต้องมีคอมเมนต์มากนัก
  • ผมไม่คิดว่านี่เป็นคอมมิต Git ที่ยอดเยี่ยม
    เมื่อเทียบกับข้อความจำนวนมากนั้น บรรทัดแรก “Convert template to US-ASCII to fix error” น่าจะทำให้ดีขึ้นได้ แค่เพิ่มอีกไม่กี่คำว่าช่องว่างแบบไหนเป็นตัวก่อปัญหา และ error คืออะไร
    เอาจริง ๆ ที่เหลือแทบไม่มีประโยชน์ ไม่ได้เป็นโทษ แต่ก็ไม่ได้มีคุณค่ามาก ผู้เขียนบันทึกเส้นทางที่ใช้ตามหาบั๊กนี้ไว้ ซึ่งก็อดคิดไม่ได้ว่าใครจะสนใจ

    • คนที่อยากเรียนรู้และเป็นโปรแกรมเมอร์ที่ดีขึ้นสนใจสิ เรื่องนี้บทความก็อธิบายคุณค่าของเนื้อหาเพิ่มเติมนั้นอยู่แล้ว ซึ่งแปลว่ามีคนสนใจ
      ในบทความยังมีลิงก์ผลการค้นหาที่แสดงคอมมิตหลายอันจากคนที่ได้เรียนรู้อะไรบางอย่างจากการแก้นั้น
      ข้อความคอมมิตนั้นคือ ขุมทรัพย์แห่งความรู้
  • ถ้าอยากดูข้อความคอมมิตที่ยอดเยี่ยม ให้ไปดู Git history ของ Linux kernel ที่นั่นนี่คือมาตรฐาน
    บรรทัดแรกจะพูดถึง subsystem ที่ได้รับผลกระทบจากการเปลี่ยนแปลงเสมอ แล้วตามด้วยสรุปหนึ่งบรรทัดในรูปคำสั่ง จากนั้นจะตอบสามคำถามให้ละเอียดที่สุดเท่าที่ทำได้

    1. พฤติกรรมปัจจุบันคืออะไร
    2. อะไรนำไปสู่การเปลี่ยนแปลงนี้
    3. หลังใช้การเปลี่ยนแปลงแล้ว พฤติกรรมใหม่คืออะไร
      ตัวอย่างเช่นอาจเขียนว่า “โค้ดปัจจุบันทำ X เมื่อรัน test case T พบพฤติกรรมที่ไม่คาดคิด U ซึ่งเกิดจากเหตุผล R จึงแก้โดยทำ F”
  • เมื่อไม่นานมานี้มีผู้ร่วมพัฒนาบอกว่าวิธีเขียนข้อความ Git ของฉัน หรือพูดอีกอย่างคือข้อกำหนดของฉันนั้น “แปลกเฉพาะตัว” ดูเหมือนภูมิหลังจาก Linux kernel จะโผล่ออกมา แต่ข้อความคอมมิตทั้งหมดของฉันก็หน้าตาเป็นแบบที่แสดงไว้ที่นี่
    ถ้าเป็นเรื่องเกี่ยวกับโค้ดเดิม คำอธิบายก็ควรอยู่ไปพร้อมกับโค้ด ส่วนเรื่องที่เกี่ยวกับกระบวนการ เช่น โค้ดที่ถูกลบออกไปหรือโค้ดที่เคยไม่ทำงาน ควรอยู่ในคอมมิต
    สิ่งที่สำคัญที่สุดคือ ถึงแม้ข้อความคอมมิตจะอ้างอิง issue เพื่อความสะดวกได้ แต่ก็ต้อง ระบุรายละเอียดแกนหลักซ้ำไว้ให้ครบ GitHub เป็นของชั่วคราว แต่ข้อความ Git ไม่ใช่

  • ข้อความคอมมิตที่อัดแน่นด้วยบริบทอยู่ที่นี่[1]
    เรื่องแบบนี้เกิดขึ้นบ่อยมากจนผู้ดูแลรักษาต้องเขียนบทความนี้[2]
    [1] https://github.com/git/git/commit/d70f554cdf38b0b05cfaa8e8eb...
    [2] https://lore.kernel.org/git/xmqqedevo8ps.fsf@gitster.g/