ปรับขนาดการเริ่มต้นซอฟต์แวร์ของคุณบนคลาวด์ (ตอนที่ 3 จาก 3)

Nov 29 2022
ในส่วนที่ 2 ของซีรีส์นี้ เราใช้แนวคิดที่นำมาใช้ครั้งแรกในตอนที่ 1 และออกแบบการเริ่มต้นซอฟต์แวร์หาคู่ออนไลน์ที่สมมติขึ้นชื่อว่า eTumble เราจัดทำ “เอกสารที่มีชีวิต” สำหรับกลยุทธ์ การออกแบบ และสถาปัตยกรรมของเรา
ที่ยางมาบรรจบกับถนน (ไปกันต่อ)

ในส่วนที่ 2 ของซีรีส์นี้เราใช้แนวคิดที่นำมาใช้ครั้งแรกในตอนที่ 1และออกแบบการเริ่มต้นซอฟต์แวร์หาคู่ออนไลน์ที่สมมติขึ้นชื่อว่า eTumble เราจัดทำ “เอกสารที่มีชีวิต” สำหรับกลยุทธ์ การออกแบบ และสถาปัตยกรรมของเรา จุดประสงค์ของโพสต์นี้เพื่อรวบรวมทุกอย่างเข้าด้วยกันและวางแผนสำหรับโครงสร้างพื้นฐานที่จำเป็นในการทำให้แนวคิดของเราเป็นจริง และรองรับความต้องการในการปรับขนาดในอนาคตของเรา

ข้อกำหนดเบื้องต้นสำหรับการก้าวไปข้างหน้า

โดยไม่ต้องเขียนโค้ดแม้แต่บรรทัดเดียวหรือใช้เงินใดๆแบบฝึกหัด "เอกสารที่มีชีวิต" ของเราที่จัดทำขึ้นในส่วนที่ 2เปิดเผยข้อกำหนดของระบบที่แจ้งความต้องการโครงสร้างพื้นฐานการโฮสต์ในอนาคตของเรา:

ฟังก์ชันการทำงานที่ระบุตั้งแต่การวางแผนและการออกแบบเบื้องต้น

เราไม่จำเป็นต้องตอบสนองความต้องการที่ "เกิน" ทั้งหมดในทันที แต่การรู้ทันความต้องการเหล่านั้นในขณะที่ออกแบบและสร้าง MVP สามารถช่วยลดการทำงานซ้ำได้ มาดูกันว่าเป็นอย่างไร!

ขอบเขต MVP เริ่มต้นตามแผนผังเรื่องราวและ OGSM

eTumble กำลังเตรียมพร้อมที่จะกลายเป็นเรื่องใหญ่ต่อไปในการหาคู่ออนไลน์ ทีมของเราใช้เวลาอย่างชาญฉลาดในการวิเคราะห์ SWOT จัดทำเอกสารแผนกลยุทธ์ 3-5 ปีของเราโดยใช้ OGSM Framework แสดงภาพและจัดลำดับความสำคัญ MVP ของเราโดยใช้ Story Mapping และออกแบบและจัดทำเอกสารสถาปัตยกรรมของเราโดยใช้ส่วนต่างๆ ของระเบียบวิธีแบบจำลอง C4

ตัวอย่างแผนผังเรื่องราวของผู้ใช้ MVP สำหรับแอปหาคู่ออนไลน์ที่สมมติขึ้น (เวอร์ชัน 6)

แผน OGSM ของเราระบุเป้าหมายเริ่มต้นที่ผู้ใช้ 25,000 รายในปีที่ 1 และกลยุทธ์เพื่อบรรลุเป้าหมายของเรา เช่น โครงการอ้างอิง และการสาธิตในวิทยาเขตของวิทยาลัย หลังจากการทำสตอรี่แมปซ้ำหลายครั้ง เราก็ตกลงกับขอบเขต MVP ของเรา — และเขียนมันลงไป

แผนที่เรื่องราวเวอร์ชันเริ่มต้นสำหรับแอปหาคู่ออนไลน์ที่สมมติขึ้น (เวอร์ชัน 1)

