GitHub Actions กำลังค่อยๆ ฆ่าทีมวิศวกรรม
(iankduncan.com)- แม้จะถูกใช้อย่างแพร่หลายเพราะเป็น CI ที่รวมมาให้เป็นค่าเริ่มต้นในรีโป แต่ ความไม่มีประสิทธิภาพเชิงโครงสร้างและประสบการณ์ผู้ใช้ที่ไม่เสถียร กลับลดทอนประสิทธิภาพการทำงานของนักพัฒนา
- ตัวดูบันทึกที่โหลดช้าและทำให้เบราว์เซอร์ล่ม, รวมถึง ไวยากรณ์ YAML ที่ซับซ้อนและข้อผิดพลาดของ expression ทำให้ต้องดีบักซ้ำแล้วซ้ำเล่า
- ด้วย โครงสร้างที่ไม่ได้เป็นเจ้าของทรัพยากรคอมพิวต์เอง จึงมีข้อจำกัดด้านประสิทธิภาพ การขยายระบบ และการควบคุมสภาพแวดล้อม
- หลายครั้งเมื่อพยายามเลี่ยงปัญหาเหล่านี้ ก็ลงเอยด้วยการ สร้าง CI ขึ้นมาใหม่ในรูปของ YAML ที่ซับซ้อนหรือ Bash script ขนาดใหญ่
- เมื่อเทียบกันแล้ว Buildkite มอบ ทางเลือก CI ที่ดูแลรักษาได้ในระยะยาว ผ่านโครงสร้าง YAML ที่เรียบง่าย เอเจนต์ที่โฮสต์เองได้ และประสบการณ์การดูบันทึกที่ใช้งานได้จริง
ปัญหาของ GitHub Actions
- ตัวดูบันทึกของ GitHub Actions ไม่มีประสิทธิภาพ: แม้แค่การตรวจสอบข้อผิดพลาดง่ายๆ ก็ยังต้องคลิกหลายขั้นและรอโหลดหลายหน้า
- เมื่อบิลด์ล้มเหลว ต้องไล่จากหน้าสรุป check → หน้าการรัน workflow → หน้า job → คลิก step ที่ถูกพับไว้ ทำให้ต้อง เปลี่ยนหน้า 3–4 ขั้น และแต่ละขั้นก็มีการโหลดแยกกัน
- ทำให้เบราว์เซอร์ล่มซ้ำๆ เมื่อเจอบันทึกบิลด์ขนาดใหญ่ และอาการที่ Chrome ค้างเมื่อใช้ฟังก์ชันค้นหาก็เกิดซ้ำได้จริง
- ในบันทึกที่ยาวมาก บางครั้งเลื่อนหน้าจอไม่ได้เลย จนสุดท้ายต้อง ดาวน์โหลด raw log artifact มาเปิดใน text editor
- ปุ่มย้อนกลับไม่ได้พากลับไปยังหน้า PR เดิม แต่พาไปยัง หน้าตา UI ของ GitHub Actions ที่คาดเดาไม่ได้ ทำให้ประวัติเบราว์เซอร์เต็มไปด้วย URL ของ Actions
- กระบวนการดีบักที่ไม่ก่อให้เกิดผลผลิต
- หากต้องการตรวจสอบตัวแปรสภาพแวดล้อม ต้องเพิ่ม step
run: envแล้ว push ใหม่ ส่งผลให้เกิด feedback loop 20 นาที และเมื่อเปลี่ยนเพียงบรรทัดเดียวก็อาจต้องทำซ้ำเป็นสิบครั้ง - feedback loop แบบครั้งละ 20 นาทีเกิดซ้ำไปมา จนเวลาทำงานทั้งวันหมดไปกับการรอ CI
- หากต้องการตรวจสอบตัวแปรสภาพแวดล้อม ต้องเพิ่ม step
- ข้อจำกัดเชิงโครงสร้างของ YAML
- YAML ของ GitHub Actions เป็นรูปแบบพิเศษที่รวม ภาษา expression ของตัวเอง, โมเดล context object และกฎการแทรกสตริง เข้าด้วยกัน
- หากใส่เครื่องหมายอัญประกาศผิดไปเพียงตัวเดียวใน expression
${{ }}ก็ต้องรอ 4 นาทีจน runner เริ่มทำงาน ถึงจะพบว่าสตริงหายไป - ไวยากรณ์ของ expression อยู่ใน พื้นที่กึ่งกลาง (liminal space) ที่ซับซ้อนเกินไปสำหรับการใช้เป็น configuration แต่ก็จำกัดเกินไปสำหรับการใช้เป็นภาษาโปรแกรมจริง
- เป็นโครงสร้างที่ทำให้ต้อง เรียนรู้ไวยากรณ์ผ่านความล้มเหลว มากกว่าผ่านเอกสาร
- ความเสี่ยงด้านความปลอดภัยของ Marketplace
- เมื่อดึง external action ผ่านไวยากรณ์
uses:เท่ากับมอบ สิทธิ์เข้าถึงรีโป ซีเคร็ต และสภาพแวดล้อมบิลด์ ให้กับ third party ที่ยังไม่ได้รับการตรวจสอบ - แม้จะ pin SHA ได้ แต่แทบไม่มีใครทำจริง และถึงจะ pin แล้วก็ยังเป็นการรัน โค้ดทึบแสงที่ไม่ได้อ่าน พร้อมสิทธิ์เข้าถึง
GITHUB_TOKEN - Marketplace ปะปนไปด้วย action ที่ชุมชนดูแลซึ่งมีคุณภาพหลากหลาย และส่วนใหญ่ประกอบด้วย shell script และ Dockerfile
- การจัดการ dependency ไม่โปร่งใส และมีความเป็นไปได้ที่จะรันโค้ดที่ไม่ปลอดภัย
- เมื่อดึง external action ผ่านไวยากรณ์
- ข้อจำกัดของสภาพแวดล้อมคอมพิวต์
- runner เริ่มต้นของ GitHub Actions คือ shared runner ที่ Microsoft เป็นเจ้าของ ซึ่งช้า ทรัพยากรจำกัด และแทบปรับแต่งอะไรสำคัญไม่ได้
- ค่าใช้จ่ายของ runner ที่ใหญ่ขึ้นนั้นสูงถึงระดับที่ฝ่ายการเงินอาจส่งคำเชิญประชุมแบบ "ขอคุยหน่อย" และถึงอย่างนั้นก็ยังควบคุมสภาพแวดล้อมไม่ได้
- มีสตาร์ตอัปอย่างน้อย 6 ราย เช่น Namespace, Blacksmith, Actuated, Runs-on, BuildJet ที่โฟกัสเฉพาะการแก้ปัญหาความช้าของ runner ใน GitHub Actions เพียงอย่างเดียว ซึ่งสะท้อนให้เห็นว่าพื้นฐานของสภาพแวดล้อมคอมพิวต์นั้นไม่เพียงพอ
- การตั้งค่า self-hosted runner ช่วยแก้ปัญหาด้านคอมพิวต์ได้ แต่ปัญหาอื่นๆ อย่าง YAML expression, โมเดลสิทธิ์, Marketplace และตัวดูบันทึกยังคงอยู่เหมือนเดิม
ปัญหาเล็กๆ ที่สะสมจนใหญ่
actions/cache: cache key ชวนสับสน, cache miss เกิดขึ้นแบบเงียบๆ และการไล่ cache ออก (eviction) ก็ไม่โปร่งใส ทำให้เสียเวลากับการดีบักแคชมากกว่าที่ประหยัดได้จากการใช้แคช- Reusable workflow: ซ้อนลึกเกินระดับหนึ่งไม่ได้, เข้าถึง context ของ workflow ที่เรียกใช้อย่างสะอาดไม่ได้, และทดสอบแบบแยกส่วนไม่ได้
- โมเดลสิทธิ์ของ
GITHUB_TOKEN:permissions: write-allกว้างเกินไป ส่วนการกำหนดสิทธิ์แบบละเอียดก็มี ปฏิสัมพันธ์ระหว่างการตั้งค่าระดับรีโป ระดับ workflow และระดับ job ที่ซับซ้อนเหมือนเขาวงกต - การควบคุม concurrency: การยกเลิกการรันที่กำลังทำงานอยู่บนสาขาเดียวกันทำได้ในบรรทัดเดียว แต่การควบคุมที่ละเอียดกว่านั้นไม่รองรับ
- ใช้ซีเคร็ตในเงื่อนไข
ifไม่ได้: การรันแบบมีเงื่อนไขอย่างif: secrets.DEPLOY_KEY != ''ทำไม่ได้ ซึ่งแม้จะสมเหตุสมผลในเชิงความปลอดภัย แต่ก็ทำให้ต้องหาทางอ้อมเมื่อต้อง เขียน workflow ที่ทำงานได้ทั้งกับ fork และรีโปหลัก
กับดักของคำว่า "งั้นก็ใช้ Bash script ไปเลย"
- วิศวกรที่เหนื่อยกับ CI YAML มักถูกล่อลวงให้ แทนที่ทุกอย่างด้วย bash script ใน
run:แต่เมื่อเวลาผ่านไปก็จะเริ่มเพิ่มเงื่อนไข ฟังก์ชัน การ parse อาร์กิวเมนต์ และการประมวลผลแบบขนาน - ผ่านไป 3 เดือน ก็จะได้ bash 800 บรรทัดที่ reimplement การทำงานขนานของ job ด้วย
waitและไฟล์ PID พร้อมตรรกะ retry และการ parse output ของตัวเอง - สุดท้ายแล้วไม่ได้หนีออกจากระบบ CI แต่กลับ สร้างระบบ CI ที่แย่กว่าเดิมด้วย bash เอง ทั้งไม่มี test framework และไม่มีใครตามทัน
- Bash เหมาะกับการเป็นกาวเชื่อม (glue) แต่ถ้าใช้เป็นระบบบิลด์หรือ test harness จะกลายเป็น การย้ายความซับซ้อนจากที่ที่มีรั้วป้องกัน ไปยังที่ที่ไม่มีรั้วป้องกันเลย
แนวทางทางเลือกของ Buildkite
-
ตัวดูบันทึกที่เสถียร
- ตัวดูบันทึกของ Buildkite แสดงบันทึกได้ตามปกติโดยไม่ทำให้เบราว์เซอร์ล่ม และยัง render ANSI color กับฟอร์แมตของ test framework ได้ครบ
- ด้วยฟีเจอร์ Annotation แต่ละ build step สามารถ แสดงสรุป test ที่ล้มเหลว รายงาน coverage หรือลิงก์ deployment เป็น Markdown บนหน้าบิลด์ได้โดยตรง
- เนื่องจากเอเจนต์รันบนโครงสร้างพื้นฐานของตัวเอง จึงสามารถ SSH เข้าไปยังเครื่องบิลด์ เพื่อดีบักโดยตรงได้
-
โครงสร้าง YAML ที่เรียบง่าย
- YAML ของ Buildkite เป็น โครงสร้างข้อมูลล้วนสำหรับอธิบาย pipeline ที่ประกาศเพียง step, command และ plugin
- หากต้องมีตรรกะจริง ก็ให้เขียนสคริปต์ด้วย ภาษาโปรแกรมจริงที่รันได้บนเครื่องโลคัล
- มัน รักษาเส้นแบ่งให้ชัดเจน ตามแนวคิด "orchestration อยู่ใน config, logic อยู่ใน code" ซึ่งเป็นเส้นแบ่งเดียวกับที่ GitHub Actions ทำให้พร่ามัว
-
ควบคุมสภาพแวดล้อมคอมพิวต์ได้อย่างสมบูรณ์
- เอเจนต์ของ Buildkite เป็น ไบนารีเดี่ยว ที่รันได้ทุกที่ ไม่ว่าจะเป็นคลาวด์ของตัวเอง on-premises หรือฮาร์ดแวร์คัสตอม
- สามารถ ควบคุม instance type, caching, local storage และเครือข่ายได้ทั้งหมด รองรับตั้งแต่ EC2 ขนาดใหญ่ที่มี NVMe drive และ Docker layer cache 20GB ไปจนถึง Raspberry Pi
- ไม่มีอุตสาหกรรม third party แบบ "Buildkite แต่เร็วกว่า" เพราะแค่ รันเครื่องที่ใหญ่ขึ้น ก็พอ
- สำหรับ ผู้ดูแลโปรเจกต์เดี่ยว ที่ดูแลไลบรารีโอเพนซอร์สขนาดเล็ก free tier ของ GitHub Actions สำหรับ public repo ก็ยังมีคุณค่าอยู่
- กลุ่มเป้าหมายหลักของบทความนี้คือ ทีมที่ดูแลระบบ production ซึ่งเวลาของ CI วัดเป็นเวลาวิศวกรรมที่สูญเสียต่อสัปดาห์ และบิลด์ที่ใช้เวลา 45 นาทีมีต้นทุนทั้งด้านคอมพิวต์และค่าแรงคน
- ในสภาพแวดล้อมแบบนั้น ค่าใช้จ่ายส่วนเพิ่มจากการดูแล Buildkite agent จะ คืนทุนได้อย่างรวดเร็ว
-
รองรับ dynamic pipeline
- ใน Buildkite แต่ละ pipeline step คือ ข้อมูล และสคริปต์สามารถสร้าง step เพิ่มแบบไดนามิกระหว่างรันไทม์ (emit) แล้วอัปโหลดได้
- ใน monorepo สามารถ สร้างเฉพาะ step สำหรับบิลด์และทดสอบที่จำเป็นตามไฟล์ที่เปลี่ยน ได้อย่างแม่นยำ โดยไม่ต้องใช้ hardcoded matrix หรือสปาเกตตี
if: contains(...) matrix, เงื่อนไขifและ reusable workflow ของ GitHub Actions พยายามทำสิ่งนี้แบบคร่าวๆ แต่สุดท้ายกลับกลายเป็นการ สร้างเครื่องจักรรูบ โกลด์เบิร์กในภาษาประกาศเชิงประกาศที่แสดงออกได้น้อย
-
ความเรียบง่ายของโครงสร้างปลั๊กอิน
- ในเชิงโครงสร้าง มันคล้ายกับ GitHub Actions Marketplace ตรงที่เป็น การดึงโค้ดมาจากรีโปของ third party
- แต่ความต่างคือ plugin ของ Buildkite ส่วนใหญ่ไม่ใช่ Docker image หากเป็นเพียง thin shell hook ที่มีพื้นผิวเล็กและอ่านทั้งหมดได้ภายในไม่กี่นาที
- และเพราะมันรันบนโครงสร้างพื้นฐานของคุณเอง blast radius จึงอยู่ภายใต้การควบคุมของผู้ใช้
-
รายละเอียดที่ให้ความสำคัญกับประสบการณ์ผู้ใช้
- Buildkite สามารถแสดง custom emoji (
:parrot:,:docker:เป็นต้น) ข้าง pipeline step ได้ ซึ่งแม้จะดูเป็นเรื่องเล็กน้อย แต่สะท้อนถึง ความใส่ใจในประสบการณ์การใช้ผลิตภัณฑ์ - ส่วน GitHub Actions ดูเหมือนเป็น ผลผลิตของการออกแบบโดยคณะกรรมการ ที่ไม่เคยถามเลยว่า "มันใช้งานแล้วรู้สึกดีไหม?"
- Buildkite สามารถแสดง custom emoji (
บทสรุป: เกณฑ์ในการเลือกระบบ CI
- GitHub Actions ครองตลาดได้เพราะข้อได้เปรียบด้าน การมีมาให้เป็นค่าเริ่มต้น (default) ใช้กับ public repo ได้ฟรี ฝังอยู่ในแพลตฟอร์มที่ทุกคนใช้อยู่แล้ว และอยู่ในระดับ "ดีพอใช้ (Good Enough)"
- มันจึงคล้าย Internet Explorer ของโลก CI และยังคงถูกใช้ต่อไปเพราะต้นทุนการย้ายระบบเป็นเรื่องจริง ขณะที่เวลาก็มีจำกัด
- Buildkite เหนือกว่าในด้าน การใช้งานได้ต่อเนื่องในระยะยาวและประสบการณ์นักพัฒนา
- สำหรับโปรเจกต์โอเพนซอร์สทั่วไป GitHub Actions ก็เพียงพอ แต่ใน สภาพแวดล้อม production ขนาดใหญ่ Buildkite เหมาะสมกว่า
- ในประวัติศาสตร์ของระบบ CI สิ่งที่ชนะส่วนแบ่งตลาดไม่ใช่ ระบบที่ดีที่สุด แต่คือ ระบบที่เริ่มใช้งานได้ง่ายที่สุด
- GitHub Actions คือ CI ที่ เริ่มใช้ง่ายที่สุด ส่วน Buildkite คือ CI ที่ เหมาะกับการใช้งานต่อเนื่องมากที่สุด และในระยะยาวอย่างหลังสำคัญกว่า
- หากเครื่องมือ CI ถูกออกแบบมาในแบบที่คอยดูดเวลาของนักพัฒนา ปัญหาไม่ได้อยู่ที่นักพัฒนา แต่อยู่ที่ตัวเครื่องมือเอง
3 ความคิดเห็น
ดูเหมือนว่าปัญหาคือตัว CI เองที่ซับซ้อนขึ้นเรื่อย ๆ
เหมือนว่าบทความเดียวกันถูกโพสต์ขึ้นมาสองรอบนะ แต่ช่วงนี้ดูเป็นการจับคู่ที่ AI น่าจะจัดองค์ประกอบออกมาได้โอเคเหมือนกัน..
ความเห็นบน Hacker News
ฉันเคยใช้ ระบบ CI มาหลายตัว ใช้ทั้ง CircleCI และ GitHub Actions เยอะมาก แต่ได้ข้อสรุปไม่เหมือนผู้เขียน
เมื่อก่อน Jenkins เหมือนจะเฉพาะทางสำหรับ Java ส่วน Travis ก็เหมือนจะเฉพาะทางสำหรับ Rails แต่ CI แบบเฉพาะทาง พวกนี้สุดท้ายก็ไปต่อได้ไม่ไกล ตอนนี้ CI พัฒนาไปเป็นแค่ workflow orchestrator แล้ว
เหตุผลที่ย้ายจาก CircleCI 2 มา GitHub Actions ก็เพราะ CircleCI ปรับตัวกับการเปลี่ยนผ่านนี้ได้ไม่ดีพอ ส่วน GHA มีความยืดหยุ่นในการแสดงออกเพียงพอ
เรื่องอย่าง log browser หรือไวยากรณ์ YAML เป็นปัญหาเล็กน้อย สิ่งสำคัญคือ การเป็นเจ้าของทรัพยากรคอมพิวต์ กับ dynamic pipeline ซึ่งอย่างแรก CI ทุกเจ้าทำได้ ส่วนอย่างหลังเป็นจุดเด่นของ Buildkite
สรุปของฉันคือ Actions โดยรวมถือว่าดีพอใช้มาก ถ้าจะตั้งบริษัทใหม่คงเลือก Buildkite แต่ถ้าเป็นโอเพนซอร์สจะใช้ Actions
ถ้าไม่เข้าใจ build graph ก็ต้องคอยรักษาสถานะ incremental build เอาไว้ ซึ่งนั่นทำให้เกิด บั๊กที่โผล่มาเป็นพักๆ ได้ เลยจำเป็นต้องใช้ระบบอย่าง UnrealEngine Horde หรือ UBA ที่เข้าใจโครงสร้างการ build อย่างลึกซึ้ง
ถ้าใช้ CI แบบทั่วไป บางที build อาจกินเวลาเกินหนึ่งวัน
ฉันมักเลือกใช้เฉพาะส่วนที่ดีของ GHA เช่น GitHub ยอดเยี่ยมในฐานะ event dispatcher แต่ไม่ค่อยดีในฐานะ workflow orchestrator ดังนั้นส่วนนั้นฉันจะยกให้ระบบอื่นทำ
ถ้าต้องดูล็อกที่ใช้งานยากวันละหลายสิบครั้ง ประสิทธิภาพการทำงานก็ลดลง การอ่าน raw log พร้อมพยายามมองข้าม escape code นั้นทรมานจริงๆ
ฉันเลือกทำให้มันเรียบง่าย ใส่ orchestration ทั้งหมดไว้ในสคริปต์ deploy.sh แล้วรันบน Mac เครื่องตัวเองหรือบน AWS CodeBuild
YAML มีแค่บรรทัดเดียวคือ
bash deploy.shขอแค่มี Docker container ก็ทำงานเหมือนกันได้ทุกที่ ไม่ว่าจะ Azure, GitHub Actions หรือที่ไหนก็ตามกลยุทธ์หลักของทุกสภาพแวดล้อม CI คือ ต้องมีระบบ build แบบเดียวกับที่ใช้บนเครื่อง local
ฉันเริ่มจาก Makefile เสมอ ทั้ง Docker, CI build, linting และทุกอย่างให้ Makefile เป็นตัวขับ ถ้าโปรเจกต์ใหญ่ขึ้นก็อาจค่อยย้ายไปใช้เครื่องมืออื่น แต่พื้นฐานคือมีเครื่องมือ trigger เพียงตัวเดียว
ฉันใช้ Fastlane กับงานมือถือเยอะมาก มันช่วยลด boilerplate และให้โครงสร้างที่ดี สุดท้ายมันก็เป็น Ruby อยู่ดี ถ้าจำเป็นก็ยังหนีออกมาได้
(ลิงก์เอกสาร GNU Make)
สุดท้ายมันก็เหมือนกับการบอกว่า “ก็เขียน Bash script ไปเลยสิ” แต่เพิ่มความซับซ้อนที่ไม่จำเป็นเข้าไป
ที่บริษัทปัจจุบันก็เป็นแบบนี้เหมือนกัน จนถึงจุดที่รัน pipeline ทั้งหมดบนเครื่อง local ไม่ได้แล้ว เลยกลายเป็น โครงสร้างพื้นฐาน CI ขนาดมหึมา ที่ต้องรัน build เป็นสิบครั้งเพื่อทดสอบ MR เดียว
ฉันรู้สึกว่าบทความนี้ เหมือนโฆษณา Nix/Buildkite
CI แค่รันสคริปต์หรือ target ของ build ได้ก็พอแล้ว หน้าที่ของ CI คือให้ environment กับ config ส่วน logic ควรอยู่ในโค้ด
แบบนี้จะได้ ความเป็นอิสระจาก CI ทำให้ย้ายระบบได้ง่าย
GitLab CI รับมือกับความซับซ้อนแบบนี้ได้ดีทีเดียว ความสามารถด้าน template และการประกอบ job นั้นยอดเยี่ยม แต่การดีบักยาก และ logic แบบมีเงื่อนไขก็มักพังแบบคาดไม่ถึง
.shย้ายได้ง่ายมากส่วนทีมที่แยกย่อยทุกอย่างไว้ใน UI ต้องเหนื่อยกันมาก
ปัญหาไม่ใช่ตัว CI/CD เอง แต่เป็น วัฒนธรรมการเขียนโปรแกรมผ่านไฟล์ config
ลูปแบบ
git commit -m "try fix"แล้วรอ 10 นาทีเป็นเรื่องที่เจอกันบ่อยเกินไป สภาพแวดล้อม CI ที่ ทำซ้ำบนเครื่อง local ได้ ก็ยังขาดอยู่มากถ้ากำหนดเรื่องการแยก environment เป็นนโยบาย ต่อให้ใช้เครื่องมือไหนก็ไม่มีปัญหา สุดท้ายหัวใจคือ การผสานกันของเครื่องมือกับวิธีการทำงาน
actช่วยมากในการจำลอง CI บนเครื่อง localชื่อเรื่องที่บอกว่า “กำลังฆ่าทีมวิศวกร” นั้นเว่อร์ไปหน่อย GitHub Actions ใช้งานได้ดีพอสมควร
ฉันชอบมันมากกว่า Bitbucket หรือ GitLab
ช่วงหลังมานี้ ความน่าเชื่อถือของ GitHub แย่ลงมาก
actions/checkoutล้มเหลวแบบไม่มีเหตุผล, release job ถูกรันสองรอบ หรือบางครั้งก็ค้างรออยู่ 40 นาทีใช้มาหลายปีแล้ว แต่รู้สึกว่าความเสถียรพื้นฐานกำลังถดถอย เสียดายที่พลาดไม่ได้ใช้ Buildkite
GitHub Actions เป็นหนึ่งใน เครื่องมือ CI ที่แย่ที่สุด ที่ฉันเคยใช้ (พอๆ กับ Jenkins)
ในทางกลับกัน Buildkite คือที่สุด dynamic pipeline ของมันช่วยให้สร้างสเต็ป retry อัตโนมัติเมื่อการทดสอบล้มเหลว หรือปรับการทดสอบแบบขนานตามการเปลี่ยนแปลงของโค้ดได้
การที่แต่ละ CI job ใช้สเปกเครื่องต่างกันได้ก็เป็นข้อดีมาก แนะนำอย่างยิ่ง
คนที่สนับสนุนแนวคิด “CI แบบเรียบง่ายอิงสคริปต์” น่าจะ ไม่เคยผ่านประสบการณ์โปรเจกต์จริงขนาดใหญ่