โค้ดชุดเดียว แต่ใช้บอร์ดหลายรุ่น จัดโปรเจกต์ยังไงดี

ตอนโปรเจกต์มีบอร์ดเพียงรุ่นเดียว เราอาจแก้ค่าขาและตัวเลือกบิ้วไว้ในไฟล์เดียวแล้วใช้งานต่อได้ แต่พอมีบอร์ดทดลองอีกตัวหรือเปลี่ยนรุ่นสำหรับติดตั้งจริง การคอยแก้ค่ากลับไปกลับมาก่อนอัปโหลดก็เริ่มเป็นสิ่งที่ต้องจำเพิ่ม
สิ่งที่ตามมาไม่ได้มีแค่โค้ดเยอะขึ้นครับ แต่เป็นคำถามว่าไฟล์ที่กำลังจะส่งออกไปถูกบิ้วสำหรับบอร์ดไหน ใช้ไลบรารีชุดใด และมีค่าทดลองติดไปหรือไม่ หากตอบจากความจำของคนที่กดบิ้วเพียงอย่างเดียว การรับช่วงงานก็จะยากขึ้นเรื่อยๆ
PlatformIO มี environment ให้แยกชุดตั้งค่าภายในโปรเจกต์ได้ แอดอยากชวนเริ่มจากใช้มันทำให้ความแตกต่างมองเห็นชัดก่อน แล้วค่อยจัดส่วนที่เหมือนกันให้ใช้ร่วมกันโดยไม่ซ่อนสิ่งสำคัญไว้มากเกินไป
environment เป็นชุดบิ้ว ไม่ใช่แค่ชื่อบอร์ด
ใน platformio.ini เรากำหนดชุดทำงานด้วยรูปแบบ [env:ชื่อ] โดยแต่ละชุดเลือก platform, board, framework และตัวเลือกที่เกี่ยวข้องได้ ส่วน [env] ใช้เก็บค่าร่วมที่ส่งต่อไปยังชุดย่อยตามกติกาของ PlatformIO
ชื่อ environment จึงควรบอกบทบาทหรือฮาร์ดแวร์ที่ตั้งใจใช้ ไม่ใช่ชื่อที่จำได้เพียงคนเดียว และควรระวังไม่ใช้คำว่า prod ให้หมายถึงหลายอย่างพร้อมกัน เช่น บอร์ดติดตั้งจริงกับบริการปลายทางจริง เพราะเป็นความต่างคนละแกนที่ต้องตัดสินให้ชัด

ตัวอย่างโครงสั้นๆ อาจแยกบอร์ดสองรุ่นแบบนี้ โดยเป็นตัวอย่างจัดรูปไฟล์ ไม่ใช่ชุดตั้งค่าที่ทดสอบกับวงจรของผู้อ่านแล้ว และยังต้องกำหนดรุ่นเครื่องมือกับตัวเลือกเฉพาะบอร์ดตามงานจริง
[env]
platform = espressif32
framework = arduino
monitor_speed = 115200
[env:bench]
board = esp32dev
build_flags = -D APP_BOARD_ESP32
[env:s3]
board = esp32-s3-devkitc-1
build_flags = -D APP_BOARD_ESP32S3
จุดที่อยากให้เห็นคือความต่างถูกวางแยกไว้ โดยไม่ต้องเปลี่ยนค่า board ในบรรทัดเดิมทุกครั้ง ส่วนค่าร่วมยังมีที่เดียวให้ตรวจ แต่เมื่อเพิ่มตัวเลือกใหม่ก็ควรอ่านกติกาว่าการเขียนในชุดย่อยเป็นการแทนค่าหรือจำเป็นต้องอ้างส่วนร่วมเพิ่มเอง
จับความต่างของฮาร์ดแวร์ให้อยู่เป็นกลุ่ม
ขาของเซนเซอร์ ไฟสถานะ และความสามารถที่แต่ละบอร์ดมีควรถูกจัดเป็นส่วนที่ชัดเจนในโค้ด เช่น ไฟล์ตั้งค่าฮาร์ดแวร์หรือชั้นเชื่อมอุปกรณ์ เพื่อให้ส่วนตรรกะหลักไม่ต้องเต็มไปด้วยเงื่อนไขกระจายทุกไฟล์
การใช้ macro จาก build flags ช่วยเลือกชุดได้ แต่ต้องตรวจว่าครอบคลุมกรณีที่ตั้งใจจริง หากไม่เลือกหรือเลือกขัดกัน ควรให้บิ้วแจ้งปัญหาตามการออกแบบ ไม่เงียบแล้วใช้ชุดค่าตั้งต้นที่อาจต่อกับวงจรคนละแบบ
อย่าดูเพียงเลขขาเหมือนกันแล้วถือว่าความหมายเหมือนกัน บอร์ดแต่ละรุ่นมีวงจรและข้อจำกัดการใช้งานของขาต่างกัน จึงควรเก็บเหตุผลการเลือกขาคู่กับรุ่นฮาร์ดแวร์ รวมถึงอุปกรณ์บนบอร์ดที่จองใช้อยู่แล้ว
เมื่อเพิ่มรุ่นใหม่ ลองตรวจรายการความสามารถที่แอปต้องใช้ก่อน เช่น อินเทอร์เฟซ หน่วยความจำ และเส้นทางอัปเดต จะได้ไม่ให้การบิ้วผ่านเป็นหลักฐานแทนว่าบอร์ดใหม่ทำงานกับอุปกรณ์ทั้งหมดได้แล้ว
ไลบรารีกับ platform ก็ควรย้อนรุ่นได้
การแยก environment ช่วยบอกชุดตั้งค่า แต่ถ้าปล่อยให้ dependency เปลี่ยนไปตามเวลาที่บิ้ว เราก็ยังอาจได้ไฟล์ต่างกันจากโค้ดชุดเดียว ควรระบุรุ่นหรือขอบเขตที่ทดสอบตามวิธีที่ระบบรองรับ และเก็บรายละเอียดเครื่องมือไว้กับรุ่นที่เผยแพร่
lib_deps ใช้ประกาศไลบรารีที่โปรเจกต์ต้องใช้ ส่วนแต่ละ environment อาจมีความต่างได้ แต่ต้องตรวจการสืบทอดค่าให้ชัด หากกำหนดรายชื่อในชุดย่อยแล้วลืมส่วนร่วม การเปลี่ยนเล็กๆ อาจทำให้ dependency บางตัวหายไปจากชุดนั้น