หากเราข้ามการวางแผนเชิงกลยุทธ์เพื่อระบุความสำคัญของการโปรโมต เราอาจไม่ได้ทำซ้ำในแผนที่เรื่องราวมากพอที่จะจัดการกับ MVP ซึ่งจะช่วยจัดลำดับความสำคัญของสิ่งที่เราสร้างขึ้นก่อน ที่น่ากลัวยิ่งกว่านั้น เราอาจเรียกมันว่า “Mike's Match Maker” (ด้านบน) แทนชื่อเรียกที่เรียกกว่า eTumble ;-)

การได้รับ MVP ของเราในมือของผู้ใช้เป้าหมายอย่างรวดเร็วจะทำให้เรามีความเข้าใจที่ดีขึ้นเกี่ยวกับโดเมนของปัญหา และส่งผลต่อการตัดสินใจในระดับกลยุทธ์และความคิด นี่คือเหตุผลที่แผนของเราเรียกว่า "เอกสารที่มีชีวิต" และควรทำซ้ำเมื่อเวลาผ่านไปเมื่อเราเรียนรู้

การเลือกแพลตฟอร์มโฮสติ้งคลาวด์ของเรา

การเลือกใช้เทคโนโลยีมักจะเหมือนกับ “การที่ช้างอยู่ในห้อง”

การเลือกผู้ให้บริการโฮสติ้งบนคลาวด์อาจกลายเป็นเรื่องการเมืองหรือศาสนาภายในองค์กรหรือทีมใดก็ได้ ฉันชอบใช้วิธีที่ขับเคลื่อนด้วยข้อมูลสำหรับการตัดสินใจเหล่านี้ และอธิบายวิธีที่เราทำกับบริษัทก่อนหน้าในการสัมภาษณ์ BrightTALK นี้ในปี 2020

ในส่วนก่อนหน้าของซีรี่ส์นี้ ฉันได้อธิบายถึงความจริงที่ว่าเราจะใช้Google Cloud Platform (GCP) ดังนั้นฉันจะอธิบายสั้นๆ ถึงแนวทางทั่วไปของฉัน

กระบวนการทางวิทยาศาสตร์ในการประเมินผู้ให้บริการโฮสติ้งคลาวด์

ฉันได้จัดการกระบวนการนี้ในองค์กรที่ผ่านมา และองค์กรหนึ่งมีสายผลิตภัณฑ์ที่มีกลยุทธ์ที่เน้นอุปกรณ์เคลื่อนที่เป็นอันดับแรก ดังนั้นเหตุผลของฉันในการเลือก GCP จึงมาจากประสบการณ์ก่อนหน้านี้ และการสนับสนุนบริษัทหลายพันแห่งที่ DoiT AWS Amplify เป็นโซลูชันที่แข่งขันกัน แต่ต่ำกว่า GCP Firebase โดยใช้เกณฑ์หลายประการข้างต้น โดยเฉพาะอย่างยิ่งการใช้งานง่าย

บทความนี้อธิบายรายละเอียดเพิ่มเติมโดยเปรียบเทียบเฟรมเวิร์กมือถือยอดนิยมสองเฟรมGCP Firebase กับ AWS Amplifyแต่อยู่หลังเพย์วอลล์ของ Medium ความเห็นพ้องต้องกันคือ Firebase ครอบคลุมกว่า ใช้งานง่ายกว่า และอาจคุ้มค่ากว่า

ไม่ว่าคุณจะเลือกแพลตฟอร์มใด เราได้ระบุข้อกำหนดทั้งระยะสั้นและระยะยาวของระบบของเรา สมมติว่าเราได้ผ่านขั้นตอนการประเมินข้างต้น เลือก GCP ด้วยเหตุผลหลายประการ และตอนนี้ต้องออกแบบโครงสร้างพื้นฐานการโฮสต์บนคลาวด์ของเรา

ทำให้ซอร์สโค้ดของเราใช้งานได้โดยอัตโนมัติ

นอกเหนือจากบุคลากรแล้ว ที่คอร์ของซอฟต์แวร์เริ่มต้นทุกตัวคือซอร์สโค้ด ซึ่งเป็นข้อความที่มีโครงสร้างซึ่งแปลงเป็นคำสั่งที่คอมพิวเตอร์สามารถเข้าใจและประมวลผลได้ เพื่อให้โปรแกรมของเราเข้าถึงผู้ชมเป้าหมายของเรา (สมมติว่าไม่มี "Smokescreen MVP" ในขั้นตอนนี้) จะต้องปรับใช้กับสภาพแวดล้อมการโฮสต์ที่เราเลือก

