Shiny Toy
เชื่อว่าทุกปัญหาแก้ได้ด้วยเครื่องมือใหม่ล่าสุดเสมอ
ปัญหาคืออะไร
หัวข้อที่มีชื่อว่า “ปัญหาคืออะไร”Shiny Toy คือการ คิดเสมอว่าปัญหาวันนี้แก้ได้ด้วยเครื่องมือ เทคนิค หรือ library ใหม่ล่าสุด (bleeding-edge) โดยไม่ประเมินความเสี่ยงหรือความสุกงอมของมันก่อน
แม้วงการซอฟต์แวร์จะพัฒนาตลอดเวลา และของใหม่มักแก้ปัญหาที่ของเก่าเคยมี แต่ของใหม่ก็มักมาพร้อม “ปัญหาใหม่” ที่ยังไม่มีใครเจอหรือแก้มาก่อน — เอกสารไม่ครบ ชุมชนเล็ก เครื่องมือ debug ยังไม่โต และบางครั้งตัว library เองก็ยังไม่เสถียรพอสำหรับ production จริง
ขึ้นกับความเสี่ยงที่ application และองค์กรรับได้ อาจสมเหตุสมผลอย่างยิ่งที่จะ รอ ให้ library หรือ framework ใหม่พิสูจน์ตัวเองใน production ระยะหนึ่งก่อนนำมาใช้ — แนวคิดนี้สัมพันธ์กับ Pain Driven Development คือรับของใหม่เข้ามาก็ต่อเมื่อ “เจ็บปวด” กับข้อจำกัดของของเดิมจริง ๆ ไม่ใช่เพราะมันดูน่าตื่นเต้น
ทำไมถึงดูน่าใช้
หัวข้อที่มีชื่อว่า “ทำไมถึงดูน่าใช้”- สัญญาว่าจะเร็วกว่า ง่ายกว่า — บทความ, block, และ conference talk มักโปรโมตของใหม่ด้วย demo ที่สวยงามและเรียบง่ายเกินจริงเมื่อเทียบกับปัญหาจริงในระบบที่มีอยู่แล้ว
- ความอยากรู้อยากเห็นและความสนุกของผู้พัฒนา — โปรแกรม merge ำนวนมากรักของใหม่ เพราะมันท้าทายและน่าตื่นเต้นกว่าการดูแล code เดิม
- แรงกดดันด้านเรซูเม่ — งานวิจัยเชิงประจักษ์เรื่อง Résumé-Driven Development (RDD) พบว่า 82% ของนักพัฒนาเชื่อว่าการใช้เทคโนโลยีที่กำลังฮิตทำให้ตัวเองน่าจ้างมากขึ้น และ 60% ของผู้จ้างงานยอมรับว่าเทรนด์มีผลต่อการเปิดรับสมัครงาน แรงจูงใจนี้ผลักดันการเลือกเทคโนโลยีโดยไม่สัมพันธ์กับความต้องการทางเทคนิคจริง
- กลัวตกยุค (FOMO) — รู้สึกว่าถ้าไม่ใช้ของใหม่ ทีมหรือองค์กรจะล้าหลังคู่แข่ง
- สับสนระหว่าง “ใหม่” กับ “ดีกว่า” — ของใหม่แก้ปัญหาบางอย่างจริง แต่ก็มักแลกด้วยข้อเสียใหม่ที่ยังมองไม่เห็นในวันที่ตัดสินใจเลือก
ทำไมถึงเป็นปัญหา
หัวข้อที่มีชื่อว่า “ทำไมถึงเป็นปัญหา”- ความเสี่ยงด้าน production ที่ยังไม่ถูกพิสูจน์ — library ใหม่อาจมี breaking changes บ่อย, bug ที่ยังไม่ถูกเจอ, หรือช่องโหว่ด้านความปลอดภัยที่ยังไม่มีใคร patch
- ต้นทุนการเรียนรู้ซ้ำซ้อน — ทุกเครื่องมือใหม่หมายถึง learning curve ใหม่สำหรับทั้งทีม ซึ่งดึงเวลาออกจากการส่งมอบคุณค่าทางธุรกิจ
- หนี้ทางเทคนิคจากการทดลองที่ค้างอยู่ — “ลองดูก่อน” มักไม่เคย “ทำเสร็จจริง” กลายเป็น code ผสมสองสไตล์ที่ดูแลยากกว่าเดิม
- ระบบนิเวศและชุมชนที่ยังเล็ก — เมื่อเจอปัญหา อาจไม่มีคำตอบใน Stack Overflow, ไม่มี Stack Overflow เลย, หรือทีม maintainer มีคนเดียว
- ของใหม่กลายเป็น Golden Hammer ตัวใหม่ — เมื่อทีมตื่นเต้นกับเครื่องมือใหม่ มักเผลอเอามันไปใช้แก้ทุกปัญหา ไม่ว่าจะเหมาะสมหรือไม่ ซึ่งกลายเป็น Golden Hammer ในคราบของใหม่
- ขัดกับหลัก YAGNI — การนำเทคโนโลยีที่ซับซ้อนเข้ามาเพื่อ “เผื่ออนาคต” หรือเพราะมันดูล้ำ โดยไม่มีความจำเป็นตอนนี้ ก็คือการทำงานที่ยังไม่จำเป็นต้องทำ
ตัวอย่าง
หัวข้อที่มีชื่อว่า “ตัวอย่าง”ทีมมี background job ธรรมดาที่ทำงานได้ดีอยู่แล้วด้วย queue ในฐานข้อมูลที่มีอยู่ แต่มีคนได้ยินเรื่อง message broker ตัวใหม่ล่าสุดจาก conference แล้วอยากเปลี่ยนทันที โดยไม่มีปัญหาด้าน throughput หรือ scalability ที่ระบบเดิมแก้ไม่ได้:
// ก่อน: โซลูชันง่าย ๆ ที่ทำงานได้ดีอยู่แล้ว ไม่มีปัญหาด้าน throughputpublic class OrderJobQueue{ private readonly IDbConnection _db;
public OrderJobQueue(IDbConnection db) => _db = db;
public void Enqueue(OrderJob job) { _db.Execute( "INSERT INTO JobQueue (Payload, Status) VALUES (@Payload, 'Pending')", new { Payload = JsonSerializer.Serialize(job) }); }}// หลัง: เปลี่ยนไปใช้ message broker ใหม่ล่าสุดที่เพิ่ง 1.0 ได้ไม่ถึงเดือน// เพราะ "มันเจ๋ง" ไม่ใช่เพราะระบบเดิมมีปัญหาจริงpublic class OrderJobQueue{ private readonly BleedingEdgeBrokerClient _broker;
public OrderJobQueue(BleedingEdgeBrokerClient broker) => _broker = broker;
public async Task Enqueue(OrderJob job) { // API ยังเปลี่ยนบ่อย เอกสารตามไม่ทัน // ไม่มีใครในทีมมีประสบการณ์ debug broker ตัวนี้ตอนมันล่มกลางดึก await _broker.PublishAsync("orders.pending", job); }}ผลลัพธ์: ทีมต้องเรียนรู้ operational model ของ broker ใหม่ทั้งหมด (deployment, monitoring, retry semantics) แลกกับสิ่งที่ระบบเดิมทำได้อยู่แล้ว และเมื่อ broker version 1.1 ออกมาพร้อม breaking API change ทีมก็ต้องหยุดงาน feature เพื่อไล่แก้
flowchart TD
A[มีปัญหาทางธุรกิจ] --> B{ประเมินทางเลือก}
B --> C[เครื่องมือปัจจุบันแก้ได้จริงไหม]
C -->|ได้| D[ใช้เครื่องมือเดิม]
C -->|ไม่ได้ ระบุข้อจำกัดชัดเจน| E[ประเมินความเสี่ยงของของใหม่]
E --> F[ทดลองในสโคปเล็ก จำกัดความเสียหาย]
F --> G[พิสูจน์คุณค่าใน production จริงหรือยัง]
G -->|ยัง| H[รอ รอบสองค่อยตัดสินใจ]
G -->|พิสูจน์แล้ว| I[นำไปใช้อย่างมีแผนย้ายทีมทั้งหมด]
ทางแก้และการ refactor
หัวข้อที่มีชื่อว่า “ทางแก้และการ refactor”- ตั้งคำถามก่อนเสมอ: ปัญหาคืออะไร ไม่ใช่เครื่องมือคืออะไร — เริ่มจากข้อจำกัดของระบบปัจจุบันที่วัดผลได้จริง (เช่น latency, throughput, DX ที่แย่มากจนเสียเวลา) แล้วค่อยหาว่าเครื่องมือไหนแก้ปัญหานั้นได้ดีที่สุด
- ใช้ Pain Driven Development เป็นเกณฑ์รับของใหม่ — รับเทคโนโลยีใหม่เข้ามาต่อเมื่อทีมรู้สึก “เจ็บ” กับข้อจำกัดของเดิมจริง ๆ ไม่ใช่เพราะกลัวตกเทรนด์
- ใช้ model adopt/trial/assess/hold แบบ ThoughtWorks Technology Radar — แยกของใหม่ตามระดับความพร้อม: ของที่ “assess” หรือ “trial” เท่านั้นที่เอาไปทดลองในสโคปเล็กและแยกจาก production หลัก ส่วนของที่ “adopt” แล้วเท่านั้นที่ใช้กับงานสำคัญ
- ทดลองในพื้นที่จำกัดความเสียหายก่อน (spike/proof-of-concept) — เขียน code ทดลองแยกต่างหาก มี timebox ชัดเจน และเกณฑ์ตัดสินใจว่าจะ “ไปต่อ” หรือ “พอแค่นี้” ก่อนเอาเข้าระบบจริง
- ให้เวลา library พิสูจน์ตัวเองใน production ของคนอื่นก่อน — รอผ่าน version major แรก ๆ ให้ community ใหญ่พอที่จะมีคำตอบเมื่อเจอปัญหา
- แยกการตัดสินใจเทคโนโลยีออกจากอีโก้และเรซูเม่ส่วนตัว — ให้ทีมทั้งทีมมีส่วนร่วมตัดสินใจ ไม่ใช่คนเดียวผลักดันเพราะอยากเรียนรู้ของใหม่ (พึงระวัง Résumé-Driven Development)
// แนวทางที่ดีกว่า: ทดลองแบบมีขอบเขต วัดผลได้ ก่อนเปลี่ยนทั้งระบบpublic class OrderJobQueue{ private readonly IDbConnection _db; private readonly IFeatureFlags _flags; private readonly BleedingEdgeBrokerClient? _experimentalBroker;
public OrderJobQueue( IDbConnection db, IFeatureFlags flags, BleedingEdgeBrokerClient? experimentalBroker = null) { _db = db; _flags = flags; _experimentalBroker = experimentalBroker; }
public async Task Enqueue(OrderJob job) { // ทดลองใน flag แยก จำกัดสัดส่วน traffic วัดผลก่อนตัดสินใจย้ายทั้งระบบ if (_flags.IsEnabled("experimental-broker") && _experimentalBroker is not null) { await _experimentalBroker.PublishAsync("orders.pending", job); return; }
_db.Execute( "INSERT INTO JobQueue (Payload, Status) VALUES (@Payload, 'Pending')", new { Payload = JsonSerializer.Serialize(job) }); }}ที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “ที่เกี่ยวข้อง”- Pain Driven Development — หลักการรับของใหม่เมื่อเจ็บปวดจริงเท่านั้น คือทางแก้หลักของ Shiny Toy
- YAGNI — อย่าเพิ่มความซับซ้อนที่ยังไม่จำเป็นต้องใช้ตอนนี้
- Golden Hammer — เมื่อของเล่นใหม่กลายเป็นค้อนที่ใช้ตีทุกปัญหา
- Speculative Generality — กลิ่น code จากการออกแบบเผื่ออนาคตที่ไม่มีอยู่จริง
- Laws of Software Architecture — กรอบคิดเรื่อง trade-off ที่ช่วยประเมินการตัดสินใจเลือกเทคโนโลยี