ความผิดพลาดเพียงครั้งเดียวของ ChatGPT ทำให้สูญเสียรายได้กว่า 15 ล้านวอน
(asim.bearblog.dev)- สตาร์ทอัพที่เพิ่งเปิดใช้การสร้างรายได้ประสบปัญหาการชำระเงินค่าสมัครสมาชิก แต่ภายในทีมไม่สามารถจำลองปัญหาได้ ทำให้ การหาสาเหตุล่าช้าไป 5 วัน
- ปัญหาเริ่มจากการคัดลอกรูปแบบการแปลง Prisma/TypeScript→Python/SQLAlchemy ที่ ChatGPT สร้างขึ้นมา โดยมี สตริง ID ที่ฮาร์ดโค้ดไว้ ถูกใส่เหมือนเป็นค่าเริ่มต้น แทนที่จะเป็นฟังก์ชันสร้าง UUID
- ด้วยโครงสร้าง AWS ECS 8 tasks และแต่ละ task มี 5 instances ผู้ใช้จึงอาจไปเจอหนึ่งใน พูล ID ไม่ซ้ำกันสูงสุด 40 ชุด และในช่วงกลางวันปัญหาถูกกลบด้วยการ deploy บ่อยครั้ง
- ตอนกลางคืนเมื่อการ deploy หยุดลง ID เดียวของแต่ละ server ถูกใช้จนหมด และหลังจากนั้นความพยายามสมัครสมาชิกใหม่ล้มเหลวเพราะ unique ID collision
- จากการประเมินตามข้อร้องเรียนวันละ 50 รายการ เป็นเวลา 5 วัน และค่าสมัครสมาชิกเดือนละ $40 ความเสียหายอยู่ที่ $10,000 ต่อเดือน โดยการไม่มี test, logging, alert และการคัดลอก code ทำให้การรับมือ incident บานปลาย
ปัญหาการสมัครสมาชิกที่เผยออกมาทันทีหลังเปิดสร้างรายได้
- สตาร์ทอัพเปิดใช้ การสร้างรายได้ เป็นครั้งแรกในเดือนพฤษภาคม และได้ลูกค้ารายแรกภายใน 1 ชั่วโมงหลังเปิดตัว
- เช้าวันถัดมา ใน Gmail มีข้อร้องเรียนจากผู้ใช้สะสมมากกว่า 40 รายการ
- ผู้ใช้ไม่สามารถสมัครสมาชิกให้เสร็จสมบูรณ์ได้
- ผู้ใช้แจ้งว่าเมื่อกดปุ่มสมัครสมาชิก จะเห็น spinner โหลดไม่สิ้นสุด
- ทีมสร้างบัญชีใหม่เพื่อตรวจสอบเอง แต่ภายในทีมการสมัครสมาชิกทำงานปกติ จึงจำลองสาเหตุไม่ได้
- ในช่วงเวลาทำงานแทบไม่มีข้อร้องเรียน และปัญหามักสะสมขึ้นในช่วงกลางคืน
การทำระบบสร้างรายได้ภายใต้แรงกดดันด้านเวลา
- เดือนพฤษภาคมเป็นช่วงเริ่มต้นของ YC S23 batch และทีมยังไม่มั่นใจว่าหลังเปิดตัวแล้วทิศทางใดเหมาะสมที่สุด
- Dalton ซึ่งเป็น group partner ของ YC แนะนำให้ใช้ ผู้สมัครสมาชิกแบบจ่ายเงิน เป็นตัวชี้วัดสำหรับกำหนดทิศทาง และให้เพิ่มราคาต่อเดือนที่คิดไว้เป็นสองเท่า
- ราคาสุดท้ายถูกกำหนดไว้ที่ $40 ต่อเดือน
- เดิมโปรเจกต์เป็น full-stack NextJS แต่ในช่วงก่อนและหลังงานสร้างรายได้ ทีมกำลังย้ายไปใช้ Python/FastAPI
- ใช้ ChatGPT ในกระบวนการย้ายระบบ
- ทำ Stripe integration เสร็จแล้วด้วย
- หลังจากนั้นเป็นเวลา 5 วัน ทีมได้นอนน้อยลงมาก และต้องจัดการอีเมลร้องเรียนวันละ 30–50 ฉบับ
รูปแบบการแปลงโมเดลที่ ChatGPT สร้างขึ้น
- ในกระบวนการย้าย backend ทีมย้าย database model จาก Prisma/TypeScript ไปเป็น Python/SQLAlchemy
- การแปลงโมเดลเป็นงานน่าเบื่อ และเมื่อเห็นว่า ChatGPT ทำได้ดี จึงใช้กับการ migration แทบทั้งหมด
- code ที่สร้างขึ้นถูกคัดลอกและวาง จากนั้นตรวจสอบการทำงาน และใน production ก็ดูเหมือนปกติ จึงเดินหน้าต่อ
- ตอนนั้นการ insert ลง database ยังคงเป็นหน้าที่ของ Next API ส่วน Python backend แค่อ่าน database เท่านั้น
- เมื่อทำฟีเจอร์สมัครสมาชิก ทีมจึงเริ่ม insert DB record จาก Python เป็นครั้งแรก
- SQLAlchemy model ใหม่สร้างเอง แต่คัดลอกรูปแบบที่ ChatGPT สร้างไว้จาก model เดิมมาใช้เหมือนเดิม
- ปัญหาเดียวกันถูกใส่เข้าไปในวิธีสร้าง ID ของทุก model
สาเหตุจริงและทำไมกลางวันจึงมองไม่เห็น
- ข้อผิดพลาดหลักคือไม่ได้ส่ง ฟังก์ชันหรือ lambda สำหรับสร้าง UUID แต่ส่งสตริง ID เดียวที่ฮาร์ดโค้ดไว้
- เมื่อผู้ใช้คนหนึ่งสมัครสมาชิกสำเร็จด้วย ID นั้นบน backend instance ใด instance หนึ่ง ความพยายามสมัครสมาชิกครั้งต่อ ๆ ไปบน instance เดียวกันจะเกิด การชนกันของ ID ที่ต้องไม่ซ้ำ
- โครงสร้าง backend ทำให้ปัญหานี้ถูกซ่อนไว้นานขึ้น
- รัน ECS tasks 8 ตัวบน AWS
- แต่ละ task รัน backend instances 5 ตัว
- ผู้ใช้อาจไปถึงหนึ่งใน ID ที่แตกต่างกันได้ถึง 40 ค่า
- ตอนกลางวันมีการ commit ตรงเข้า main branch วันละ 10–20 ครั้ง และทุกครั้งจะเกิดการ deploy backend ใหม่
- ทุกครั้งที่มีการ deploy จะมี ID ใหม่ 40 ค่าให้ลูกค้าใช้งานได้
- ตอนกลางคืน เมื่อการ commit และ deploy หยุดลง ID เดียวของแต่ละ server ก็ถูกใช้หมดอย่างรวดเร็ว
- ช่วงแรกมี server ที่สมัครสมาชิกได้เกือบ 40 ตัว แต่เมื่อเวลาผ่านไปก็ลดลงจนเกือบเหลือ 0
ขนาดความเสียหายและการดำเนินการหลังจากนั้น
- ประเมินความเสียหายจาก
50 emails/day x 5 days x $40/monthเป็นรายได้ที่สูญเสีย $10,000 ต่อเดือน- การคำนวณนี้อิงเฉพาะผู้ใช้ที่ส่งข้อร้องเรียนมาเท่านั้น
- การหาสาเหตุต้องใช้เวลา 5 วัน อีเมลจำนวนมาก Sentry logs หลายร้อยรายการ การคุย Discord ยาวนานกับวิศวกร Stripe และการตรวจสอบไฟล์สำคัญ 5 ไฟล์
- หลังพบสาเหตุ Adam ก็ส่งแพตช์แก้ไขขึ้นอย่างรวดเร็ว
- หลังจากนั้นได้เพิ่ม unit/integration tests ที่เข้มงวด, alerts และ logging
- เหตุการณ์นี้แสดงให้เห็นว่า เมื่อความผิดพลาดของมนุษย์, test ที่ไม่เพียงพอ, การคัดลอก code และการ push ตรงเข้า main ซ้อนกัน แม้โค้ดเพียงบรรทัดเล็ก ๆ ก็อาจนำไปสู่การสูญเสียรายได้ครั้งใหญ่ได้
2 ความคิดเห็น
เอ๊ะ โค้ดที่ AI สร้างขึ้นมาแบบอัตโนมัติต้องรีวิวก่อนอยู่แล้วสิ ทำไมถึงเอาไปใช้ทั้งอย่างนั้นเลยล่ะ
ความคิดเห็นจาก Hacker News
สิ่งที่ทำให้เงิน 10,000 ดอลลาร์หายไปคือ การไม่มี monitoring แอปปล่อย exception จากฐานข้อมูลออกมาอย่างต่อเนื่องและเป็นจำนวนมาก แต่ไม่มีใครได้รับการแจ้งเตือน
ถ้ามีการแจ้งเตือนแบบนั้น เรื่องนี้คงจบด้วย การตรวจสอบ 5 นาที ไม่ใช่การตรวจสอบ 5 วัน ถ้ายังไม่ได้แก้ระบบแจ้งเตือน ก็เท่ากับว่ายังไม่ได้แก้อะไรจริง ๆ
ตอนทุกอย่างทำงานได้ดี การเขียนโปรแกรมก็ง่าย ส่วนที่ยากคือส่วนที่จัดการกับปัญหา
ตั้งแต่วินาทีที่มีลูกค้าจ่ายเงินเข้ามา ก็ต้องมีคนที่มีความรู้และประสบการณ์ในการจัดการ logging, monitoring, alerting, security ฯลฯ จะทำ DevOps แบบมือสมัครเล่นไม่ได้
แต่ส่วนที่บ้าจริง ๆ คือฐานข้อมูลไม่มี error logging และ alerting นี่ไม่ใช่โค้ด legacy อายุ 20 ปี แต่เป็นผลิตภัณฑ์ใหม่ และไม่ใช่โค้ดยุคที่ใช้ error ของ DB แทน data validation ด้วย
บทความในบล็อกขึ้น 404 เลยทิ้งลิงก์ Web Archive ไว้
https://web.archive.org/web/20240610032818/https://asim.bear...
ผู้เขียนได้เพิ่มการแก้ไขสำคัญไว้ว่า แนวปฏิบัติในเรื่องนี้แย่มากและน่าอายมาก และหลังจากนั้นได้เพิ่ม unit/integration test ที่แข็งแรง รวมถึง alerting/logging แล้ว สุดท้ายแล้วเป็นความผิดพลาดของมนุษย์ และเมื่อมองย้อนกลับไปก็เป็นเรื่องที่หลีกเลี่ยงได้อย่างชัดเจน
นอกจากนี้ยังเสริมว่า เรื่องนี้เกิดขึ้นในช่วงไม่กี่สัปดาห์แรกของบริษัท ภายใต้แรงกดดันด้านเวลาสูง และขอให้มองเป็นเรื่องขำ ๆ เกี่ยวกับบั๊กที่ทำซ้ำได้อย่างประหลาดใน production
แม้จะเป็นความผิดพลาดโง่ ๆ แต่มนุษย์ไม่ว่าจะเป็นรายบุคคลหรือเป็นกลุ่มก็ย่อมทำผิดพลาดโง่ ๆ ได้อยู่แล้ว
https://0912i390129ionkjan.bearblog.dev/how-a-single-chatgpt...
https://webcache.googleusercontent.com/search?q=cache%3Ahttp...
เห็นข้อผิดพลาดได้ทันที แม้จะเคารพทีมนี้ แต่เรื่องนี้แทบไม่เกี่ยวกับ ChatGPT และเกี่ยวข้องมากกว่ากับการที่ทีมใช้ โมเดลการเขียนโปรแกรม ที่ยังไม่คุ้นเคยพอ
ต่อให้ผ่าน code review มาแล้ว แค่มีเครื่องมือมอนิเตอร์ที่ตั้งค่าได้ภายใน 5 นาที ก็มีโอกาสสูงที่จะจับได้
หัวข้อแบบ “เราใช้ LLM แล้วเขียนโปรแกรมผิดพลาด และเพราะไม่ได้ทำ QA จึงเสียเงิน 10,000 ดอลลาร์” คงไม่ทำให้ผู้บริหารมีปฏิกิริยาแบบ “ถ้า ChatGPT ทำพัง เราจะเสีย exposure เท่าไร?” ได้ จะต้องมีผู้จัดการระดับกลางและระดับสูงจำนวนมากเอาบทความนี้ไปโพสต์บน LinkedIn แน่ ๆ
LLM ไม่สามารถ “ทำพลาด” ได้ มันไม่ deterministic และไม่สามารถอนุมาน คิด หรือทำตรรกะได้ มันเป็นเครื่องสร้าง word salad ที่หรูหรามากโดยใช้ความน่าจะเป็นเชิงสถิติ และไม่มีหลักประกันว่าสิ่งที่สร้างออกมาจะถูกต้องหรือแม่นยำ ดังนั้นตามนิยามแล้ว การเรียกว่าเป็นความผิดพลาดก็ไม่เหมาะ
แก้ไข: หลังจากบทความถูก downvote อย่างหนักด้วยเหตุผลที่ชัดเจน อันดับก็พุ่งขึ้นมาอย่างกะทันหัน ซึ่งดูเหมือนหมายความว่า moderator เป็นคน boost: https://hnrankings.info/40627558/
น่าขำที่บทความ clickbait ซึ่งตามกฎควรถูกเปลี่ยนหัวข้อ กลับถูก moderator boost แถมการที่ผู้เขียนดูเหมือนจะสังกัดบริษัทของ Y Combinator ก็คงเป็นเรื่องบังเอิญล้วน ๆ: https://news.ycombinator.com/item?id=40629998
การสร้าง UUID สำหรับ primary key ไม่ควรใช้
str(uuid.uuid4())แต่ควรใช้ callableuuid.uuid4โดยตรง และบอกว่า SQLAlchemy จะเรียกฟังก์ชันตอนสร้างค่า ส่วนค่า default ของวันที่server_default=text("(now())")อาจไม่ทำงานตามที่คาด จึงแนะนำให้ใช้func.now()และให้ตรวจสอบการ importuuidกับtextของ SQLAlchemy รวมถึงพิจารณาใช้DateTime(timezone=True)เพื่อจัดการ timezoneจากนั้นมันเสนอ code ที่แก้แล้วเป็น
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()), unique=True, nullable=False)ซึ่งการเพิ่มlambda:ตรงนี้เป็นสิ่งที่แก้ปัญหาuuid.uuid4()เป็นเหมือนการนิยาม schema ในเครื่องมืออย่าง Prisma ดังนั้นตัวบั๊กเองจึงไม่น่าแปลกใจ และผมก็อาจทำพลาดแบบเดียวกันได้แต่แค่รัน
kubectl logsครั้งเดียวก็น่าจะจับได้ทันทีแล้ว อีกอย่าง จาก Next.js กับ Prisma ไปใช้ Python เนี่ยนะ? ทำไม?ตัวความผิดพลาดเองพอเข้าใจได้ ต่อให้เขียนโค้ดโดยไม่ใช้ ChatGPT ก็ดูเหมือนจะพลาดหลุดไปได้ค่อนข้างง่าย
แต่ไม่เข้าใจว่าทำไมหลังจากล้มเหลวครั้งแรกแล้วยังจับไม่ได้ บริษัทนี้ไม่มี logging หรือ? ความจริงที่ว่า backend พยายาม reuse UUID ควรจะเห็นได้ทันทีจาก error
การเผลอส่ง string ให้ฟังก์ชันที่ต้องรับ callable object แทน
Stringเป็นเรื่องที่เกิดได้บ่อย ถ้าไม่ได้ใช้ ORM ปัญหาเฉพาะนี้คงถูกหลีกเลี่ยงได้ แต่นั่นอาจเป็นอคติส่วนตัวของผมต่อ ORM ก็ได้ บั๊กคล้าย ๆ กันเกิดในบริบทที่ไม่ใช่ฐานข้อมูลได้เต็มที่คนที่คุยโวว่าตัวเองจับบั๊กนี้ได้แน่นอน คงเป็นวิศวกรที่เก่งกว่าผมมาก หรือที่เป็นไปได้มากกว่าคืออาจเข้าใจความสามารถตัวเองผิดไปเล็กน้อย
อย่างไรก็ตาม การที่ ไม่มี log หรือไม่ได้ดู log นั้นเข้าใจยากจริง ๆ ถ้าเป็น ECS ผมคิดว่า exception แบบ Duplicate Key น่าจะถูกส่งต่อไป CloudWatch ได้โดยไม่ต้องตั้งค่าเพิ่มเติม เลยสงสัยว่าไม่ได้ถูกส่งไป หรือถูกส่งไปแล้วแต่ไม่มีใครตรวจดูว่าเกิด exception อะไรขึ้นตลอดทั้งคืนกันแน่
ในสถานการณ์แบบนี้ การถามว่าทำไมการตรวจพบจึงล่าช้า และทำไมการวินิจฉัยจึงใช้เวลานาน เป็นเรื่องที่มีประโยชน์
ผมเคยเห็นความผิดพลาดแบบเดียวกันหลายครั้งแม้ในโค้ดที่มนุษย์เขียน โดยเฉพาะใน React / TypeScript / JavaScript มักมีคนลืม lambda อยู่บ่อย ๆ
บทความในบล็อกดูเหมือนไม่ได้อธิบายสาเหตุรากของปัญหาให้ชัด แล้วก็โยนไปว่าเป็นความผิดของ ChatGPT ทันที ถ้าทำงานรีบ ๆ แล้วเอาคอมมิตที่เป็นการเปลี่ยนแปลงใหญ่หรือไม่มีเพื่อนร่วมงานรีวิวเข้า main เรื่องแบบนี้ก็เกิดขึ้นได้
ปัญหาจริง ๆ คือถ้าเร่งรีบ เลือกทางลัด และไม่มีการทดสอบกับการรีวิวโค้ดโดยเพื่อนร่วมงานอย่างเพียงพอ ก็จะเกิดข้อผิดพลาด แค่มีเทสต์ที่ลองตัวเลือกการสมัครหลาย ๆ แบบก็น่าจะเจอได้ทันทีแล้ว
ถ้าเอาคนแบบนี้ไปไว้ใกล้โค้ดที่สำคัญทางการเงิน ก็จะเกิดปัญหาคล้าย ๆ กัน และทำให้ผมสงสัยวิจารณญาณของคนที่ตัดสินใจ deploy โค้ดนั้นโดยแทบไม่มีการทดสอบ
น่าแปลกที่ไม่มี lint rule สำหรับกรณีนี้
หวังว่าจะไม่ใช่แบบนั้น
ส่วนที่ว่า “เดิมทีโปรเจกต์เป็น full-stack NextJS แต่ก่อนอื่นอยาก migrate ทุกอย่างไปเป็น Python/FastAPI” ทำให้ตาสว่างเลย
ไม่รู้ว่าสตาร์ทอัพที่ยังไม่มีลูกค้าจะ justify การ เขียนใหม่ ได้อย่างไร
ไม่ว่าจะมีลูกค้าหรือไม่ ผมก็ไม่เข้าใจว่าทำไมถึงย้ายในแนวราบจาก Node ไป Python ตั้งแต่ช่วงต้นขนาดนี้ ถ้ามีลูกค้าหลายร้อยคนแล้วกำลังจะเปลี่ยนไปใช้ Go อะไรแบบนั้นยังพอเข้าใจได้บ้าง แต่ก็ยังน่าสงสัยอยู่ดี
เช่น ต้องสร้าง DTO object เป็นกอง แต่ AutoMapper ไม่ทำงานกับชุดเวอร์ชันและการตั้งค่าโปรเจกต์ที่ผมใช้ ส่วน Entity Framework กับการ serialize/deserialize JSON ก็สร้างความเจ็บปวดมากกว่าประโยชน์ที่ได้
แน่นอนว่าสามารถแก้แบบค่อยเป็นค่อยไปได้ ขุดเอกสารให้ลึก ผสม hack อัปเกรดแพ็กเกจ และเขียน config ใหม่ก็ทำได้ แต่ถ้าเป็นมนุษย์ก็จะอยากถือถังน้ำมันในเชิงเปรียบเทียบแล้วเผาทิ้งทั้งหมด จากนั้นทำระบบที่สองให้ดีกว่าเดิม แน่นอนว่าในความเป็นจริงมันไม่ได้ดีขึ้น แค่มีจุดเจ็บปวดแบบอื่นเกิดขึ้น และอาจทำสิ่งที่ระบบแรกเคยทำได้ไม่ครบหรือทำได้ไม่ดีด้วยซ้ำ
ที่ทำงานก็เหมือนกัน ทุกครั้งที่เห็นระบบ legacy หรือระบบยุ่งยาก สมองจะมีแรงกระตุ้นแบบเดียวกัน ต้องใช้ความพยายามอย่างจริงจังและต่อเนื่องถึงจะเอาชนะสมองที่ตะโกนว่าให้เขียนใหม่ได้ บางครั้งการเปลี่ยนสถาปัตยกรรมอย่างการเขียนใหม่หรือการนำ container มาใช้ก็ออกมาดี แต่โดยมากแล้วมักเป็นการเดินเข้ากองไฟหรือกลายเป็นงานที่ไม่รู้จบ
เว้นแต่จะมั่นใจสูงว่าจะช่วยปรับปรุงการปฏิบัติการของระบบหรือ developer experience ของนักพัฒนาคนอื่น ๆ ได้ การไม่ยอมแพ้ต่อแรงกระตุ้นนั้นถือว่าโชคดีแล้ว
ChatGPT น่าจะเป็นฝ่ายที่ทำให้แอปทำเงินได้ด้วยซ้ำ เพราะถ้าไม่มี ChatGPT ก็คงไม่มีความสามารถพอจะ implement
การขาดความสามารถด้านการเขียนโค้ด ดีบัก logging และ monitoring ต่างหากที่ทำให้เสียเงิน 10,000 ดอลลาร์ และในเรื่องนี้ผลสุทธิของ ChatGPT เป็นบวก
ทุก commit message มีอีโมจิ ลิง กล้วย จรวด พลุ มีครบแทบทุกอย่าง
https://grook.ai/share?id=e269e88a7b1a71eff4f176c864b30161&x...
เขาบอกว่าเดิมทีเป็น full-stack NextJS และระหว่าง migrate backend ไปเป็น Python/FastAPI ก็แปล database model ของ Prisma/Typescript ไปเป็น Python/SQLAlchemy งานนี้น่าเบื่อ จึงเห็นว่า ChatGPT ทำได้ค่อนข้างดีและใช้กับการ migrate เกือบทั้งหมด
ถ้าไม่มี ChatGPT ตั้งแต่แรกก็คงไม่พยายามทำการ migrate ล่วงหน้านี้ ดังนั้นจะมองว่าผลสุทธิเป็นบวกก็ยาก สแตกเดิมอาจมี error logging ที่ดีกว่าก็ได้ หรืออาจไม่มีก็ได้ และเพราะเป็นโค้ดที่เขียนเองจึงอาจเข้าใจโครงสร้างดีกว่าและต้องการมันน้อยกว่าก็ได้
การตัดสินใจ “เขียนโค้ดทั้งหมดใหม่เป็นครั้งที่สอง” ก่อนเปิด monetization ก็น่าสนใจอยู่เหมือนกัน
มีข้อความว่า “ก่อนอื่นผมอยากบอกว่าขั้นตอนปฏิบัติที่นี่แย่และสามารถหลีกเลี่ยงได้ เรื่องนี้เกิดขึ้นในช่วงเวลาอื่นที่มีแรงกดดันด้านเวลาสูง โปรดอ่านโดยคำนึงถึงจุดนี้”
ข้อจำกัด แบบนี้ทำให้ซอฟต์แวร์แบบ subscription น่ากลัว
เคยมีกรณีที่เรียกเก็บเงินผู้ใช้สองครั้งเพราะ race condition ด้วย ดังนั้นพอเห็น timeout หรือ error ที่เกี่ยวกับเงิน ผมจะระแวงถึงขั้นสันนิษฐานไว้ก่อนว่ามีการชำระเงินแล้ว แล้วค่อยกลับไปตรวจสอบภายหลัง
โค้ดที่เขียนด้วย TypeScript กับ Python, เฟรมเวิร์กอย่าง Next.js, รันงาน AWS 8 งานโดยแต่ละงานมี 5 อินสแตนซ์ แต่รายได้มีแค่ 40 ดอลลาร์ และเวลาในการพัฒนาแค่ไม่กี่สัปดาห์น่ะหรือ?
นี่มันเกิดอะไรขึ้นกันแน่ พอแก้ตัวว่าโค้ดเละเพราะข้อจำกัดด้านเวลา แต่กลับเอาเวลาไปใช้กับการรีแฟกเตอร์ข้ามภาษาและสร้างระบบกระจายตัวโดยไม่มีเหตุผล อันนี้ยิ่งแย่กว่า
เป็น ความซับซ้อนแบบทำร้ายตัวเอง ที่ต้องเล่นกลทั้งฟีเจอร์และความซับซ้อนทางเทคนิคที่ไร้สาระไปพร้อมกัน ไม่รู้ว่าคิดอะไรอยู่
แก้ไข: เป็นบริษัท YC ฤดูร้อนปี 2023 แต่ถึงฤดูร้อนปี 2024 ผลิตภัณฑ์ก็ดูเหมือนยังอยู่หลังกำแพงรายชื่อรอใช้งานอยู่ อาจเป็นเพราะกำลังเขียนใหม่ด้วย Rust อยู่ก็ได้
ดูเหมือนเขาน่าจะยังไม่เคยเขียน Python รวมกันถึง 1,000 บรรทัดด้วยซ้ำ แต่กลับชี้ปัญหาได้ถูกต้อง
Python มีข้อบกพร่องตรงที่ลอกกลยุทธ์การประเมินค่าของ Common Lisp มาได้ไม่ถูกต้อง ถ้ามีอาร์กิวเมนต์อย่าง
foo=obj.whatever()ใน expression ค่าเริ่มต้นของอาร์กิวเมนต์ฟังก์ชันแบบเลือกได้obj.whatever()จะถูกประเมินตอนที่นิยามฟังก์ชันถูกประมวลผล ไม่ใช่ตอนเรียกฟังก์ชันผมสงสัยว่าตั้งใจทำแบบนั้นเพื่อประสิทธิภาพ Python ยังมีข้อบกพร่องอีกอย่างคือไม่มีไวยากรณ์ literal จริง ๆ สำหรับอ็อบเจ็กต์ที่ใช้บ่อยอย่าง list
[1, 2, 3]ไม่ใช่ literal แต่ใกล้เคียงกับ constructor มากกว่า และทุกครั้งที่ถูกประเมินก็ต้องสร้าง list ใหม่แล้วเติมค่าลงไปผู้ออกแบบคงไม่อยากให้พารามิเตอร์อย่าง
list=[]สร้าง list ว่างใหม่ทุกครั้งที่อาร์กิวเมนต์ถูกละไว้ ใน Lisp'(1 2 3)และ'()เป็น literal จริง ๆ และทุกครั้งที่ถูกอ้างถึงก็ชี้ไปยังอ็อบเจ็กต์เดียวกัน โปรแกรมเมอร์เลือกได้ว่าจะใช้(list 1 2 3)หรือ'(1 2 3)เป็น expression ค่าเริ่มต้นแบบแรกจะสร้างอ็อบเจ็กต์ใหม่ที่แก้ไขได้ทุกครั้งเหมือน
[1, 2, 3]ส่วนแบบหลังแทบจะแน่นอนว่าจะคืนอ็อบเจ็กต์เดิม และไม่สามารถแก้ไขได้อย่างน่าเชื่อถือและพกพาได้ ภาษาได้รับความนิยมยุคใหม่มีฟีเจอร์ส่วนใหญ่ของ Lisp กันหมดแล้ว จึงดูเหมือนมุกตลกที่ว่าไม่มีอะไรให้เสียfoo=obj.whatever()นั้นobj.whatever()ถูกประเมินตอนประมวลผลนิยามฟังก์ชัน ไม่ใช่ตอนเรียกฟังก์ชัน ดูไม่น่าจะถูกได้เลยถ้า
.whatever()พึ่งพาสถานะภายในที่เปลี่ยนไปหลังจากการเริ่มต้นอ็อบเจ็กต์ แล้วมันจะเป็นอย่างไรล่ะ