หนึ่งในกลยุทธ์ของเราสำหรับ eTumble คือการสร้างสรรค์สิ่งใหม่ๆ ให้เร็วกว่าผู้อื่น แม้ว่าสิ่งนี้สามารถอธิบายได้หลายแง่มุมของการเริ่มต้นซอฟต์แวร์ แต่เราจะมุ่งเน้นไปที่ความเร็วของนักพัฒนาและอัตราที่ผู้ใช้ปลายทางสามารถรับรู้ฟังก์ชันการทำงานใหม่ (เรื่องราวของผู้ใช้) มีการศึกษาที่พิสูจน์ว่าสิ่งนี้เป็นข้อได้เปรียบในการแข่งขัน แต่เราจะไม่ลงรายละเอียดทั้งหมดของไปป์ไลน์ DevOps และ DevSecOps และ CI/CD ในบทความนี้

สิ่งที่เกิดขึ้นอาจเป็นความชอบส่วนบุคคลของทีมพัฒนา ผู้ให้บริการโฮสติ้งซอร์สโค้ดหลายราย (เช่น — Github.com, Gitlab.com หรือ Bitbucket.com) มีเครื่องมือของตนเองแล้ว หลายๆ แห่งเสนอเว็บฮุคเมื่อเกิดเหตุการณ์ที่เรียกใช้โซลูชันของบุคคลที่สาม ผู้ให้บริการโฮสติ้งระบบคลาวด์แต่ละรายก็มีบริการของตนเองเช่นกัน เช่น Azure Dev Ops ของ Microsoft หรือ Cloud Build และ Cloud Deploy ของ GCP

โดยปกติแล้ว คำแนะนำของฉันต่อองค์กรส่วนใหญ่คือการพิจารณาโซลูชันของผู้ให้บริการระบบคลาวด์ อย่างน้อยที่สุดสำหรับขั้นตอน "ปรับใช้" ของขั้นตอนการสร้างของคุณ เนื่องจากไม่จำเป็นต้องแชร์รหัสบัญชีบริการที่มีอายุการใช้งานยาวนาน (ซึ่งอาจถูกบุกรุกได้) กับบุคคลที่สาม ระบบ. GCP มีWorkload Identity Federationที่ให้คุณกำหนดบทบาท IAM ให้กับโซลูชันของบุคคลที่สามโดยไม่ต้องแชร์คีย์ ซึ่งเป็นตัวเลือกเช่นกัน

ข้อควรพิจารณาสำหรับการปรับขนาดบนคลาวด์

เสาหินหรือไม่

ลองดูสิ การเริ่มต้นซอฟต์แวร์ที่ประสบความสำเร็จทั่วโลกส่วนใหญ่ในปัจจุบันเริ่มเป็นแอปพลิเคชันขนาดใหญ่ 3 ชั้น ไม่มีอะไรผิดปกติกับเสาหินในช่วงแรก การมีเพศสัมพันธ์ช่วยลดความซับซ้อนทางเทคนิคจำนวนมาก และเนื่องจาก "โทโพโลยีของทีม" หมายความว่าการตัดสินใจเหล่านี้มักจะเกี่ยวกับภาระทางความคิดในทีมของคุณ ด้วยเป้าหมายผู้ใช้ 25,000 รายในปีแรกและการมุ่งเน้นวิทยาเขตของวิทยาลัย นี่เป็นการออกแบบที่ยอมรับได้อย่างสมบูรณ์สำหรับสิ่งที่กำหนดขอบเขตไว้ใน MVP ของเรา

ปัญหามักเกิดขึ้นเมื่อคุณเริ่มปรับขนาด อย่างไรก็ตาม ไม่ต้องกลัว เพราะเราสามารถออกแบบโซลูชัน "รวดเร็วและสกปรก" ของเราเพื่อให้คำนึงถึงสถาปัตยกรรมไมโครเซอร์วิสในอนาคตของเราได้อย่างง่ายดาย

องค์ประกอบองค์ประกอบในสถาปัตยกรรมโมเดล C4 สำหรับ API แอปหาคู่ออนไลน์ที่สมมติขึ้น

