ทักทาย
สวัสดีครับ หลังจากที่ห่างหายจากหัวข้อนี้ไปนาน วันนี้ได้โอกาสมาเขียนเรื่องนี้ต่อแล้ว โดยจะยังเป็นเรื่องเกี่ยวกับการทำ Application Lifecycle Management ที่ดี ที่ถูกต้องของ Power Platform กันต่อ หลังจากที่ในพาร์ทที่แล้วเรารู้จักกับคอนเซปหลักๆไปแล้ว
โดยถ้าคุณยังไม่เคยอ่านบทความแรก สามารถกดอ่านก่อนได้ครับ >> กดอ่านพาร์ทแรก
หัวข้อ
ในพาร์นี้เราจะมาพูดถึงหัวข้อดังนี้ครับ
- Dependencies
- Solution Layers
- Managed Properties
- Patch Solution
- Clone solution
Dependencies
Dependencies แปลตรงตัวก็คือ “การพึ่งพาอาศัย” ซึ่งความหมายค่อนข้างตรงตามชื่อ มันคือความเชื่อมโยงของ Object ต่างๆใน Solution ของเรา
เช่น ผมมี Power Apps อยู่ 1 ตัว และในแอปนั้นผมใช้ Dataverse table เป็นฐานข้อมูล และตัวแอปก็ยังเชื่อมกับ Flow ของ Power Automate อีกด้วย


ซึ่งหมายความว่าตัว Power Apps นั้นพึ่งพา/ผูกกับ Table และ Flow นี้อยู่นั่นเอง ซึ่งเมื่อเป็นแบบนี้ หมายความว่าเราจะไม่สามารถลบ Table และ Flow นี้ได้ตราบใดที่เราไม่นำออกจากแอปเสียก่อน เรียกได้ว่าเป็นการป้องกันการที่เราเผลอไปลบแล้วทำระบบที่เราออกแบบมาพังนั่นเอง


วิธีการตรวจสอบ Dependencies
ซึ่งเราก็สามารถดูได้ง่ายๆว่า object แต่ละอย่างนั้นมี Dependencies อะไรบ้าง โดยการ
- คลิกที่ปุ่ม … ที่ object ที่ต้องการ
- คลิกที่ Advanced
- คลิกที่ Show dependencies

ระบบจะโชว์หน้าจอ Dependencies ขึ้นมาให้เราเห็น ซึ่งจะมีอยู่ทั้งหมด 3 แท็ปดังนี้
- Delete blocked by – แสดงให้เห็นว่าเราไม่สามารถลบ object นี้ได้ เพราะถูก object ใดใช้งานอยู่ ตัวอย่างในภาพ ระบบกำลังบอกว่าผมไม่สามารถลบ Flow นี้ได้ เพราะถูกใช้งานโดย Power Apps ตัวนึงอยู่