ถ้ามี library ที่แอปเลือกเองกับตัวที่ framework พ่วงมา ควรดูว่าตอนบิ้วกำลังใช้ตัวใดจริง การมีชื่อเหมือนกันในโค้ดไม่ได้รับประกันว่าเครื่องพัฒนาทุกเครื่องกำลังแก้ปัญหาด้วย dependency รุ่นเดียวกัน
ข้อมูลที่ควรไปกับ artifact จึงมีทั้ง commit, environment, platform/framework และรายการรุ่นที่เกี่ยวข้อง ไม่ใช้เพียงชื่อ firmware.bin เป็นหลักฐานว่าบิ้วจากอะไร เพราะไฟล์ชื่อเดียวกันสามารถเกิดจากชุดตั้งค่าหลายแบบได้
กดบิ้วให้ชัดว่ากำลังเลือกชุดไหน
ตอนใช้คำสั่งสามารถระบุชุดอย่าง pio run -e bench หรือ pio run -e s3 เพื่อให้การเลือกอยู่ในขั้นตอนที่ย้อนดูได้ ส่วนค่าเริ่มต้นของโปรเจกต์ก็ควรกำหนดให้ตรงกับงานที่ทีมตั้งใจ ไม่ปล่อยให้ทุกคนเดาว่าปุ่ม build ในเครื่องตัวเองใช้ชุดเดียวกันหรือไม่
การอัปโหลดต้องตรวจพอร์ตและบอร์ดเป้าหมายอีกชั้น เพราะการบิ้วถูกชุดแต่ส่งผิดเครื่องก็ยังเกิดได้ ในช่วงเริ่มต้นควรให้เฟิร์มแวร์รายงานตัวตนของ build ออกมา เพื่อดูว่าบอร์ดที่เปิดอยู่กำลังใช้รุ่นและ environment ใดจริง
ค่าเครือข่ายหรือข้อมูลลับที่แต่ละเครื่องต้องใช้ไม่ควรถูกรวมเข้าไปใน environment โดยไม่คิดวิธีดูแลต่อ โดยเฉพาะค่าที่ไม่จำเป็นต้องบิ้วใหม่เมื่อเปลี่ยน อาจเหมาะกับขั้น provision หรือ runtime configuration ตามความต้องการของระบบมากกว่า
เพิ่มการตรวจตามจำนวนชุดที่ต้องดูแล
เมื่อมีหลาย environment ควรมีรายการว่าชุดใดต้องบิ้วผ่านในรุ่นหนึ่ง และชุดใดต้องทดสอบฮาร์ดแวร์จริง ไม่ให้การแก้ส่วนกลางตรวจเพียงบอร์ดที่กำลังเสียบอยู่แล้วถือว่าทุกชุดพร้อมตามไปด้วย
ผลบิ้วช่วยตรวจส่วนของเครื่องมือกับโค้ด แต่พฤติกรรมขา การอ่านอุปกรณ์ และการกู้คืนยังต้องทดสอบกับวงจรจริง เมื่อแยกสถานะหลักฐานเหล่านี้ไว้ คนรับไฟล์ไปติดตั้งก็จะรู้ว่ารุ่นนี้ผ่านอะไรแล้วและยังมีส่วนใดต้องตรวจต่อ
บอร์ดที่ชื่อใกล้กันอาจมีรุ่นย่อยด้าน flash และ PSRAM ต่างกันด้วย จึงควรตรวจ board definition ให้ตรงกับตัวที่มีอยู่ ไม่ใช้ชื่อ environment ที่ตั้งเองเป็นหลักฐานแทนรุ่นฮาร์ดแวร์จริง
สรุป
การแยก environment ใน PlatformIO ช่วยให้ชุดบิ้วของบอร์ดแต่ละแบบมองเห็นและเลือกซ้ำได้ แต่ควรจัดค่าฮาร์ดแวร์ dependency และตัวตนของ artifact ไปด้วยกัน เมื่อขั้นบิ้วกับอัปโหลดระบุเป้าหมายชัด เราจะลดการสลับค่าตามความจำ และมีข้อมูลพอรับช่วงเมื่อโปรเจกต์ไม่ได้อยู่กับบอร์ดตัวเดียวอีกแล้วครับ