ในไดอะแกรมสถาปัตยกรรมโมเดล C4 ของเรา เราได้ระบุ "ตัวควบคุม" ในมุมมองคอมโพเนนต์สำหรับแอป "Backend API" ตัวอย่างเช่น แถวที่ระบุการเผยแพร่ข้อความไปยัง Pub/Sub อาจรวมตรรกะไมโครเซอร์วิสภายในแอป API ที่เลเยอร์ "Model" ของสถาปัตยกรรม Model-View-Controller (MVC) เส้นทาง API ยังคงเหมือนเดิม

เมื่อพิจารณาถึงไมโครเซอร์วิส เราสามารถย้ายฟังก์ชันการทำงาน “Model” จากแอป API ไปยังบริการต่างๆ ที่แยกจากกัน และสื่อสารผ่าน HTTP/RPC หรือการส่งข้อความแบบอะซิงค์ หากคุณวางแผนล่วงหน้า คุณสามารถออกแบบเลเยอร์ wrapper สำหรับการเรียกใช้ฟังก์ชันหรือเมธอดที่โต้ตอบกับชั้นข้อมูลในขั้นต้น และเปลี่ยนไปใช้การโทรระยะไกลในอนาคตโดยมีการเปลี่ยนแปลงโค้ดเพียงเล็กน้อย

อย่างไรก็ตาม หากคุณได้ออกแบบระบบกระจายเพียงพอ คุณอาจเลือกใช้สถาปัตยกรรมที่ขับเคลื่อนด้วยเหตุการณ์แทนตามที่แสดงในไดอะแกรมคอนเทนเนอร์ของเรา

จะ "ไร้เซิร์ฟเวอร์" หรือใช้คอนเทนเนอร์

ในตอนต้นของซีรีส์ 3 ส่วนนี้ ฉันระบุว่าการเริ่มต้นซอฟต์แวร์ในปัจจุบันมีความได้เปรียบกว่าเมื่อ 5-10 ปีที่แล้ว ส่วนหนึ่งเป็นผลมาจากผู้ให้บริการระบบคลาวด์แบบไฮเปอร์สเกล ผลิตภัณฑ์ไร้เซิร์ฟเวอร์ เช่น AWS Lambda, Google Cloud Functions หรือแม้แต่ Azure Functions เป็นตัวอย่างที่ดี นักพัฒนาสามารถพุชโค้ดไปยัง "รันไทม์" เหล่านี้และได้รับประโยชน์จากการไม่ต้องบำรุงรักษาโครงสร้างพื้นฐานและการปรับขนาดอัตโนมัติ

แม้ว่านี่จะดูเหมือนเป็นวิธีการที่ชัดเจนในการเปิดตัว MVP ของคุณ แต่โปรดคำนึงถึงเขตที่วางทุ่นระเบิดทางเทคนิคที่คุณวางไว้ระหว่างทาง บริการเหล่านี้บางส่วนมีโปรแกรมจำลองเพื่อให้คุณสามารถสร้างและทดสอบภายในเครื่องได้ ซึ่งช่วยลดการพึ่งพาและค่าใช้จ่ายของสภาพแวดล้อมอื่น

ฉันชอบที่จะใช้ประโยชน์จากโซลูชันแบบไร้เซิร์ฟเวอร์สำหรับงานอะซิงโครนัสแบบวัตถุประสงค์เดียวขนาดเล็กที่กระตุ้นโดยเหตุการณ์ในระบบของคุณ เช่น "ไฟล์ที่อัปโหลดหรือเปลี่ยนแปลง" หรือ "ข้อความที่เผยแพร่"

สำหรับการสร้าง API ที่จะกำหนดเส้นทางคำขอไปยังส่วนแบ็คเอนด์ต่างๆ แอปพลิเคชันคอนเทนเนอร์อาจเป็นทางเลือกที่ฉลาดกว่า เนื่องจากการขึ้นต่อกันทั้งหมดถูกรวมไว้ในอิมเมจ คอนเทนเนอร์ทำให้การพัฒนาและการทดสอบในพื้นที่ง่ายขึ้น ผู้ให้บริการโฮสติ้งระบบคลาวด์ส่วนใหญ่เสนอโซลูชันคอนเทนเนอร์แบบ "ไร้เซิร์ฟเวอร์" เช่น ECS บน AWS และ Cloud Run หรือ App Engine แบบยืดหยุ่นบน GCP