- Used by – แสดงให้เราเห็นว่า object นี้ ถูกใช้งานโดย object ใดอยู่บ้าง (ซึ่งส่วนใหญ่ก็จะเห็นคล้ายๆกับแท็ป Delete blocked by

- Uses – แสดงให้เราเห็นว่า object นี้มีการใช้งาน object ใดอยู่บ้าง ตัวอย่างในภาพ ระบบกำลังบอกว่า Power Apps ตัวนี้ มีการใช้งาน ทั้งตัว Flow และตัว Table อยู่

ซึ่งการดู Dependencies จะช่วยให้เราเห็นความเชื่อมโยงของ object แต่ละตัว อีกทั้งกรณีเราต้องการลบอะไรซักอย่างแต่ไม่สามารถลบได้ ก็สามารถใช้การดู Dependencies นี้เข้ามาช่วยได้
Solution Layers
Solution Layer แปลตรงตัวคือ “ชั้นของ Solution” ซึ่งก็….ตรงความหมายนะ แต่อาจจะไม่เห็นภาพเท่าไร ผมขอยกตัวอย่างละกัน น่าจะเห็นภาพกว่าอธิบายเชิงทฤษฎี
วิธีการดู Solution Layer
- คลิกที่ปุ่ม … ที่ object ที่ต้องการ
- คลิกที่ Advanced
- คลิกที่ See solution layers

ระบบก็จะแสดง layer ของ object นี้ให้เห็น ซึ่งถ้าเป็น object ที่อยู่ใน unmanaged solution ก็จะมี layer เดียวคือ unmanaged layer

แต่ถ้าเราไปดูที่ managed solution ที่เราได้ deploy ไปที่ environment ปลายทางแล้ว เราถึงจะเริ่มเห็นความแตกต่าง
ด้านล่างนี้คือ layer ของ Power Apps ที่ environment ปลายทาง ซึ่งในตอนนี้ก็ยังมีอยู่ layer เดียว ซึ่งถูกต้องแล้วครับ ถ้า solution ถูก deploy มาตามปกติ และไม่มีการผูกกับ solution อื่น ตัว object ด้านในก็จะมี layer เดียว

ทีนี้ ผมจะลองกดเข้าแก้ไขแอปตัวนี้ ซึ่งเป็นแอปที่อยู่ใน managed solution ผมจะเข้าไปแก้อะไรซักอย่างนึง

ทีนี้หลังจาก edit แอปเสร็จ กลับมาดู layer อีกทีนึง จะเห็นว่าตอนนี้มีอีก layer มาซ้อนด้านบนแล้วเรียกว่า Unmanaged layer ซึ่งจะเกิดขึ้นก็ต่อเมื่อมีการแก้ไข object ที่อยู่ใน managed solution เท่านั้น

ซึ่งในตอนนี้ ตัวแอปที่ End User เห็นและเข้าใช้งาน ก็จะเป็นแอปที่ถูกแก้ไขแล้ว (Layer บนสุด)
และพอเป็นแบบนี้แล้ว ต่อให้เราจะกลับไปแก้แอปที่ environment ต้นทาง และ import solution มาใหม่ยังไง end user ก็จะไม่เห็นความเปลี่ยนแปลงนั้นเลย เพราะถูก unmanaged layer ทับอยู่นั่นเอง
อ่านมาถึงตรงนี้ คุณไม่อยากให้เกิด unmanaged layer ใช่ไหม? ถ้าใช่ อ่านหัวข้อถัดไป (หัวข้อ Managed Properties) ต่อได้เลย
การลบ Unmanaged layer
ซึ่งถ้าเผลอสร้าง Unmanaged layer ขึ้นมาแล้ว ก็สามารถลบออกได้เช่นกัน โดยหลังจากลบแล้ว object นั้นก็จะกลับไปสู่ managed state และมี layer เดียวเหมือนเดิม

หากลบ unmanaged layer การแก้ไขใดๆก็ตามที่ถูกทำใน unmanaged layer นั้น จะถูกนำออกทั้งหมด
Managed Properties
Managed properties คือการตั้งค่าที่กำหนดว่า เราจะอนุญาตให้ทำอะไรกับ object นี้บ้างในตอนที่ถูก import แบบ managed solution แล้ว
โดยสามารถเข้าตั้งค่าได้ดังนี้ (จะทำได้เฉพาะตอนที่เป็น unmanaged solution เท่านั้น)
- คลิกที่ปุ่ม … ที่ object ที่ต้องการ
- คลิกที่ Advanced
- คลิกที่ Managed properties

เราจะเห็น property ที่เราสามารถปรับได้ ซึ่งแต่ละ object จะมีไม่เหมือนกัน อย่างในภาพด้านล่างนี้เป็นของ Power Apps ซึ่งจะมีแค่ Allow customizations

ซึ่งถ้าเราปิดตรงนี้ เราจะมั่นใจได้เลยว่าแอปที่ถูก import ไปทื่ environment ปลายทางด้วย managed solution จะไม่สามารถถูกแก้ไขได้แน่นอน หากจะแก้ไขต้องมาแก้ที่ environment ต้นทางและ import ไปเท่านั้น
จากภาพด้านล่างจะเห็นว่าเราไม่สามารถกด Edit แอปที่ environment ปลายทางได้เลย (ไม่ว่าจะเป็น Owner หรือต่อให้เป็น Admin สูงสุดยังไง ก็ไม่สามารถแก้ไขได้)

Patch solution
มาถึงหัวข้อที่บอกเลยว่า มีประโยชน์มากๆ ซึ่งการ Patch solution นี้ ถ้าอธิบายให้เข้าใจง่ายๆ มันเอาไว้ใช้ตอนที่เราต้องการ deploy การแก้ไขบางอย่างขึ้นไปแค่บางส่วน ยังไม่อยากยกขึ้นไปทั้ง Solution ซึ่งใช้ได้ดีในสถานการณ์ต่อไปนี้
- ใน Solution เรามีอยู่ทั้งหมด 20 object แต่จริงๆเรามีแก้ไขแค่ 2 object เราไม่อยาก import ไปทีเดียวทั้ง solution เพราะจะใช้เวลานาน
- สิ่งที่เราจะ import ไป เราไม่มั่นใจว่าจะใช้งานได้ราบรื่นไหม อาจจะเกิดปัญหาก็ได้ เลยอยากที่จะสามารถ rollback กลับได้กรณีติดปัญหา
เพราะว่าการ Patch นั้น เราสามารถเลือกได้เลยว่าจะนำ object ไหนบางส่วนที่จะ deploy ขึ้นไปได้ และถ้า deploy ไปแล้วต้องการย้อนกลับ ก็สามารถ rollback กลับได้ง่ายๆเลย
วิธีการทำ Patch solution
ตอนนี้เรามี unmanage solution หลักของเราอยู่ที่ environment ต้นทาง

ซึ่งใน solution นี้มีอยู่หลาย object เลย แต่สมมติตอนนี้เราต้องการแก้ไขแค่ Power Apps อย่างเดียว

ให้เลือกที่ solution หลักของเราแล้วทำการ
- คลิกที่ปุ่ม … ที่ object ที่ต้องการ
- คลิกที่ Clone
- คลิกที่ Clone a patch

ตั้งชื่อ Patch ของเรา ในที่นี้ผมจะตั้งว่า Hotfix ต่อท้าย ประมาณว่าเป็นการแก้ไขด่วน ต้องการเอาส่วนนี้ขึ้นก่อน แล้วก็กำหนด Version number ให้เรียบร้อย (เลข Version number ต้องมากกว่าเลขของ solution หลัก เสมอ)

เราก็จะได้ Patch ขึ้นมาเสมือนเป็นอีก solution หนึ่ง ซึ่งในตอนนี้ก็จะยังไม่มี object ใดๆอยู่ภายใน

ทีนี้เราก็กด Add existing แล้วก็เลือกได้เลยว่าเราจะเพิ่ม object ใดเข้ามาในการ patch ครั้งนี้บ้าง ซึ่งผมก็จะกดเพิ่ม Canvas app เข้ามา


หลังจากเพิ่ม object เฉพาะส่วนที่เราแก้ไขเรียบร้อย ตามที่ต้องการแล้ว ทีนี้เราก็สามารถ Export solution นี้ไป import เหมือนกับการ export import solution ทั่วไปเลย
โดยเมื่อ import ไปที่ environment ปลายทางเรียบร้อยแล้ว เราก็จะเห็น solution ของเราแยกกันอยู่แบบนี้

ซึ่งในตอนนี้ตัว Canvas app ที่เราใส่มาใน patch ด้วยก็จะถูกอัพเดทที่ environement ปลายทางเรียบร้อยแล้ว
ถ้าเกิดว่าเราต้องการย้อนกลับ เช่น ตัวแอปที่แก้มาอาจจะยังมีปัญหา ต้องการ rollback กลับก่อน เราก็เพียงแค่กด Delete solution ของ patch ตัวนี้ออก ทุกอย่างก็จะกลับไปเป็นของ solution หลักเดิมนั่นเอง ดังนั้นไม่ต้องเป็นห่วงกับการ rollback อีกต่อไป

การจะทำ Patch solution ได้นั้น ที่ environment ปลายทางต้องมี solution หลักรออยู่แล้ว
Clone solution
การ Clone solution บอกเลยว่าถ้าอ่านชื่อแบบนี้ ทุกคนคงเข้าใจว่ามันคือการ Copy solution แน่เลย ซึ่งจริงๆไม่ใช่! ผิดถนัดเลย ชื่อมันชวนสับสนไปเอง
เอาจริงๆแล้วการ Clone solution มันคือการรวบ Patch ทั้งหมดที่เราทำไว้กลับเป็น Solution เดียวแค่นั้นเอง!

เช่น ตอนนี้ผมอาจจะมี Patch อยู่หลายเวอร์ชั่นเลย ซึ่งการแก้ไขใน patch ทั้งหมดทดสอบแล้วว่าใช้งานได้ดี ไม่ติดปัญหาอะไร เราเลยอยากรวบกลับมาเป็น solution หลักอันเดียวแล้ว
หรือเราต้องการ deploy ครั้งหน้าแบบที่เป็นการ deploy ทั้ง solution เราก็จะใช้การ Clone solution ในการรวบ patch ทั้งหมดกลับมารวมกันนั่นเอง

เราสามารถ Clone solution ได้ดังนี้
- คลิกที่ปุ่ม … ที่ object ที่ต้องการ
- คลิกที่ Clone
- คลิกที่ Clone solution
- กำหนด Display name (ถ้าต้องการ)
- กำหนด Version number (ต้องมากกว่าเวอร์ชั่นของ patch ทั้งหมด)


Patch ทั้งหมดก็จะถูกรวบกลับมาเป็น solution หลักเดียว!

หาก Solution นั้นยังมี Patch อยู่ เราจะไม่สามารถแก้ไขใดๆใน solution หลักได้เลย ต้องทำการรวบ patch ทั้งหมดเข้ามาด้วยการ Clone solution ก่อน
บทสรุป
ตอนนี้ทุกท่านก็ได้รู้จักองค์ประกอบอื่นๆของ Solution ที่นอกจากจะช่วยให้การพัฒนาระบบของเราเป็นไปตาม Application Lifecycle Management ที่ดี (Health ALM) แล้ว ก็ยังช่วยอำนายความสะดวกให้เราอีกด้วยทั้งในมุมของการพัฒนาและการดูแลต่อไปในอนาคต
เทคนิคอื่นๆเกี่ยวกับการใช้ Solution ยังมีต่อ ซึ่งก็จะ Advance มากขึ้นไปอีก ไว้โอกาสหน้าจะมาแชร์เพิ่มเติมครับ 😉