นักพัฒนา Back Endคำตอบสัมภาษณ์
คำถามสัมภาษณ์ทั่วไป
ผม/ฉันปฏิบัติตามหลักการ REST: ให้ทรัพยากรเป็นคำนาม (ไม่ใช่คำกริยา), URI มีลำดับชั้นและแสดงความสัมพันธ์ของทรัพยากร, ใช้ HTTP methods อย่างมีความหมาย (GET อ่าน, POST สร้าง, PUT/PATCH อัปเดต, DELETE ลบ). ผม/ฉันเวอร์ชัน API ตั้งแต่เริ่มต้น (/v1/) เพื่อให้สามารถพัฒนาแบบไม่ทำให้เกิดการแตกหักได้ง่ายขึ้น. ออกแบบรูปแบบการตอบกลับ, รหัสข้อผิดพลาด และรูปแบบการแบ่งหน้าให้ สอดคล้องกัน. จดเอกสารด้วย OpenAPI/Swagger. ผม/ฉันคำนึงถึงความต้องการของฝั่งไคลเอ็นต์ระหว่างการออกแบบ — API ที่ถูกต้องทางเทคนิคแต่ใช้งานยากคือ API ที่แย่. นอกจากนี้ยังพิจารณา rate limiting, การพิสูจน์ตัวตน และการตรวจสอบค่าป้อนเข้าจากผู้ใช้เป็นเรื่องสำคัญระดับแรกด้วย.
ผม/ฉันออกแบบสคีมาจากรูปแบบการเข้าถึงข้อมูล — ทำ normalization เป็นค่าเริ่มต้น และทำ denormalization เมื่อประสิทธิภาพการคิวรีต้องการ. ใช้ดัชนี (indexes) อย่างมีกลยุทธ์: ทุกคิวรีที่ช้าได้รับแผน explain และเพิ่มดัชนีตาม selectivity และความถี่ของคิวรี. หลีกเลี่ยงปัญหา N+1 โดยออกแบบการ eager loading ในชั้นข้อมูล. เขียน migrations อย่างระมัดระวัง — เปลี่ยนแปลงที่เข้ากันได้ย้อนหลังเมื่อเป็นไปได้ และใช้กลยุทธ์ blue-green deployment สำหรับการเปลี่ยนแปลงสคีมาที่แตกหัก. ผม/ฉันออกแบบเพื่อความสมบูรณ์ของข้อมูลด้วย: คอนสเตรนต์ของ foreign key, not-null และ check constraints เพื่อบังคับความสอดคล้องที่ระดับฐานข้อมูล.
ผม/ฉันออกแบบบริการแบบ stateless ตั้งแต่ต้น — สถานะจะอยู่ในฐานข้อมูลหรือแคช ไม่ใช่ในหน่วยความจำของแอปพลิเคชัน. ใช้การประมวลผลแบบอะซิงค์ (message queues: RabbitMQ, Kafka, SQS) สำหรับงานที่ไม่จำเป็นต้อง synchronous. แคชอย่างก้าวร้าวในเลเยอร์ที่เหมาะสม: ผลลัพธ์คิวรีฐานข้อมูล (Redis), การคำนวณสรุป, และทรัพยากรที่เป็นสแตติก. ออกแบบ API ให้สามารถขยายในแนวนอนได้ง่ายและชอบใช้บริการที่จัดการให้ (managed services เช่น RDS, ElasticCache) ที่สามารถสเกลได้แยกกัน. ผม/ฉันยังออกแบบด้วยการจัดการ rate limiting และ backpressure — บริการต้องสามารถลดระดับการให้บริการได้อย่างสุภาพเมื่อมีโหลดสูง.
การพิสูจน์ตัวตน: ใช้ OAuth 2.0 / OIDC สำหรับการพิสูจน์ตัวตนของผู้ใช้, API keys หรือ JWT สำหรับการสื่อสารระหว่างบริการ. ตรวจสอบและทำความสะอาดค่าป้อนเข้าทุกอย่าง — ไม่มีการประกอบ SQL โดยตรงจาก input ของผู้ใช้. นำ rate limiting และ throttling มาใช้เพื่อป้องกันการละเมิด. ใช้ HTTPS/TLS ทุกที่และบังคับการตรวจสอบใบรับรอง. ใช้หลัก least-privilege: แต่ละบริการและผู้ใช้มีสิทธิ์ขั้นต่ำที่จำเป็น. ตรวจสอบการใช้งานสิทธิ์ (audit) อยู่เสมอ. สแกน dependencies หาช่องโหว่ (OWASP Dependency-Check, Snyk) ใน CI. และบันทึกเหตุการณ์ด้านความปลอดภัย — การพิสูจน์ตัวตนล้มเหลว, การยกระดับสิทธิ์ — ไว้รวมศูนย์เพื่อตรวจสอบ.
ผม/ฉันยึดหลักว่าข้อผิดพลาดควรถูกบันทึก, จัดประเภท, และส่งกลับอย่างมีความหมาย. ใช้ structured logging (JSON) ใ นระดับ log ที่เหมาะสมเพื่อให้สามารถค้นหาจากล็อกได้. ใช้ distributed tracing (OpenTelemetry) เพื่อสามารถติดตามคำขอข้ามบริการได้. กำหนดรหัสข้อผิดพลาดให้สอดคล้องกันทั่วทั้ง API และจดไว้ในเอกสาร. ตั้งการแจ้งเตือนเมื่ออัตราข้อผิดพลาดผิดปกติ ไม่ใช่แค่เมตริกเชิงเทคนิคอย่าง CPU. ในสถาปัตยกรรมไมโครเซอร์วิส ผม/ฉันนำ circuit breakers (Resilience4j, Hystrix) มาใช้เพื่อป้องกันการล้มเหลวแบบลุกลามเมื่อ dependency เสียหายหรือเสื่อมสภาพ.
ผม/ฉันได้สร้างและดูแลทั้งสองแบบมาแล้ว. โมโนลิทถูกประเมินค่าต่ำเกินไป: มันง่ายกว่าในการพัฒนา, ทดสอบ, และดีพลอย และทีมส่วนใหญ่ไม่จำเป็นต้องใช้ไมโครเซอร์วิสจนกว่าจะถึงข้อจำกัดด้านการสเกลหรือการประสานงานทีม. เมื่อผม/ฉันย้ายไปใช้ไมโครเซอร์วิส ผม/ฉันใช้แนวทาง Strangler Fig — แยกบริการออกมาเป็นขั้นตอนจากโมโนลิทที่ใช้งานได้ แทนที่จะทำ decomposition แบบ big-bang. ไมโครเซอร์วิสนำความซับซ้อนในการปฏิบัติการมาอย่างมาก (service discovery, distributed tracing, โหมดความล้มเหลวของเครือข่าย, ความสอดคล้องของข้อมูลข้ามบริการ) — ผม/ฉันยอมรับความซับซ้อนนั้นเมื่อประโยชน์ชัดเจนว่ามากกว่าต้นทุน.
ผม/ฉันเขียน unit tests สำหรับโลจิกของธุรกิจแบบแยกส่วน (mock ฐานข้อมูลและ dependency ภายนอก). เขียน integration tests ที่ตรวจสอบบริการกับฐานข้อมูลจริง (สำหรับการทดสอบ) — เทสต์เหล่านี้ทดสอบรอบ request-response เต็มรูปแบบและจับข้อผิดพลาด SQL, ปัญหาประสิทธิภาพคิวรี, และปัญหาการแม็ปข้อมูลที่ unit tests อาจพลาด. ใช้ contract testing (Pact) เมื่อบริการมี API ที่เผยแพร่และถูกใช้งานโดยทีมอื่น. ผม/ฉันยังเขียน load tests (k6, Locust) สำหรับ endpoints ที่ต้องการประสิทธิภา พสูง. ความครอบคลุมของการทดสอบมีความหมายต่อเมื่อเทสต์เหล่านั้นสามารถจับความล้มเหลวจริงได้.
ผม/ฉันออกแบบระบบขับเคลื่อนด้วยเหตุการณ์โดยใช้ RabbitMQ และ Apache Kafka. เข้าใจการทดสอบสลับกันของ trade-offs: at-least-once vs exactly-once delivery, รูปแบบ consumer group, dead letter queues, และการรับประกันลำดับของข้อความ. ออกแบบสคีมาเมสเสจอย่างระมัดระวัง — การวิวัฒนาการของสคีมาที่เข้ากันได้ย้อนหลังเป็นสิ่งจำเป็นในผลิตภัณฑ์. ทำให้ consumer เป็น idempotent เพื่อให้ข้อความซ้ำไม่ทำให้ข้อมูลเสียหาย. ตรวจสอบ queue depth และ consumer lag เป็นเมตริกปฏิบัติการหลัก. สถาปัตยกรรมขับเคลื่อนด้วยเหตุการณ์ช่วยให้สเกลและการแยกส่วนดีขึ้นมาก แต่ต้องการการจัดการสคีมาและการจัดการความล้มเหลวอย่างมีวินัย.
พร้อมที่จะสร้างของคุณเองหรือยัง?
อัปโหลด CV และรายละเอียดงานเพื่อสร้างเวอร์ชันที่ปรับแต่งภายใน 60 วินาที
รับคำตอบการสัมภาษณ์ที่ปรับให้เป็นส่วนตัวสำหรับใบสมัครงานของคุณ
อัปโหลดประวัติย่อ (CV) และ/หรือ คำอธิบายตำแหน่งงาน