ฉันชอบความสามารถในการพกพาของคอนเทนเนอร์สำหรับแอปพลิเคชันที่ซับซ้อนมากขึ้น และหากคุณปฏิบัติตามหลักการของระเบียบวิธีแอปแบบ 12 ปัจจัย วิธีนี้ยังช่วยลดความเสี่ยงของการเลื่อนการกำหนดค่าที่คืบคลานเข้ามาในสภาพแวดล้อมต่างๆ ในไปป์ไลน์ CI/CD ของคุณ

Priyanka Vergadia ที่ Google ได้จัดทำคอลเลกชั่นของ "บันทึกย่อ" และด้านล่างนี้คือ " ฉันควรเรียกใช้ข้อมูลของฉันที่ใด" เป็นคำแนะนำที่เป็นประโยชน์

ขอขอบคุณ: Google Cloud Platform

ใช้ประโยชน์จากกลุ่มอีเมลเพื่อปรับขนาดจากหนึ่งไปยังหลายทีม

สมมติว่าเราเริ่มต้นด้วยคนไม่กี่คน แต่ในที่สุดแผนของเราต้องรองรับผู้ใช้หลายสิบล้านคนในหลายประเทศ เราจะปรับขนาดองค์กรของเราอย่างไม่ต้องสงสัยเพื่อรวมทีมและผู้เชี่ยวชาญจำนวนมาก (แกน y และแกน z ของ AKF Scale Cube ใช้กับองค์กรของเราด้วย)

แนวทางปฏิบัติที่ดีที่สุดในการตั้งค่า Identity and Access Management (IAM) ด้วยแพลตฟอร์มระบบคลาวด์คือการกำหนดบทบาทให้กับกลุ่มแทนที่จะเป็นผู้ใช้รายบุคคล ในบทความที่ฉันเขียนเมื่อสองสามปีที่แล้วเกี่ยวกับการจัดโครงสร้างองค์กรบนคลาวด์ฉันอธิบายกลุ่มเริ่มต้นที่แนะนำและอีกมากมาย

กลุ่มที่เราจัดตั้งในระยะเริ่มต้นสามารถปรับขนาดตามองค์กรได้ (สมาชิกเท่านั้นที่เปลี่ยนไปตามกาลเวลา)

แม้ว่าการเริ่มต้นของเราจะเริ่มต้นด้วยคน 3 คน แต่ก็ไม่มีอะไรหยุดเราไม่ให้กำหนดกลุ่มและเพิ่มคนในหลายๆ คนเพื่อเริ่มต้น เมื่อเราจ้างคนมากขึ้น เราสามารถปล่อยให้กลุ่มกับผู้เชี่ยวชาญค่อยๆ

ตัวอย่างกลุ่มผู้ใช้ในองค์กรหลังจากเพิ่มขนาดทีมสำหรับแอปหาคู่ออนไลน์ที่สมมติขึ้น

ในระดับองค์กร ในที่สุดคุณก็สามารถแยกทีมออกไปได้ตามความต้องการและความต้องการในการโหลดความรู้ความเข้าใจ ไม่ว่าคุณจะเริ่มต้นจากที่ใด แนวทางปฏิบัติที่ดีที่สุดคือการมอบบทบาท Cloud IAM ให้กับกลุ่ม แทนที่จะเป็นผู้ใช้รายบุคคล เพื่อให้ดูแลรักษาได้ง่ายขึ้นและลดการทำงานซ้ำให้สังเกตรูปแบบได้ที่นี่

การออกแบบลำดับชั้นของทรัพยากรระบบคลาวด์ของคุณสำหรับผู้เช่าหลายราย

รายการตรวจสอบการอ้างอิง GCP ที่ปลอดภัยนี้ฉันได้เขียนไว้เมื่อสองสามปีที่แล้ว รวมถึงตัวอย่างการออกแบบแนวปฏิบัติที่ดีที่สุดที่แนะนำ ขณะที่เรากำลังออกแบบสถาปัตยกรรมระบบคลาวด์สำหรับ MVP อาจมีงานบางอย่างที่ “ทิ้งไป” ในช่วงเริ่มต้น แต่ฉันยังคงแนะนำให้ใช้โครงสร้างที่คล้ายกันเมื่อตั้งค่าลำดับชั้นของทรัพยากรระบบคลาวด์

ตัวอย่างลำดับชั้นของทรัพยากร Google Cloud Platform — ช่วงเริ่มต้น

