ข้ามไปยังเนื้อหา

Micro-Frontends คืออะไร?

แนวคิด micro-frontend ยืมมาจาก micro-services โดยตรง micro-service แยก backend ออกเพื่อให้ ทีมหนึ่งเป็นเจ้าของหนึ่ง service ตั้งแต่ต้นจนจบ — โค้ดของตัวเอง, ฐานข้อมูลของตัวเอง, deploy pipeline ของตัวเอง micro-frontend ทำแบบเดียวกันกับ UI: ทีมหนึ่งเป็นเจ้าของ vertical slice ของผลิตภัณฑ์ ตั้งแต่ pixel ที่เรนเดอร์ออกมาลงไปจนถึง API ที่ป้อนข้อมูลให้

คำสำคัญคือ vertical การแยกแบบ horizontal (ทีมหนึ่งทำ “CSS ทั้งหมด” อีกทีมทำ “การ fetch ข้อมูลทั้งหมด”) ยังคงบังคับให้ทุกคนต้องผ่าน release เดียวกัน ส่วนการแยกแบบ vertical ให้ฟีเจอร์ที่เบ็ดเสร็จในตัวเองแก่ทีม — เช่น Checkout — ที่ทีมสามารถ build, test และ ship ได้โดยไม่ต้องรอใคร

สิ่งที่ทำให้ MFE เป็น MFE จริงๆ มากกว่าจะเป็นแค่ folder หนึ่งใน monorepo คือ การ build และ deploy ที่เป็นอิสระ แต่ละ slice ผลิต artifact ของตัวเองและขึ้น production ตามตารางเวลาของตัวเอง shell โหลด slice แต่ละชิ้นในเวอร์ชันที่กำลัง live อยู่ในขณะนั้น

flowchart LR
  subgraph CatalogTeam["Catalog team"]
    CR["Repo"] --> CB["Build"] --> CD["Deploy v3.2"]
  end
  subgraph CartTeam["Cart team"]
    KR["Repo"] --> KB["Build"] --> KD["Deploy v1.9"]
  end
  CD --> Shell["Astro shell"]
  KD --> Shell
  Shell --> User["User's page"]
แต่ละทีม build และ deploy slice ของตัวเองตามจังหวะของตัวเอง

สังเกตว่า shell ดึง เวอร์ชันใดก็ตามที่กำลัง live เข้ามา — Catalog ship ได้ห้าครั้งต่อวัน ส่วน Cart ship สัปดาห์ละครั้ง และไม่มีฝ่ายไหน block อีกฝ่าย

มีสองช่วงเวลาที่แตกต่างกันโดยพื้นฐานซึ่ง slice สามารถถูกนำมารวมกันได้:

  • Build-time integration: slice ถูกเผยแพร่เป็น versioned packages (เช่น ไปยัง private npm registry) และ shell import เข้ามา การประกอบเกิดขึ้นตอนที่ shell build คุณจะได้ type safety และ bundle เดียวที่ถูก optimize แล้ว แต่การเปลี่ยนแปลงของทีมจะไปถึงผู้ใช้ก็ต่อเมื่อ shell rebuild และ redeploy เท่านั้น
  • Run-time integration: slice ถูก deploy เป็น artifact ที่รันแยกกัน (สคริปต์, remote HTML fragment, federated module, iframe) shell ดึง artifact เหล่านั้นเข้ามาเมื่อหน้าเพจถูกร้องขอหรือเรนเดอร์ใน browser ทีมต่างๆ ship อย่างเป็นอิสระอย่างแท้จริง โดยแลกมาด้วยส่วนประกอบที่ขยับเคลื่อนไหวมากขึ้นและการรับประกัน ณ เวลา compile ที่อ่อนแอลง

บทเรียนถัดไปจะลงลึกทั้งสองแบบ สำหรับตอนนี้ ภาพในใจคือ: build-time แลกความเป็นอิสระเพื่อความปลอดภัย ส่วน run-time แลกความปลอดภัยเพื่อความเป็นอิสระ

micro-frontends เป็นวิธีแก้แบบ เชิงองค์กร สำหรับปัญหา เชิงองค์กร — คนมากเกินไปแย่งกันทำ frontend ตัวเดียว หากคุณไม่มีปัญหานั้น คุณส่วนใหญ่จะรับเอาแต่ต้นทุนมาโดยไม่ได้ประโยชน์

ข้าม MFE ไปเมื่อ:

  • คุณเป็น ทีมเล็ก (วิศวกรไม่กี่คน) modular monolith สร้างได้เร็วกว่าและรันได้ถูกกว่ามาก
  • slice ของคุณ coupling กันแน่น และแชร์ state กันมาก — แอปแชต, design canvas, form wizard ที่ซับซ้อน รอยต่อต่างๆ ก่อความเจ็บปวดมากกว่าคุณค่าของความเป็นอิสระที่ได้รับ
  • ประสิทธิภาพคือสิ่งสำคัญที่สุดและ budget เล็กมาก หลาย framework และ dependency ที่ซ้ำซ้อนสามารถลบล้างผลที่ได้ เว้นแต่คุณจะเข้มงวด (islands ของ Astro ช่วยได้มากตรงนี้ แต่ก็ไม่ใช่เวทมนตร์)

เลือกใช้ MFE เมื่อหลายทีมจำเป็นต้อง ship ไปยังพื้นผิวเดียวกันอย่างเป็นอิสระ — แล้วปล่อยให้ Astro ทำให้หน้าเพจที่ได้ออกมายังเร็วอยู่

'vertical slice' ที่ทีม MFE เป็นเจ้าของหมายถึง:
อะไรที่ทำให้ run-time integration ต่างจาก build-time integration?
สถานการณ์ใดเป็นเหตุผลที่อ่อนที่สุดในการนำ micro-frontends มาใช้?