เมื่อองค์กรขยายขนาด พัฒนาไปสู่เวอร์ชันที่ใหม่กว่าของผลิตภัณฑ์ที่แสดงอยู่ในแผนที่เรื่องราวของผู้ใช้ เราอาจเปลี่ยนไปใช้การบริหารเครือข่ายแบบรวมศูนย์ การจัดการคลัสเตอร์ Kubernetes และโครงสร้างทีมแบบหลายผู้เช่า การดำเนินการนี้มักทำให้การเริ่มต้นใช้งานซอฟต์แวร์หยุดชะงักเมื่อถึงจุดเปลี่ยนที่อธิบายไว้ในส่วนที่ 1ของซีรี่ส์นี้

อาจมีการ “โยนทิ้ง” ไปบ้างในช่วงเริ่มต้น

GCP มีข้อมูลอ้างอิงที่ดีเยี่ยมซึ่งอธิบายวิธีสร้างผู้เช่าหลายรายขององค์กรพร้อมรายละเอียดเพิ่มเติม ด้านล่างนี้คือภาพประกอบของโครงสร้างพื้นฐานระบบคลาวด์ของ eTumble ในอนาคตเมื่อเราบรรลุเป้าหมาย Y2 และ Y3 ของเรา (ละเว้นมุมมองทรัพยากรสำหรับความสั้นของบทความ)

ตัวอย่างลำดับชั้นของทรัพยากร Google Cloud Platform — ระยะหลัง

ประเด็นสำคัญในที่นี้คือการสังเกตว่าโปรเจ็กต์โฟลเดอร์บริการที่ใช้ร่วมกัน เริ่มต้นไม่เคยเปลี่ยนแปลง และ กลุ่ม ที่ เราจัดตั้งในระยะแรกสามารถปรับขยายตามองค์กรได้ (เฉพาะสมาชิกเท่านั้นที่เปลี่ยนแปลงเมื่อเวลาผ่านไป) ผู้เช่าแต่ละราย (ทีม) จะรักษาทรัพยากรเฉพาะของตน เช่น ฐานข้อมูลและความลับในโครงการของตน และอ้างอิงจากแอปคอนเทนเนอร์ที่ปรับใช้กับคลัสเตอร์ในเนมสเปซของตน

ระบบภายนอก (การรับรองความถูกต้อง การชำระเงิน อีเมล ฯลฯ)

แผนและการออกแบบของเราแสดงให้เห็นถึงความต้องการระบบภายนอก เช่น อีเมลธุรกรรม การชำระเงินออนไลน์ และอาจเป็นไปได้ว่าข้อมูลประจำตัวและการรับรองความถูกต้อง ขณะเลือกผู้ให้บริการโซลูชันภายนอก ให้พิจารณาสิ่งต่อไปนี้:

  • สภาพแวดล้อม ที่หลากหลาย สำหรับการทดสอบและการผลิตด้วยการตรวจสอบสิทธิ์แยกต่างหาก
  • การรักษาและหมุนเวียนข้อมูลประจำตัวในที่เก็บข้อมูลลับที่เข้ารหัส
  • สิ่งจูงใจทางการค้าที่มีให้ซื้อผ่านตลาด

ยินดีด้วยที่มาได้ไกลขนาดนี้! ซีรีส์ 3 ส่วนนี้จะพาคุณไปสู่เส้นทางตั้งแต่ระเบียบวิธีและเฟรมเวิร์กที่มีประโยชน์ ไปจนถึงการออกแบบการเริ่มต้นซอฟต์แวร์ตั้งแต่เริ่มต้น และสุดท้ายคือการใช้ "เอกสารที่มีชีวิต" เพื่อวางแผนโครงสร้างพื้นฐานระบบคลาวด์สำหรับทั้งช่วงเริ่มต้นและระยะหลัง

ฉันรอคอยที่จะให้คุณใช้หลักการเหล่านี้และดำเนินการต่อจากจุดที่เราค้างไว้เพื่อช่วยแก้ปัญหาความเหงาในระดับดาวเคราะห์ ;-)

หากคุณรู้สึกว่าซีรีส์นี้จะเป็นประโยชน์กับผู้อื่น โปรดอย่าเก็บเป็นความลับ ให้ "ความรัก" และปรบมือให้แต่ละส่วน และแบ่งปันกับผู้อื่น ขอบคุณที่อ่าน!