# blog.ninprd — Full Content > Read about experience sharing and technology on blog.ninprd, a dynamic blog by Peeranat Danaidusadeekul, a full-time Software Engineer and part-time blogger. This file contains the full text of every published post on the blog, newest first. Relative links and image paths inside a post are relative to its canonical URL. --- # สีเหลืองเยลโล่ว บ๊ายบาย Skooldio - URL: https://blog.ninprd.com/blog/goodbye-skooldio/ - Published: 2026-06-14 - Tags: experience-sharing, skooldio, skooldio-tech, resignation, career-growth, software-engineer - Summary: ทำงาน 4 ปีที่ Skooldio Tech ได้อะไรมาบ้าง ไปดูกัน > สีเหลืองเยลโล่ว บริษัทที่อยากเข้า Skooldio ผ่ามมม นี่เป็นประโยคที่นิลใช้ใน form สมัครงานเมื่อ 4 ปีที่แล้วครับ เป็นช่วงเวลาที่น่าจดจำสำหรับนิลเลยแหละครับ ตอนนี้ผ่านมา 4 ปีแล้ว หมดเวลาสนุกแล้วสิครับ ถึงเวลาที่นิลจะออกไปเติบโตในที่แห่งอื่นแหละครับ นิลแอบอยากมา recap ว่าใน 4 ปีนี้ นิลได้ทำอะไรบ้างกับ Skooldio ครับ นิลอยากเริ่มจากสิ่งที่นิลได้ลองใน 4 ปีที่ Skooldio และจบด้วยสิ่งที่นิลได้เรียนรู้นะครับ ใครอยากอ่านตรงไหนสามารถเริ่มอ่านจากจุดนั้นได้เลยครับ --- ## สิ่งที่นิลได้ลองใน 4 ปีที่ Skooldio Tech เอาล่ะ 4 ปีทุกคนคิดว่านิลจะได้เป็นอะไรมาแล้วบ้าง มาดูกั๊น 555555 ### Technical Growth #### ได้ลองเป็น PM และ UX/UI Designer จำเป็นในหลาย ๆ project อย่างที่เคยบอกใน blog แรกไปว่านิลเคยอยู่ทีมที่เป็น Proof of Concept (PoC) ซึ่งเป็นทีมที่ต้องพัฒนา product อย่างไว เลยมีบาง project ที่พี่ ๆ ให้นิลลองไปรับ requirement กับลูกค้าเอง หรืออาจจะมีบาง project ที่รีบมากและไม่ได้ design ของบางส่วนไว้ ทำให้นิลได้ลองจับงานทั้ง requirement เขียน user story จนถึงการไปก๊อก ๆ แก๊ก ๆ Figma มาด้วยแหละ ถือว่าได้ลองอะไรเยอะเลยครับ #### ได้เป็น Dev Lead ทำ Learning Platform สำหรับนักเรียนหลักหมื่นคนทั่วไทย อันนี้เรียกได้ว่า highlight เลยแหละครับ นิลได้ร่วมทำ platform KapiBarian ใน [Craft AI Project](https://www.facebook.com/people/CRAFT-AI-Project/61578569144193/) เพื่อพัฒนา platform ที่ช่วยส่งเสริม reading literacy และ critical thinking ให้กับน้อง ๆ ครับ รวมถึงต้องสามารถให้ครูมาดูข้อมูลและช่วยส่งเสริมการพัฒนาน้อง ๆ ได้อีกด้วย ใน project นี้ นอกจากเป็น Dev ที่ทำงาน ต้องเป็น Dev Lead คอยดูงานน้อง ๆ และควบคุม timeline ของ project งานนี้นิลยังควบงาน Software Architect ที่ต้องวาง architect ของระบบและเป็น DX Engineer ที่ช่วยลดคอขวดของการทำงานของชาว Dev และต้องบินไปตามจังหวัดต่าง ๆ เพื่อสอนคุณครูใช้งานระบบด้วยครับ บอกเลยว่าเหนื่อยมากกกกก แต่ก็สนุกมากเหมือนกันครับ ยิ่งช่วงท้าย ๆ นี่นิลคิดว่านิลเริ่ม sync กับน้อง PM จนมองตาแล้วออก requirement กันแล้วแหละ 555555 แต่เสียดาย นิลแรงหมดก่อน แหะ ไม่งั้นน่าจะได้ทำอะไรที่สนุกกันอีกเยอะเลยแหละ (อ่ยยย 😔) ![](assets/bye-bye-skooldio-kapibarian.webp) ### Communication Growth #### ได้ลองเขียน Blog (และยาวมาถึงทุกวันนี้) อันนี้เป็นหนึ่งในสิ่งที่นิลรู้สึกว่า success สำหรับนิลมากเลยครับ เมื่อ 4 ปีก่อน นิลรู้สึกว่าตัวเองเป็นคนที่พูดไม่รู้เรื่องเลย เป็นคนที่เรียบเรียงคำพูดไม่เป็นเลย พอนิลทำงานที่ Skooldio ครบ 1 ปี นิลก็ได้เห็นพี่ ๆ เขียน LinkedIn ในการครบรอบการทำงานและนิลก็เห็นพี่ ๆ ที่ออฟฟิศเขียน blog กัน นิลเลยอยากลองมั่ง [ซึ่งออกมาเป็น blog แรกอันนี้](https://blog.ninprd.com/blog/1-year-at-skooldio)ครับ และหลังจากที่นิลลองเขียน blog เมื่อ 3 ปีที่แล้ว และได้ออกไปงาน meetup งาน conference รวมถึงได้เป็น facilitator workshop ที่ต้องใช้ skill การพูดและการอธิบายเยอะ ๆ แล้ว นิลรู้สึกว่านิลสามารถเรียบเรียงการพูดนิลได้ดีขึ้น และสามารถอธิบายของหลาย ๆ อย่างให้เพื่อน ๆ เข้าใจได้ดีขึ้นครับ ล่าสุดคุยกับเพื่อนที่เรียนสถาปัตย์มาแล้วเพื่อนบอกว่า อยากคุยกับ Dev ที่สื่อสารออกมารู้เรื่องแล้วคิดถึงนิลคนแรก ในใจนิลแบบ 🥹 รู้สึกภูมิใจอันนี้มาก ๆๆ 😭 โฮฮฮ #### ได้ลองเป็น Speaker พูดหน้าห้องเรียน อันนี้เป็น event ที่เกิดขึ้นงง ๆ ฮะ เรื่องหลัก ๆ เลยมีอยู่ว่า manager ที่ออฟฟิศนิลเป็นเพื่อนกับอาจารย์วิศวะภาคคอมที่จุฬาฯ ครับ และมีอยู่คาบนึงที่อาจารย์เขาไม่ว่างเลยอยากให้พี่ manager คนนั้นมาแชร์เกี่ยวกับการทำงานในบริษัทให้น้อง ๆ วิศวฯ จุฬาฯ ปี 1 ฟังกันครับ ซึ่งพี่ manager เขาก็ให้โอกาสนิลในการมาพูดหน้าห้องเรียนให้น้อง ๆ ฟังกัน ซึ่งก็เป็นโอกาสที่ทำให้นิลได้เรียนรู้เกี่ยวกับการพยายามควบคุมห้องเรียนด้วย ถือว่าได้ลองทำอะไรใหม่ ๆ ดีครับ #### ได้ลองออกไป Conference และ Meetup นิลได้เริ่มที่การได้ลองไป UX Day ของ Gang Connector ในปี 2023 ครับ ซึ่งตอนนั้น Skooldio เป็น sponsor เลยทำให้มีตั๋วเข้างานครับ เอาตรง ๆ คือนิลรู้สึกว่าตัวเองเป็นคนที่ social awkward มาก ๆ แต่ก็คิดอีกมุมนึงว่า ถ้านิลไป น่าจะได้เจอเพื่อน ๆ UX ในบ. แหละ นิลเลยกัดฟัน 1 ทีแล้วก็ตัดสินใจไปครับ แต่ในความเป็นจริง ไม่มีเพื่อนไปเลยครับ นั่นเลยทำให้นิลต้องพยายามเอาตัวรอดในงาน conference ครั้งแรก และก็ได้ค้นพบท่าในการเข้าสังคมรูปแบบใหม่คือ ถ้าเราคุยกับ extrovert คนนึงแล้วเขาถูกชะตากับเรา เขาจะพาเราไปด้วยทุกที่ในงานและพาเราไปรู้จักคนเยอะมากเลย ซึ่งนิลก็ได้เรียนรู้ว่า conference/meetup เนี่ย value ที่มากกว่าการมาฟัง topic ต่าง ๆ คือการได้คุยกับคนอื่น ๆ ในงานและแลกเปลี่ยนความคิดในหัวข้อที่เราสนใจร่วมกัน และมันทำให้เราได้คุยกับคนที่มีความชอบคล้าย ๆ กัน รวมถึงมันได้ connect กับผู้คนไว้ และเราก็จะสามารถเห็น movement ของคนที่ทำของใกล้ ๆ กันได้ (และมันได้ของตามบูธที่เขามาเปิดเยอะด้วย ฮา 5555555) #### ได้ลองเป็น TA และ Facilitator ตาม workshop ต่าง ๆ นิลได้เริ่มเป็น TA จาก bootcamp ที่มีชื่อว่า [Web Development Bootcamp](https://landing.skooldio.com/web-development-bootcamp) ครับ โดยตอนแรกก็แอบไม่มั่นใจ เพราะรู้สึกว่าตัวเองยังอธิบายเกี่ยวกับ technical ได้ไม่ดีขนาดนั้น แต่พอลองได้ทำก็รู้ว่าจริง ๆ ตัวนิลก็ทำได้นี่นา หลังจากที่นิลรู้สึกว่านิลทำได้แล้ว นิลก็เริ่มขยายผลไปตาม workshop ต่าง ๆ ของ Skooldio ครับ เริ่มจาก [Product Manager Bootcamp](https://landing.skooldio.com/product-management-bootcamp), Prompt Engineering and RAG, [AI Automation for Business Transformation](https://www.skooldio.com/workshops/ai-automation-for-business-transformation) และ [AI Automation Transformation](https://www.skooldio.com/workshops/ai-automation-transformation) ![](assets/bye-bye-skooldio-faci.webp) ### Random Event #### ได้แข่ง Hackathon ในนามบริษัท ย่างเข้าปีที่ 2 ของการทำงาน นิลก็ได้ถูกชวนไปส่ง project เข้าแข่ง [hackathon ของ ETDA ในรายการ Hack for GROWTH](https://www.etda.or.th/th/hackforgrowth) ครับ ซึ่งเป็นการหา solution การส่งเสริมในหมวดการท่องเที่ยวครับ ซึ่งตอนนั้นก็ถึงรอบ 20 ทีมสุดท้ายแหนะะ ยังคงคิดถึงพี่ ๆ ที่อยู่ในทีมที่แข่งด้วยกัน เป็น moment ที่สนุกมากครับ ได้เข้าไปเรียนรู้อะไรเยอะเลยว่าโลกนี้ไม่ได้จบที่แค่ coding แต่ idea และ business มันต้องมาด้วย #### ได้ลองสอน Class ใน Web Development Bootcamp รุ่นที่ 2 นิลได้รับโอกาสจากพี่ฝั่ง business ว่าอยากได้คนสอนเกี่ยวกับ git ซึ่งพี่เขามองว่านิลดูสอนได้และนิลก็เป็น TA ใน bootcamp นี้อยู่แล้ว คนเรียนทุกคนน่าจะรู้จัก และก็นิลก็ย้ายสายมาด้วย อาจจะสามารถอธิบายในมุมที่น้อง ๆ ที่ย้ายสายเหมือนกันจะเข้าใจได้ ซึ่งเอาตรง ๆ คือตอนนั้น นิลไม่มั่นใจเลย แต่ในหัวนิลก็คือ *"ลองดู"* ครับ ซึ่งก็ซ้อมสอนหลายรอบมาก เตรียมกับน้อง TA เยอะมาก ก็ยังมีจุดที่พลาดอยู่ครับ ตอนสอนนิลก็ยังลน ๆ และก็มี slide นึงที่พลาดแบบมี comment TODO ไว้ใน slide ด้วย (ขอโทษนักเรียนรุ่นนั้นด้วยครับ 🥲) สุดท้ายก็ผ่านมาได้แบบทุลักทุเลมาก ๆ มองย้อนกลับไปต้องขอบคุณพี่ ๆ ที่ไว้ใจให้สอนและน้อง ๆ TA ที่ support กันวันนั้น รวมถึงคนเรียนทุกคนที่อยู่ฟังกันจนจบด้วยครับ ขอบคุณครับ ✅ ![](assets/bye-bye-skooldio-teach-web-dev-bootcamp.webp) #### ได้เรียน bootcamp 7 หมื่นฟรี อันนี้เริ่มจากการที่นิลสนใจ UX จากการไป [UX Day ในปี 2023](https://www.facebook.com/photo/?fbid=203003242246877) และ UX Conference ในปี 2024 มา ทำให้นิลเริ่มจะสนใจในสาย UX มากขึ้นครับ นิลเลยตัดสินใจขอเรียน [UX/UI Bootcamp ของ Skooldio](https://landing.skooldio.com/ux-ui-bootcamp) ไป (ซึ่งเป็นสวัสดิการที่จะสามารถขอเรียน Bootcamp ฟรีได้นะครับ อิ_อิ) ซึ่งนิลก็บอกตรง ๆ เลยว่าคุ้มมากกก สามารถ[อ่าน review ของนิลได้ที่นี่เลย](https://blog.ninprd.com/blog/skooldio-ux-ui-bootcamp-7-review) #### ได้ลองเป็นช่างภาพงาน event เมื่อก่อนนิลรับงานถ่ายรูปพวกรับปริญญาแหละครับ ซึ่งในตอนนี้ร่างกายนิลก็รับการถือกล้องหนัก ๆ เป็นเวลานาน ๆ ไม่ไหวแล้ว นิลก็เลยเลือกจะเลิกรับงานถ่ายรูปไป ทีนี้สิ้นปีที่แล้วมีการรับสมัคร staff [งานมาเรียนธอนของ Skooldio](https://www.facebook.com/MarianthonFestival/) ซึ่งนิลก็อยากไปช่วย volunteer มาก ๆ ครับ โดยที่พี่ ๆ เขารู้ว่านิลถ่ายรูปได้ พี่เขาเลย assign นิลมาเป็นตากล้อง ซึ่งเอาจริง ๆ เลยคือนิลไม่มั่นใจเลยครับว่าจะเป็นตากล้องงาน event ได้เพราะไม่เคยทำแบบจริง ๆ จัง ๆ เลยครับ (ไม่มั่นใจอีกแล้วครับท่านผู้ชม 5555555) แต่สุดท้ายนิลก็รอดออกมาได้ครับ นิลได้เจอกับพี่ ๆ หลายคนเลย ทั้งพี่เนียร์จาก [Rebalance](https://web.facebook.com/rebalpt) พี่คะน้าจาก[เพจ Farang Angmor](https://web.facebook.com/KanaFarangAngmor) พี่จอยจาก[เพจ Finding Joy](https://web.facebook.com/profile.php?id=61559748992181) อาจารย์เกดจาก[เพจเกตุวดี Marumura](https://web.facebook.com/Gademaru) เจ้าของหนังสือริเน็นที่โด่งดังมาก ๆ และก็ได้เจอ[พี่ ๆ ทีมเสือเผ่น](https://web.facebook.com/seuxphen)มาสอนการวิ่ง และก็[พี่เอ๋ นิ้วกลม](https://web.facebook.com/roundfinger)ด้วย เป็นการทำงานที่ได้รับความรู้ในหลาย ๆ ด้าน และทำให้นิลมองโลกการทำงานโดยเลนส์ใหม่ ๆ ด้วยครับ ขอบคุณพี่ ๆ ที่ให้โอกาสนิลได้ทำตรงนี้ด้วยครับ ![](assets/bye-bye-skooldio-event-photographer.webp) --- ## สิ่งที่ได้เรียนรู้ในการทำงาน 4 ปี นิลกลัวจะเขียนเยอะเกิน ขอคัดอันเด็ด ๆ มา 10 ข้อละกันครับ 1. *เราทุกคนมี pace ของตัวเอง เข้าใจตัวเองและอย่าเร่งตัวเอง* ในช่วงแรก ๆ ที่นิลทำงานครับ นิลคิดว่าตัวเองช้ากว่าคนอื่น พยายามอัดงานเข้าไป พยายามเรียนรู้เพิ่มเยอะ ๆ เพียงเพราะนิลคิดว่านิลกำลังทำได้ไม่ดีพอ นิลต้องตาม Dev คนอื่น ๆ ให้ทัน แต่พอไปคุยกับ manager มาจริง ๆ นิลก็ทำได้ตาม expectation ของ junior แล้ว หรือทำได้ตามที่พี่ ๆ เขาคาดหวังแล้ว ซึ่งนิลก็กลับมาคิดได้ว่าจริง ๆ ทุกคนก็มี pace ของตัวเองครับ เราต้องรู้ก่อนว่าตอนนี้เรากำลังพุ่งไปด้วยความเร็วเท่าไหร่ และเราต้องกลับมาคิดดี ๆ ว่าการพุ่งไปด้วยความเร็วเท่านั้น ส่งผลกับเราอย่างไรบ้าง 2. *อย่ารอจนพร้อม 100% ค่อยลอง* ถ้าสังเกตดูในพาร์ทก่อนหน้านี้ เกือบทุกอย่างที่นิลได้ลอง ไม่ว่าจะเป็น TA, การสอน class Web Dev Bootcamp, ช่างภาพงาน event, หรือการขึ้นไปพูดหน้าห้องเรียน นิลเริ่มต้นด้วยความรู้สึก "ไม่มั่นใจ" แทบทั้งนั้นเลยครับ 5555 นิลรู้สึกว่าตัวเองยังไม่พร้อม ยังเก่งไม่พอ ยังอธิบายได้ไม่ดีพอ แต่พอได้ลองทำจริง ๆ นิลก็พบว่าเราทำได้นี่นา และเราเก่งขึ้นจากการได้ลองทำ ไม่ใช่จากการรอให้พร้อมก่อน learning ที่ได้คือถ้ามัวรอให้พร้อม 100% ก่อนค่อยลอง เราอาจจะไม่ได้เริ่มสักที ความพร้อมหลาย ๆ อย่างมันมาจากการลงมือทำไปเลยมากกว่าครับ 3. *อย่าเพิ่งรีบแก้ปัญหา ถ้ามันยังไม่เกิด* หลาย ๆ ครั้ง นิลจะเป็นสาย preventive โดยจะพยายามแก้ปัญหาก่อนที่มันจะเกิด เพราะนิลอาจจะเคยผ่านมาแล้ว และนิลก็รู้ว่ามันจะเป็นปัญหา แต่เวลาที่มันยังไม่เป็นปัญหาเนี่ย ทุกคนจะมองว่านิลคิด worst case เกินไป หรือหลาย ๆ คนจะไม่เชื่อนิลในตอนแรกครับ ซึ่งสุดท้ายตอนที่ทุกคนเจอปัญหานี้จริง ๆ และมันก็ใหญ่มาก ๆ แล้ว ซึ่งนิลก็ได้ learning ว่านิลควร point ปัญหาให้ถูกเวลามากขึ้นครับ 4. *ทุกครั้งที่เราแก้ปัญหานึง จะมีอีกปัญหานึงโผล่มาเสมอ* ในองค์กรของเราจะเต็มไปด้วยปัญหาครับ ซึ่งนิลก็จะอยากแก้ปัญหาตรงนู้นตรงนี้ตรงนั้นเต็มไปหมด บางอันนิลก็แก้ได้ บางอันก็แก้ไม่ได้ แต่พอนิลยิ่งแก้ปัญหาไปเรื่อย ๆ นิลก็ค้นพบว่านิลก็จะเจอปัญหาเรื่อย ๆ นี่นา ซึ่ง learning ที่ได้ก็คือนิลควร prioritize ปัญหาที่จะแก้ รวมถึงแก้บางอัน และเรียนรู้ที่จะอยู่กับบางปัญหาให้ได้ 5. *เวลาคุยกับใคร ให้คุยในหน่วยเงินที่เขาสนใจ* เวลาเราคุยกับ PM เราก็ควรจะคุยกับเขาว่า solution A ใช้เวลากี่วัน มี trade off อะไร ไม่ใช่ว่าเราจะไปคุยกับเขาว่าการทำ solution A ใช้ library นี้แล้วมันทำแบบนี้ วู้ฮู้~ ข้อนี้จริง ๆ มันคือการ know your audience ครับ คุยกับใครก็ใช้ภาษาคนนั้น หรือใช้หน่วยที่คนนั้นสนใจ มากกว่าการที่เราจะใช้หน่วยเงินของตัวเองในการคุยในทุก ๆ ที่ 6. *อย่าคิดไปเองว่าสิ่งที่เราทำมันมี value ถ้าบริษัทไม่ได้สนใจขนาดนั้น* อันนี้เป็นบทเรียนที่เจ็บอยู่เหมือนกันครับ หลาย ๆ ครั้งนิลจะอินกับงานบางอย่างมาก ๆ คิดว่ามันเจ๋ง มันมีประโยชน์ มันต้องเป็นของที่สำคัญแน่ ๆ แล้วก็ทุ่มแรงลงไปเต็มที่ แต่สุดท้ายมันกลับไม่ใช่สิ่งที่บริษัทกำลัง focus อยู่ในตอนนั้น สิ่งที่เรามองว่ามี value มาก ๆ เลยกลายเป็นของที่ไม่มีใครสนใจเท่าที่เราคิด เช่น นิลเคยไป optimize CI จากที่มัน run maximum 45 นาที เหลือ maximum แค่ 10 นาที ยิ่งงานที่ run น้อย ๆ เนี่ย เหลือแค่ 3 นาทีด้วยซ้ำครับ ซึ่งในมุมนิลมันคือการ optimize ขั้นเทพแบบ เชรดดด กูทำได้ไงวะ แต่สุดท้ายแล้วสิ่งนี้ไม่ใช่สิ่งที่ทีม focus ตอนนั้นครับ ทีมกำลัง focus deliverable กันในระดับที่สามารถปิด CI ทิ้งได้เลยแหละ (ใช่ครับ ปิดทิ้งเลย 😭) นิลเลยได้ learning ว่า value ของงานไม่ได้ตัดสินจากเราคนเดียว แต่มันต้องสอดคล้องกับสิ่งที่ทีมหรือบริษัทกำลังให้ความสำคัญด้วย ก่อนจะทุ่มแรงลงไป ลองเช็คก่อนว่าของที่เราจะทำมัน align กับ direction ขององค์กรไหม 7. *ทำงานอย่าติดเกรงใจขนาดนั้น* หลาย ๆ คนเวลาทำงานครั้งแรกแล้วขอ request อะไรจากพี่ ๆ ไป เราจะชอบรอ หรือถ้าพี่ ๆ บอกว่าไม่ได้ เราก็จะถือว่าเราไม่ได้ (หรืออันนี้อาจจะเป็นที่นิล) แต่ถ้าสิ่งนั้นเป็นสิ่งที่จะทำให้เราอยากทำงานที่นี่ต่อ หรือเป็นสิทธิที่เราพึงได้ ก็สู้เพื่อสิ่งนั้นเถอะ อย่าเกรงใจขนาดนั้นเลย 8. *ทุก ๆ อย่างในการทำงานเป็น trade off ดูดี ๆ ว่าตอนนั้นทีมกำลัง focus อะไรกันอยู่* ในช่วงแรก ๆ ของการทำงาน นิลเป็นคนที่ทำงานไวมาก แต่สุดท้ายมัน trade กับคุณภาพของ code ที่เขียน ในขณะเดียวกัน ตอนนี้นิลทำงานด้วยวิธีที่ใช้เวลาวางแผนเยอะมาก ๆ ข้อเสียคือใช้เวลาวางแผนเยอะ แต่นิลสามารถลด surprise ได้ทั้งหมด ซึ่งทั้ง 2 วิธีนี้ ไม่มีวิธีไหนที่ผิดเลย แต่ถ้าตอนนั้นทีมกำลังเร่ง กำลังรีบ ทุกอย่างต้องรีบทำ การที่นิลใช้เวลาวางแผนนานก็อาจจะไม่ตอบโจทย์ก็ได้ หรือถ้านิล focus คุณภาพดี ๆ การเร่งแบบแรกของนิลก็อาจจะไม่มีประโยชน์ก็ได้ 9. *หน้าที่ของ engineer คือการ deliver solution อย่าทำตัวเป็น blocker ของทีม* ในช่วงแรก ๆ ของการทำงาน project นึง นิลเอา practice ของ software ไปเป็นตัวตั้ง ว่าเราจะไม่ทำสิ่งนี้ ถ้ามันขัด coding standard หรือ software practice ในบางอย่าง ถ้าสิ่งที่ลูกค้าขอไม่ได้ขัดกับสิ่งที่เราตกลงเป็นลายลักษณ์อักษรไว้ เราในฐานะ engineer ก็ควรดัน solution ที่พา user ไปถึง goal มากกว่าจะไปยึด coding standard 10. *การลาออก ก็เหมือนการบอกเลิกความสัมพันธ์* ในวันที่นิลตัดสินใจลาออกและค่อย ๆ เดินไปบอกทีมทีละคน หรือทีละกลุ่ม นิลรู้สึกหนักใจมากครับ ลามไปถึงการนอนไม่หลับเลยแหละ เพราะนิลรู้สึกเหมือนกำลังจะเดินออกจากความสัมพันธ์ที่เราสู้ด้วยกันมา 9 เดือน หรือบางคนก็เจอนิลตั้งแต่นิลเพิ่งเข้า นิลรู้สึกผูกพันกับที่นี่มากเลยครับ และการตัดสินใจนี้ไม่ใช่เรื่องง่ายสำหรับนิลเลย ;-; --- จบไปแล้วนะครับ ทั้ง blog ทั้ง journey ของนิลที่ Skooldio อย่างที่บอกเลยว่าเป็น 4 ปีที่ครบรสมาก ๆ ยังมีหลาย ๆ อย่างที่อยากทำที่นี่ แต่ก็ด้วยโอกาสและเวลา นิลก็อาจจะต้องไปต่อละครับ ขอบคุณ Skooldio รวมถึงเพื่อน ๆ พี่ ๆ น้อง ๆ ที่บริษัทด้วยครับ ทุกคนน่ารักกับนิลมาก ถ้าเจอกันตามงาน meetup หรือ conference ก็ทักกันด้วยน้าา 🤣 ส่วน journey ถัดไปนิลจะไปทำที่ไหนต่อ รอติดตามได้เลยครับ ขอบคุณทุก ๆ คนที่อ่านมาถึงตรงนี้ครับ นิล --- # วัดผล AI Code Reviewer ด้วยการทำ Evaluation แบบ LLM-as-a-Judge - URL: https://blog.ninprd.com/blog/holiday-hack-evaluate-ai-code-review-agent-with-llm-as-a-judge/ - Published: 2026-05-04 - Tags: ai, eval, code-review, dev, Y2026, holiday-hack, evalite, llm-as-a-judge - Summary: นิลทดสอบ AI code review agent ด้วยการทำ evaluation แบบ LLM-as-a-Judge โดยใช้ library Evalite พร้อมเปรียบเทียบ judge model 2 เจ้า และวัดผลด้วย Issue Coverage กับ False Positive Rate สวัสดีครับ ในช่วงวันหยุดแบบนี้ นิลจะมาทำภาคต่อของเจ้า [Holiday Hack รอบที่แล้ว](holiday-hack-code-review-agent-typescript-glm.md) ซึ่งเป็นเจ้า code review agent ที่นิลลองไปทำใน [repository scrum-poker ของนิล](https://github.com/peeranat-dan/scrum-poker)นะครับ (ขายของอีกรอบ 5555) ถ้าใครยังไม่ได้อ่าน [สามารถกลับไปอ่านได้ที่ลิงก์นี้เลยครับ](holiday-hack-code-review-agent-typescript-glm.md) อะ ซึ่งรอบที่แล้ว เราได้ว่า code review agent ของนิลสามารถ catch issue ได้ 4 ใน 5 issues (80%) ที่นิลตั้งธงไว้ครับ ส่วนภาคต่อวันนี้นิลจะทำอะไรมาดูกันครับ เท้าความนิดนึง รอบที่แล้วนิลทำ AI code review agent ไป 1 ทีโดยนั่งปรับ Prompt เพิ่ม Context งก ๆ ไปเรื่อย ๆ ในหลาย iteration รอบนี้นิลอยากวัดผลจากสิ่งที่ทำไป ด้วยการทำสิ่งที่เรียกว่า evals ครับ อะ ถ้าใครงงคำว่า evals เดี๋ยวนิลอธิบายให้ฟัง 1 ทีครับ ## Evals (Evaluation) คืออะไร? อะ ถ้าพูดถึง concept ของการทำ evals หรือที่เราจะเรียกเต็มยศว่า evaluation เนี่ย เราอาจจะต้องถอยมาที่การพัฒนา software ทั่วไปครับ ว่าปกติแล้ว เวลาเราเขียน code กันเนี่ย ถ้าเราอยากเช็คว่า function นั้น ๆ มีการทำงานถูกต้องไหม เราก็จะใช้ unit test เป็นตัวบอกใช่ไหมล่ะครับ และถ้าเราอยากทดสอบการทำงานของระบบที่เชื่อมต่อกันล่ะ สิ่งนั้นก็ถูกตอบด้วยผลลัพธ์ของ integration testing ครับ และสุดท้ายคือถ้าเราอยากทดสอบ flow การทำงานของเว็บล่ะ เราก็จะใช้ end-to-end testing เพื่อตอบว่าระบบยังทำงานด้วย flow ที่เรากำหนดได้อยู่ แล้วสำหรับพวก AI application ล่ะ เราจะเช็คอะไรกันล่ะ นั่นสิครับ ผิด ๆ เราจะ set metric ต่าง ๆ ที่เกี่ยวข้องกับ LLM เช่น accuracy toxicity และ hallucination และดูว่า AI application ของเราตอบมาถึงเกณฑ์ที่เรากำหนดไว้ไหม ซึ่งเราเรียกการทำแบบนี้ว่าการทำ AI evaluation (evals) ## แล้วเราทำ evals กับอะไรได้บ้าง บอกเลยว่าจริง ๆ เราทำ evaluation ได้ทั้งกับของที่ยังไม่ deploy เพื่อให้เรามั่นใจคุณภาพก่อนเอาไปใช้จริงได้ครับ สิ่งนี้เรียกว่า pre-deployment evaluation ส่วนเมื่อเรา deploy ตัว AI agent ของเราไปซักพักแล้วเกิดข้อมูลการใช้งานจริงแล้วเราอยากมาดูว่าการทำงานของ agent มัน perform เป็นยังไงบ้าง เพื่อเอาไปปรับตัว agent ของเราต่อไป อันนั้นเราจะเรียกว่า post-deployment evaluation ครับ ซึ่งอย่างที่เขียนไปว่ามันมีเป้าประสงค์การใช้งานที่ต่างกัน ## แล้วทำ evals ไป ใครจะบอกว่า output ผิดหรือถูก? จริง ๆ ที่นิลทำไปเมื่อ blog ที่แล้วอะครับ ที่นิลนั่งติ๊ก ✅ กับ ❌ ในการเจอแต่ละ issue เนี่ย อันนี้ก็ถือว่านิลเป็นคนบอกแล้วใช่ไหมล่ะครับว่า output มันผิดหรือถูก ซึ่งในโลกของการทำ evals เนี่ย ก็มีวิธีเช็คหลัก ๆ 2 แบบคือ 1. **Human Expert:** ให้บุคคลที่เป็นผู้เชี่ยวชาญใน field นั้น ๆ มานั่งดูว่า output ของ AI ตรงกับที่อยากได้ไหม คล้าย ๆ กับ blog ที่แล้วของนิลที่นิลมานั่งดูผลลัพธ์ของ AI แบบตาแตก 😵‍💫 ซึ่งก็จะมีข้อดีที่ความแม่นยำแต่ข้อเสียหลัก ๆ เลยคือ scale ไม่ได้ 2. **LLM-as-a-Judge:** ให้ LLM อีกเจ้าหรืออีก Model นึงมานั่งตรวจ โดยส่ง prompt และ expected output ให้มัน โดยมันจะคืนกลับมาเป็น score ซึ่งเราก็สามารถให้ metric ได้ว่าเราอยากให้มันคืนกลับมาเป็นคะแนนในแง่มุมไหน เช่น accurate ไหม ไรงี้ ซึ่งข้อดีก็คือ automate ได้ แต่ข้อเสียคือเราอาจจะเจอ bias ของ LLM model ตัวที่ใช้ judge ครับ ## แล้ววันนี้นิลจะทำอะไรบ้าง อย่างแรกเลยคือนิลจะทำ pre-deployment evals ครับ เพื่อให้นิลรู้ว่าเจ้า AI code review ของนิลมัน perform ยังไงนะครับ โดยสิ่งที่นิลต้องเตรียมคือ ground truth หรือ source of truth ว่าสิ่ง input และ output ที่นิล ในฐานะ human expert ต้องการ หน้าตาเป็นยังไงครับ จากนั้น นิลจะต้องไป setup การทำ evaluation ใน project เดิมที่นิลเคยทำแหละ ซึ่งการทำ evals วันนี้นิลเลือกเป็น LLM-as-a-Judge เพราะรอบที่แล้วนิลทำแบบ human expert ไปแล้วยังไงล่า แล้วนิลจะทำด้วย library ชื่อว่า [Evalite](https://evalite.dev/) ของ [Matt Pocock](https://x.com/mattpocockuk) น่ะครับ เพราะเป็น library ที่เป็นภาษา TypeScript และสร้างมา on top library ที่มีชื่อว่า [Vitest](https://vitest.dev/) ที่นิลใช้งานอยู่แล้วครับ โดย metric ที่นิลจะ run วันนี้ก็จะมี 2 ตัวหลัก ๆ ตามนี้ 1. **Issue Coverage**: AI เจอกี่ issue จากที่ตั้งไว้ ซึ่งสิ่งนี้คือสิ่งที่นิลทำใน Holiday Hack รอบที่แล้ว แต่รอบนี้นิลมาทำแบบ automate ครับ ซึ่งในรอบนี้นิลขอขยายจาก 5 issues เป็น 9 issues เพราะนิลอยากรู้ว่าจาก 9 potential issues มัน catch ได้เท่าไหร่กันแน่ (ซึ่งเดี๋ยวมีเทียบกับ 5 issues รอบที่แล้วให้เห็นด้วยครับ) 2. **False Positive Rate:** AI report issue ที่ไม่มีอยู่จริงเยอะแค่ไหน ซึ่งจริง ๆ ในรอบที่แล้วนิลก็ทำไปแล้วเหมือนกัน รอบนี้นิลมาลอง automate ดูครับ สุดท้าย ๆๆ ตัว model ที่นิลจะเอามาทำ evals คือ openai/gpt-oss-120b ซึ่งนิลใช้ฟรีจาก [OpenRouter](https://openrouter.ai/) ครับ ที่นิลเลือก model นี้เพราะมันฟรีและมันเป็นของ OpenAI ดังนั้นมันน่าจะ support พวก lib ของ OpenAI ที่นิลใช้อยู่ในการทดลองนี้ครับ ซึ่งถ้าเรามองภาพทั้งหมดแล้ววันนี้เราจะมาทำสิ่งนี้กันครับ ![ai evals visualized](assets/holiday-hack-evals-visualized.webp) ## เริ่มสร้าง Ground Truth กัน ซึ่งเมื่อจะ setup ground truth นิลก็ต้อง setup จากผลลัพธ์การทดลองครั้งที่แล้วครับ ซึ่งนิลขอยกตารางจากรอบที่แล้วมาแล้วเติม category ว่าเป็น bug ประเภทไหน รวมถึงเพิ่ม severity ว่าบัคนี้รุนแรงแค่ไหนด้วยครับ | Issue | Category | Severity | | ----------------------------------------- | ------------ | -------- | | Query เปลือง (spectator filter) | Performance | Medium | | Handle ชื่อซ้ำ | Functional | High | | xlsx bundle size | Performance | Medium | | สิทธิ์ admin เห็น sidebar เพิ่ม | Security | High | | Firestore Indexes | Convention | High | | N+1 query pattern | Performance | High | | T-shirt session data not mapped correctly | Functional | Medium | | Handle vote value (-1 หรือ -2) | Edge Case | Medium | | มี browser side-effect ใน service | Code Pattern | Low | ซึ่งทุกคนอาจจะถามว่าแล้วตารางนี้จะ turn ไปเป็น ground truth ได้ยังไง นิลตอบเลยว่า ก็นี่แหละ ground truth ที่เรากำลังตามหาครับ 😎 หลัก ๆ มันคือข้อเท็จจริงที่เราจะเอาไป validate กับผลลัพธ์ครับ ## Setup Codebase + Evalite อย่างที่บอกไปว่านิลจะใช้ Evalite ดังนั้นนิลก็เปิด docs แล้วก็ลุยเลยครับ อย่างแรกเลยคือนิลรู้ว่าเดี๋ยวเราต้องเรียกตัว code review ในการทำ evals แน่ ๆ นิลเลยเลือกจะ refactor code review function ก่อนครับ จากที่นิล refactor ตัว code review function ออกมาแล้ว นิลต้องไป setup scorer ก่อนครับ scorer คือตัวตรวจคะแนนซึ่งจะสอดคล้องกับ metric ที่เรา set มาตอนแรกครับ ซึ่งก็คือ issue coverage กับ false positive rate ครับ หลักการง่าย ๆ ของการสร้าง scorer คือให้สร้าง prompt อีกชุดนึงให้ LLM review โดยบอก role และให้มัน structured output แบบที่เราอยากได้ออกมา ซึ่งใน score ของนิลที่ทำ issue coverage นิลจะมี ground truth issue ทั้งหมดและวัดกับ output ที่ AI ดักได้ ซึ่งเมื่อเอา issue ที่ดักได้จาก list ที่กำหนด นิลก็จะรู้ว่ามันดักได้กี่ issue จากทั้งหมดครับ ส่วน false positive rate นิลวัดจากเอา issue ทั้งหมดที่มัน report มากับ issue ทั้งหมดที่เรารู้มาเพื่อดูว่ามัน report ของที่ false positive ไปกี่อันครับ ซึ่งเดี๋ยวนิลจะแปะ code ของทั้ง 2 scorer ไว้ใน repository นะครับ เผื่อให้ทุกคนไปอ่านกันได้ อีกอันที่นิลต้องตัดสินใจคือเรื่อง scoring scale ครับ จริง ๆ แล้วการทำ evals เราสามารถเลือกได้ว่าจะวัดผลแบบ binary (ถูก/ผิด) หรือจะใช้ Likert Scale แบบ 1-5 คะแนนแบบที่เราเห็นในแบบประเมินทั่วไปก็ได้ แต่สำหรับ blog นี้นิลเลือกใช้ binary (✅/❌) ครับ เพราะ issue มันมีอยู่จริงหรือไม่มี ไม่มีกึ่งกลาง ยิ่งถ้าใช้ 1-5 เราก็ต้องมาตีความกันอีกว่า "เจอ issue นี้ได้ 2 คะแนน" หรือ "ได้ 4 คะแนน" แปลว่าอะไรกันแน่ ซึ่งมันเพิ่มความกำกวมและซับซ้อนโดยไม่จำเป็นครับ ซึ่งปลายทางแล้วตัว Evalite code ที่เป็นการทดสอบจะเหลือแค่นี้ครับ ```ts wrap evalite("Code Review Quality", { data: [ { input: diffContent, expected: expectedIssues, }, ], task: async (input): Promise => { return callAIReviewer(input); }, scorers: [IssueCoverage, FalsePositiveRate], }); ``` > ⚠️ ก่อนจะไปถึงผลลัพธ์ อยากแทรกตรงนี้ก่อนนิลเจอปัญหาของ openrouter model เรื่องการทำ structured output หนักมากเลยครับ นิลใช้เวลานั่ง retry ผลนานมาก กว่ามันจะออกมาอย่างที่นิล expect ไว้น่ะครับ ซึ่งถ้าใครเล็งจะใช้ free model ก็อาจจะต้องระวังเรื่องนี้ด้วยนะครับ ถ้าถามว่านิลแก้ไง นิลแก้ด้วยการนั่ง spam ไปเรื่อย ๆ ครับ 5555555555 ## Evals ด้วย gpt-oss-120b ### AI review output (reviewer: GLM 5.1) ```md wrap "General settings tab now visible to admins, potentially exposing the owner‑only SessionTerminationButton" "Duplicate participant names are not handled with uid suffixes in the Excel header as required" "Export service suffers from an N+1 query by fetching votes separately for each round" "Potential missing Firestore composite index for the rounds query (sessionId, status, createdAt)" "Bundle size increase due to importing the entire xlsx library without lazy loading" ``` ### Issue Coverage | Issue | Catch? | Rationale | | ----------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- | | Query เปลือง (spectator filter) | ❌ | The AI review does not mention a missing spectator filter or an expensive query related to it. | | Handle ชื่อซ้ำ | ✅ | The AI review explicitly states that duplicate participant names are not handled. | | xlsx bundle size | ✅ | The AI review notes a bundle size increase due to importing the entire xlsx library. | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | The AI review flags that a general settings tab is now visible to admins, implying extra UI exposure. | | Firestore Indexes | ✅ | The AI review mentions a potential missing Firestore composite index for the rounds query. | | N+1 query pattern | ✅ | The AI review describes an N+1 query pattern in the export service. | | T-shirt session data not mapped correctly | ❌ | The AI review does not discuss T‑shirt session data mapping. | | Handle vote value (-1 หรือ -2) | ❌ | The AI review does not mention handling of negative vote values. | | มี browser side-effect ใน service | ❌ | The AI review does not reference any browser side-effect inside a service. | Total Issue Coverage: ***56%*** ### False Positive Rate | Issue | False Positive? | Rationale | | ------------------------------- | --------------- | ---------------------------------------------------------------------------------------------- | | สิทธิ์ admin เห็น sidebar เพิ่ม | ❌ | This matches the known Security/High issue where admins can see sidebar items they should not. | | Handle ชื่อซ้ำ | ❌ | Corresponds to the known Functional/High duplicate name handling issue. | | N+1 query | ❌ | Matches the known Performance/High N+1 query pattern causing redundant reads. | | Firestore Indexes | ❌ | Same as the known Convention/High missing Firestore indexes definition issue. | | xlsx bundle size | ❌ | Identical to the known Performance/Medium issue about the xlsx library increasing bundle size. | False Positive Rate: **0%** > "ตัวเลขนี้ดูดีมาก แต่เดี๋ยวไปเจอกันที่สรุปผลนะครับว่ามันหมายความว่าอะไรจริง ๆ" ทีนี้นิลขอลองใช้ LLM อีกเจ้าในการทำ evals นิลอยากลอง run อีก 1 ทีเพราะนิลอยากรู้ว่าถ้าเปลี่ยน model ในการ judge จะได้ผลลัพธ์ต่างกันไหม ซึ่ง model ที่นิลเลือกมานั่นก็คือ kimi-k2.6 ครับ เพราะอะไรน่ะหรือ เพราะนิลติด rate limit ของ OpenRouter แล้วยังไงล่ะ 555555 แล้วก็ Kimi ก็เป็น model ที่ค่อนข้างเก่งและ claim ว่าตัวเองสูสีกับ Opus 4.6 ด้วยแหละครับ ขอญาตแปะ benchmark 1 ทีครับ ![](assets/kimi-k2-6-benchmark.webp) ซึ่งใน run นี้ GLM 5.1 ยังเป็นตัว reviewer เหมือนเดิมนะครับ เปลี่ยนแค่ judge model อย่างเดียว ## Evals ด้วย kimi-k2.6 ### AI review output (reviewer: GLM 5.1) ```md wrap "Missing duplicate participant name deduplication; UIDs not appended to duplicate display names as required by AC" "Missing validation for illegal Excel characters in generated worksheet names" "T-shirt vote values exported as raw numbers instead of human-readable labels like XS, S, or M" "N+1 query pattern fetching votes per-round instead of batching with an in-operator query on round IDs" "Missing required Firestore composite index for querying rounds by sessionId, status, and createdAt" "Browser download side effect inside the service function makes it untestable and couples logic to browser APIs" "Unit tests do not cover t-shirt sizing value mapping in exported workbooks" ``` ### Issue Coverage | Issue | Catch? | Rationale | | ----------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------- | | Query เปลือง (spectator filter) | ❌ | The AI discussed an N+1 query and a missing composite index but never mentioned a missing spectator filter. | | Handle ชื่อซ้ำ | ✅ | The AI explicitly noted missing duplicate participant name deduplication and that UIDs are not appended to duplicate display names. | | xlsx bundle size | ❌ | The AI mentioned Excel worksheet validation and exports but did not mention bundle size concerns for the xlsx library. | | สิทธิ์ admin เห็น sidebar เพิ่ม | ❌ | The AI review did not mention admin roles, sidebar items, or related security issues. | | Firestore Indexes | ✅ | The AI called out a missing required Firestore composite index for querying rounds. | | N+1 query pattern | ✅ | The AI explicitly identified the N+1 query pattern and suggested batching with an in-operator query. | | T-shirt session data not mapped correctly | ✅ | The AI noted t-shirt vote values are exported as raw numbers instead of human-readable labels and mentioned value mapping. | | Handle vote value (-1 หรือ -2) | ❌ | The AI discussed raw number exports but never mentioned handling edge case vote values like -1 or -2. | | มี browser side-effect ใน service | ✅ | The AI explicitly flagged a browser download side effect inside the service function as untestable and coupled to browser APIs. | Total Issue Coverage: ***56%*** (เท่าเดิม แต่เจอคนละปัญหากัน) ### False Positive Rate | Issue | False Positive? | Rationale | | ---------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | Handle ชื่อซ้ำ | ❌ | This issue describes the known Functional/High duplicate name handling bug by specifying that deduplication and UID appending are missing. | | Validate illegal excel character in worksheet name | ✅ | None of the known issues mention worksheet name validation or illegal Excel characters, making this an unrelated concern. | | T-shirt vote value mapping | ❌ | Exporting raw numbers instead of human-readable labels is a concrete instance of the known Functional/Medium t-shirt session data mapping issue. | | N+1 query | ❌ | This is a direct description of the known Performance/High N+1 query pattern issue, only with additional technical detail. | | Firestore Indexes | ❌ | This specifies the exact missing Firestore composite index, which is a reasonable variant of the known Convention/High missing indexes definition issue. | | browser side effect | ❌ | This directly restates the known Code Pattern/Low issue regarding browser side effects inside a service function. | | Unit tests do not cover t-shirt sizing value mapping | ✅ | The known list identifies a functional data mapping bug rather than a test coverage deficiency, so this is not a known or variant issue. | False Positive Rate: **17%** (น่าสนใจจ ไว้เจอกันที่สรุปผล) ซึ่งนิลลืมแคปผลของ run 1 มา ขอแก้ตัวที่ run 2 ครับ (แปะรูป Evalite หน่อย เผื่อใครอยากเห็น dashboard ของ Evalite 555555) ![](assets/evalite-code-review-example.webp) เอาล่ะ ความสนุกอยู่ตรงที่การสรุปผลแล้วววว ## สรุปผลกัน 1 ที จากการลอง evals ครั้งแรก นิลพบว่าถ้าเราเทียบ 5 issues เดิมที่เราเคยติ๊กถูกไปเมื่อรอบที่แล้ว รอบนี้ก็ยังติ๊กถูก 4 จาก 5 อันเดิมนะ ซึ่งที่เลขมันน้อยลงเพราะนิลเพิ่ม issue มาอีก 4 อัน มันเลยลดจาก 80% เหลือ 56% ครับ ซึ่งในการ run evals แรกอนาคตก็ดูสดใสมากครับ ทีนี้พอมาใน evals run ที่ 2 ที่เราลองเปลี่ยน model ในการ evals นิลกลับเจอว่าตัว AI code review ของนิลตอบ issue ได้ไม่เหมือนเดิมซะงั้น แต่ก็ยังคง issue coverage ที่ 56% เพราะไปเจอ issue ตัวล่าง ๆ แทน แปลว่าจริง ๆ แล้วตัว code review agent ของนิลก็ยังไม่เสถียรขนาดนั้นเหมือนกันครับ ซึ่งก็เป็นปกติของ LLM แหละที่แม้ prompt ตั้งต้นจะเหมือนกัน แต่ output ที่ออกมาอาจจะเหมือนหรือไม่เหมือนกันก็ได้ ส่วน false positive rate ที่ AI ให้มาเนี่ย ตอน run แรกนิลก็แอบยิ้มแล้วครับ แต่พอมาดูผลลัพธ์อีกที ground truth ของนิลอาจจะยังไม่มากพอ ไม่ครอบคลุมพอด้วยครับ และพอ run evals ครั้งที่ 2 นิลก็ค้นพบว่าจริง ๆ issue ที่มัน flag มาเป็น false positive เนี่ย จริง ๆ เป็น issue ที่ valid หมดเลยนะครับ นิลว่าอันนี้เป็นที่ ground truth ของนิลไม่แน่นพอจริง ๆ ทำให้ตัว LLM report issue ที่ valid เป็น false positive ครับ ## Step ต่อไปคืออะไร? จากที่เห็นตอนนี้นิลจะยังทำได้แค่ทีละ 1 PR อยู่ แปลว่าถ้านิลเอา PR อื่น ๆ มา review มันอาจจะไม่ได้ผลลัพธ์ได้เท่ากับ PR ที่นิลเตรียมไว้ครับ ทีนี้นิลกำลังเล็งการทำให้ตัว AI agent นี้มัน general มากขึ้นอยู่ ซึ่งเดี๋ยวในรอบหน้านิลจะลองสร้าง workflow ต่อ เดี๋ยวขอไปสำรวจก่อนว่าตัวอื่น ๆ ในตลาดทำยังไง (เพื่อจะ steal like an artist 😎) หยอกครับ นิลอยากรู้ว่าเจ้าอื่น ๆ ในตลาดเขาทำยังไง นิลจะได้เอามาปรับตัว agent ของนิลให้มันทำงานได้ effective มากขึ้นครับ อีกอันที่นิลเจอระหว่างทางคือความสับสนว่า เราควร structure repository นี้ยังไงดี เพราะตอนแรกนิลวาง repository แบบ Proof of Concept (PoC) มาก ๆ พอนิลอยากจะ scale นิลก็ต้องมา refactor นู่นนี่นั่น ยิ่งที่ชัดสุดเลยคือตัวการ reuse AI model ข้ามแต่ละ module ที่ดูจะแอบต้อง duplicate code หรือการที่ต้อง declare model ที่เราใช้แยกแต่ละที่ที่เราใช้ก็ดูที่จะมีปัญหาเรื่องการ maintain code อยู่เหมือนกัน รอบหน้านิลอาจจะต้องลองเปลี่ยนไปใช้พวก framework ต่าง ๆ เช่น Mastra หรือ Voltagent เพื่อทำให้ code เป็นระเบียบมากขึ้น และเพิ่มความเป็นระเบียบให้กับ code แหละ แต่ไว้ว่ากันคราวหน้า คราวนี้นิลได้ผลการทดลองมาล้า 555555 คราวหน้าอาจจะต้องเริ่มใช้ framework มั่งละะ 😎 --- จบไปแล้วนะครับกับ Holiday Hack เรื่องการทำ evaluation จริง ๆ evaluation ก็ไม่ได้ยากอย่างที่คิดกันใช่ไหมล่ะครับ แอะ จริง ๆ ยากครับ มันต้องใช้ resource ของ human expert ค่อนข้างเยอะเลย ในการสร้าง ground truth ขึ้นมา ซึ่ง eval ของนิลก็เป็นแค่การ transform manual review มาเป็น automation เฉย ๆ ถ้าทำจริง ๆ ยังมีขั้นตอนอีกเยอะเลยครับ ซึ่งก็ไว้ explore กันต่อครับ รอบนี้นิลทำเสร็จแล้วก็โดดลงไปแช่ onsen ละสั่ง soft serve ชาเขียว 1 อัน (คิดกับตัวเองว่าตรูออกกำลังกายไปทำไมฟระ 5555555) ขอให้ทุกคนสนุกกับการทำ evaluation ครับ นิล ## Links used in this experiments - [Evaluation codebase](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript/tree/setup-evals-experiment) - [Evaluation scorer and evals file](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript/blob/setup-evals-experiment/src/evals/code-review.eval.ts) - [Previous Holiday Hack](holiday-hack-code-review-agent-typescript-glm.md) --- # Holiday Hack: ลอง Iterate Code Review Agent ด้วย TypeScript และ GLM 5.1 - URL: https://blog.ninprd.com/blog/holiday-hack-code-review-agent-typescript-glm/ - Published: 2026-04-16 - Tags: weekend-hack, holiday-hack, ai, dev, Y2026, typescript, code-review - Summary: นิลลอง iterate ตัว AI Code Review Agent ที่ไม่ work จากรอบก่อน โดยค่อย ๆ เพิ่ม Context ให้ GLM 5.1 ทีละ iteration จนมัน catch potential issue ได้ 80% มาดูกันว่านิลได้เรียนรู้อะไรบ้าง > "หยุดยาว 3 วันไม่รู้จะทำอะไรดี" ในช่วงสงกรานต์แต่ละปีนิลก็จะนั่งทำอะไรเล่น ๆ ไปเรื่อย ๆ ครับ เช่น ปีที่แล้วก็ทำตัว [Scrum poker ที่ชื่อว่า E-Mate](https://e-mate.ninprd.com/) ขึ้นมา (แปะลิงก์เผื่อเพื่อน ๆ ไปลองใช้ดูนะค้าบ 555555) แต่ปีนี้งานแอบเข้ามาเยอะมากเลยจนนิลรู้สึกว่า ทำไรดีวะ ทีนี้นิลก็ย้อนตัวเองกลับไปถึงวีคที่นิลทำตัว [Weekend Hack รอบที่แล้วที่เป็น Code Review Workflow และทำ PR Label ครับ](weekend-hack-solving-medium-large-pull-request-review.md) ซึ่งนิลมองว่ามันยังมี Improvement ที่ทำได้อยู่ นิลเลยหยิบมาทำเลยล้ากัน ซึ่งโจทย์ในตอนนั้นคือนิลอยากสามารถ skim pull request (PR) ไว ๆ โดยให้ AI ซักตัวนึงช่วย review system impact/flaws ใช่ไหมครับ ทีนี้ผลลัพธ์ของนิลรอบที่แล้วคือมันไม่ work เนอะ ซึ่งใน Holiday Hack รอบนี้แหละ เราจะมาเจาะลึกมากขึ้น หาเหตุผลที่มันไม่ work แล้วเราจะทำให้มัน work ขึ้นกันครับ 5555555 ซึ่งในแต่ละ step จะมาจากการที่นิล take notes และ iterate จริง ๆ เลยนะครับ รวมถึง decision ของนิลในแต่ละ iteration ด้วยครับ สิ่งที่นิลกำลังจะเขียนต่อไปนี้นิลคาดหวังว่าจะใช้เวลาไม่เกิน 3 วันในช่วงสงกรานต์ครับ ซึ่ง goal ของนิลคือ - อยากลองเล่น AI with TypeScript ดู - อยากเข้าใจ agent architecture มากขึ้น ว่าการวาง AI agent 1 ตัวและคาดหวังให้มันทำทุกอย่างจะรอดไหม และถ้าไม่รอด เราจะ scale มันไปท่าไหนดีเพื่อให้มันรอดตาม Task ที่เราคาดหวังไว้ - อยากได้ iteration ถัดไปของ code review agent ว่ามันจะช่วยนิลได้มากน้อยแค่ไหน ## มา Setup การทดลองกัน ซึ่งในรอบนี้นิลจะใช้ปัจจัยควบคุม 2 อย่างคือ git diff ของ PR ที่นิลทำใน repo เจ้า Scrum poker และ LLM Model เป็น [GLM 5.1](https://z.ai/) ครับ เพราะนิลได้ยินพี่ที่ออฟฟิศขายหนักมาก ประกอบกับช่วงนี้ก็เห็นกระแสค่อนข้างกลับมาอยู่ นิลเลยลองตัว z.ai Coding Plan Lite ดูครับ อีกเหตุผลนึงที่นิลเลือกตัว GLM คือนิลได้ยินชื่อเสียงจากพี่ [Katopz](https://www.facebook.com/katopz/) และพี่ [Piyalitt](https://www.facebook.com/piyalitt) มาครับ ว่า GLM นั้น เก่งเรื่อง coding มาก ซึ่งในช่วงนี้ก็มี [GLM 5.1 ออกมาพอดี ซึ่งก็ Claim ว่าตัวเองเก่งเทียบเท่ากับ Claude Opus 4.6](https://z.ai/blog/glm-5.1) ในราคาที่ถูกกว่ากันเกือบ 3 เท่าอีก ทำให้นิลสนใจที่จะลองตัว GLM ครับ ตัว PR ที่นิลจะเอามาใช้ประกอบบทความวันนี้คือ [PR นี้](https://github.com/peeranat-dan/scrum-poker/pull/290)ครับ เป็น PR ที่เพิ่ม feature การ export การ vote ของทุกรอบใน Scrum poker ของนิลครับ ซึ่งนิลก็ให้ AI generate ออกมาแบบติด bug นิดนึงนะครับ potential issues ที่ควรจับได้ของ PR นี้คือ - การ query ข้อมูล: ตอนนี้นิลดึงข้อมูลด้วยการ query participant ทุกคนที่อยู่ใน session นั้น ๆ อยู่ แล้วมา filter หน้าบ้านให้เอา spectator ออก ซึ่ง**เปลืองครับ** สู้ query ออกตั้งแต่ตอนดึงข้อมูลดีกว่า - การ handle ชื่อคนซ้ำ: ตอนนี้ตัว function ที่ใช้ map หัวตาราง ไม่ได้ handle ไว้ว่าถ้าชื่อซ้ำแล้วจะแสดงผลยังไง ซึ่งมีโอกาสที่คนจะชื่อซ้ำในตารางแล้วเราไม่สามารถแยกออกได้ว่าคน ๆ นั้นคือใคร - การใช้ xlsx: xlsx เป็น library ที่มี dependency ที่สร้าง bundle size ที่ใหญ่ซึ่งแอบไม่เหมาะกับงาน frontend มาก ๆ - เรื่องสิทธิ์: AI ควร detect ว่ามีการเพิ่มสิทธิ์ admin ที่ menu แล้วบอกคน review ว่าลองเช็คตรงนี้ดูดี ๆ - Firestore indexes: PR นี้มีการ query ของที่มีการ sorting อยู่ แต่ใน PR นี้ ไม่ได้มีการ push file `firestore.indexes.json` มาด้วย ซึ่งนิล expect ให้ AI ช่วยเตือนส่วนนี้ได้จะดีมากครับ ซึ่ง metric นึงที่นิลใช้วัดคือตัว AI สามารถ catch issue ได้เยอะแค่ไหน และสามารถแนะนำจุดที่มีโอกาสเป็น system impact ได้เยอะแค่ไหนครับ ส่วนด้าน code นิลก็สร้าง TypeScript Project อันนึงโล่ง ๆ มาครับแล้วก็ใช้ npm package [openai](https://github.com/openai/openai-node) มาครับ โดยนิลจะแยก file `prompt.md` กับ `diff.txt` ไว้ครับ เพื่อให้เราสามารถแก้ prompt ได้โดยแยกจากการทำงานหลักของ application function ครับ อะพอเราได้ละว่าเรา setup ยังไงบ้าง เดี๋ยวเราไปลุยกันเลยครับ > NOTE: นิลแปะ full response กับตัว reasoning content แยกออกมาไว้ใน accordion เพื่อให้บทความลื่นไหลขึ้นนะครับ เพื่อน ๆ สามารถกางตัว accordion เพื่ออ่านได้เลยครับ ## Iteration 0: Analyze git diff ใน iteration 0 นิลเอา setup เดิมที่ไม่ work ใน n8n port มาลงที่ TypeScript แล้วมา run แบบ local ครับ ซึ่งใน iteration แรก นี่คือ ### Prompt used ```markdown wrap You are a senior software engineer reviewing a PR for the engineering team. The user will provide the git diff of the PR, and you will analyze the changes and provide a structured review summary in the following format: ## Summary What this PR does in 2-3 sentences. ## Files Changed Key files and their roles. Be extremely concise. ## System Impact Which system components are affected and how. ## Risk Areas Potential breaking changes or side effects. If none, say "None identified." ## Suggested Focus Where reviewers should pay most attention. Sacrifice grammar for the sake of concision. Use bullet points, not paragraphs. ``` ### Output #### Token Usage ```yaml completion_tokens: 692 - reasoning_tokens: 43 prompt_tokens: 7199 total_tokens: 7891 ```
AI Output ```markdown wrap ## Summary Adds an "Export votes" feature that lets session owners and admins download all voting data as an `.xlsx` file. Also grants admins access to the General settings menu where the export button lives. ## Files Changed - **`package.json` / `pnpm-lock.yaml`** — Adds `xlsx@0.18.5` dependency - **`game-settings-modal.tsx`** — Adds `'admin'` to General settings menu roles - **`general-settings.tsx`** — Adds "Export" section with `SessionExportButton` - **`session-export-button.tsx`** — New: button component triggering export mutation - **`use-export-session-votes.ts`** — New: TanStack Query mutation hook - **`export-session-votes.ts`** — New: orchestrates data fetching, workbook build, and file download - **`build-votes-workbook.ts`** — New: pure function constructing the XLSX workbook from domain data - **`build-votes-workbook.test.ts`** — New: 7 unit tests for workbook builder - **`index.ts`** — New: barrel export for xlsx lib ## System Impact - **Permissions**: Admins now see General settings (was owner-only). This exposes Session Termination to admins as well — confirm this is intentional. - **Data access**: `checkIfUserCanManageSession` gates the export; spectators cannot export. - **Bundle size**: `xlsx` is ~900KB unminified; adds significant client-side weight since `XLSX.writeFile` includes file-writing logic that wouldn't tree-shake. - **Network**: Export fetches all rounds + all votes per round sequentially via `Promise.all` — could be heavy for sessions with many rounds. ## Risk Areas - **Admin now sees "Danger Zone" / Session Termination** via the General settings role change. This may be unintended scope creep beyond export access. - **`xlsx@0.18.5`**: This is the last free version of SheetJS Community Edition. It's a large dependency; consider whether server-side export or a lighter alternative (e.g., generating CSV) would suffice. - **N+1 query pattern**: `searchVotes` is called once per round inside `Promise.all`. With many rounds this could be many concurrent reads. - **No `displayName` sanitization**: Participant display names are used directly as headers — could contain characters that confuse Excel or cause formula injection. - **Sheet name truncation** slices at 31 chars with no uniqueness guarantee — two sessions with the same 31-char prefix produce identical sheet names (only one sheet here, so low risk). ## Suggested Focus - **Role change in `game-settings-modal.tsx`**: Verify admins *should* see the entire General tab (including Danger Zone / termination), not just export. - **`build-votes-workbook.ts`**: Correctness of missing-vote handling, spectator filtering, and edge cases. - **Bundle impact of `xlsx`**: Confirm team is okay with the client-side size increase; consider lazy-loading the export path. ```
Reasoning ```md wrap Let me analyze this PR systematically.\n\nThe PR adds an Excel export feature for session voting data. It introduces the `xlsx` library to generate `.xlsx` files containing vote data per round, with participants as columns. ```
### Analysis หลัก ๆ แล้ว ตัว GLM สามารถที่จะ detect ของที่มันเห็นครับ เช่น bundle size ของ lib xlsx, เรื่องสิทธิ์ admin, และ performance issue ที่มันดักได้เพิ่มเติม ทั้งนี้ทั้งนั้น ยังมี issue เช่น เรื่อง Firestore index ที่มันน่าจะไม่รู้ context ของ repository และ issue เช่น การ query เปลือง และการ handle ชื่อซ้ำที่มันยัง identify ไม่ได้ นอกจากนี้นิลอยากรู้ว่ามันคิดอะไรบ้าง นิลเลยดู reasoning content ที่ได้มาจาก response ซึ่งนิลก็เจอสิ่งนี้ครับ ```md wrap Let me analyze this PR systematically.\n\nThe PR adds an Excel export feature for session voting data. It introduces the `xlsx` library to generate `.xlsx` files containing vote data per round, with participants as columns. ``` ซึ่งนิลมองว่ามันยังไม่ค่อยทำ reasoning อะไรเท่าไหร่เลย แล้วมันก็ตอบมาแล้ว ซึ่งอาจจะเป็นหนึ่งในสาเหตุที่มันยังตอบ issue ได้ไม่ครบถ้วนครับ #### Issue ที่นิลคาดหวังให้เจอ | Issue | จับได้ไหม? | Note | | ------------------------------- | ---------- | ---------------------------------------------- | | query เปลือง (spectator filter) | ⚠️ | เจอเรื่อง N+1 Query แทนเรื่อง spectator filter | | handle ชื่อซ้ำ | ❌ | ไม่ได้พูดถึง | | xlsx bundle size | ✅ | จับได้และ suggest ให้ export เป็น csv พอ | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | จับได้และให้นิล reconfirm ตัวเอง | | Firestore indexes | ❌ | ไม่ได้พูดถึง | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Additional Note | | -------------------------------- | ----------- | ------------------------------------------------ | | N+1 query pattern | Performance | น่าสนใจครับ | | display name → formula injection | Security | อันนี้น่าสนใจมาก นิลไม่ได้ expect สิ่งนี้เลยครับ | | sheet name limit ที่ 31 ตัวอักษร | Edge Case | แอบ edge case แต่ก็ดีที่เจอครับ | ### สิ่งที่จะลองใน iteration 1 1. ให้ AI คืน thinking ออกมาด้วย 2. พยายามให้ AI คืน reasoning content ออกมาเพิ่ม ถ้า reasoning content เพิ่มขึ้น นิลคาดว่าจะเห็นได้ว่า model หยุดคิดตรงไหน และนั่นจะบอกได้ว่าต้องเพิ่ม context อะไรใน Iteration ถัดไป โหยยยยย เขียนปุ๊ป รู้สึกเบียวปั๊ปปป 🥷🏼🔥 -- จบ Iteration ที่ 0 -- > NOTE: ระหว่างทางที่ลองนิลรู้สึกว่า GLM มันช้ามากกก ใครกดสั่งอะไรมันไว้ก็สามารถไปทำอะไรอย่างอื่นรอได้ก่อนเลยนะครับ 🥱😴 ## Iteration 1: Force AI to return thinking and reasoning more ใน iteration นี้นิลคิดว่าถ้าเราอยากได้เรื่อง thinking จาก AI เพิ่ม นิลคิดว่าเราน่าจะต้องบอกมันเพิ่มใน prompt นิดนึงครับว่าช่วยคืน thinking กับ reasoning มาให้หน่อย จะได้รู้ว่าเรา model หยุดคิดที่ตรงไหน และเราจะ improve context ที่เราส่งไปต่อยังไงได้บ้าง ### Prompt Used ใน Iteration นี้นิลเพิ่ม part thinking เข้าไปใน prompt เพิ่มครับ ```diff lang="md" wrap You are a senior software engineer reviewing a PR for the engineering team. The user will provide the git diff of the PR, and you will analyze the changes and provide a structured review summary in the following format: +## Thinking +Think step by step. Walk through the diff line by line. For each change, explain: + - What the code does + - Why it might be written that way + - Any concerns, anti-patterns, or edge cases you spot + - What context or files would you want to see to fully understand this change + Do NOT skip this section. Be thorough and detailed. ...existing prompt ``` ### Output #### Token Usage ```yaml completion_tokens: 2425 - reasoning_tokens: 1245 prompt_tokens: 7277 total_tokens: 9702 ```
AI Output ```markdown wrap ## Thinking **package.json / pnpm-lock.yaml** - Adds `xlsx@^0.18.5` (SheetJS community edition) — Apache-2.0 licensed, fine for most use. Pulls in transitive deps (adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word). This is a ~1MB+ addition to the bundle. Worth noting for client-side bundle size. **game-settings-modal.tsx** - Expands "General" menu access from `['owner']` to `['owner', 'admin']`. This means admins now see the entire General tab — including the SessionTerminationButton in Danger Zone. This is a broader permission change than just export. Need to confirm this is intentional. **general-settings.tsx** - Adds new "Export" section between SessionInfo and Danger Zone. Clean, follows existing patterns. **session-export-button.tsx** (new) - Button component with loading state, toast feedback. `useCallback` wrapping is slightly unnecessary since `exportMutation` object is stable from `useMutation`, but harmless. **use-export-session-votes.ts** (new) - Thin TanStack Query mutation wrapper. Clean. **build-votes-workbook.ts** (new) - Pure data→workbook transformation. Filters spectators, builds array-of-arrays grid (Round # | participant names | Average). Handles missing votes with empty string. Truncates sheet name to 31 chars (Excel limit). - Concern: `vote.value` typed as `number`, but planning poker often has non-numeric values ("?", "☕", "∞"). If domain allows these, they'd be excluded or cause issues. - Concern: Sheet name truncation via `.slice(0, 31)` doesn't sanitize invalid Excel sheet name characters (`\ / ? * [ ]`). **build-votes-workbook.test.ts** (new) - Well-structured test suite covering: sheet naming, truncation, header-only, vote filling, missing votes, spectator exclusion, round numbering, null averages. Good coverage. **export-session-votes.ts** (new) - Orchestrator: auth check → parallel fetch (session, participants, rounds) → parallel fetch votes per round → build workbook → `XLSX.writeFile` download. - **Major concern**: N+1-like pattern. Votes are fetched per-round (`Promise.all` over `rounds.map`). A single query filtering by sessionId would be more efficient and avoid O(n) requests. - **Concern**: `XLSX.writeFile` is a browser-side side effect (creates `anchor` element, triggers download) buried inside a service function. This makes the service untestable in isolation and couples it to the browser. Better to return the workbook/buffer and let the caller trigger the download. - Auth via `checkIfUserCanManageSession` — good, called first. Would want to verify this function's implementation. **lib/xlsx/index.ts** (new) - Barrel export. Fine. ## Summary Adds an XLSX export feature for session voting data, allowing owners and admins to download all votes as a `.xlsx` file. Also grants admins access to the General settings tab. The implementation fetches rounds and votes client-side, builds an Excel workbook using SheetJS, and triggers a browser download. ## Files Changed - **package.json** — adds `xlsx` dependency - **game-settings-modal.tsx** — expands General tab access to admins - **general-settings.tsx** — adds Export section with export button - **session-export-button.tsx** — new UI component for triggering export - **use-export-session-votes.ts** — new TanStack Query mutation hook - **export-session-votes.ts** — new service: auth + data fetching + download - **build-votes-workbook.ts** — new pure function: data → XLSX workbook - **build-votes-workbook.test.ts** — unit tests for workbook builder - **lib/xlsx/index.ts** — barrel export ## System Impact - **Auth/permissions**: Admins gain access to General settings (including Danger Zone / session termination). Verify this is intentional. - **Bundle size**: `xlsx` is a heavy client-side dependency (~1MB+ ungzipped). Consider dynamic import if bundle size matters. - **Data layer**: Exercising `searchParticipants`, `searchRounds`, `searchVotes` in a new access pattern (bulk fetch for export). ## Risk Areas - **Admin role expansion** — admins can now see and use the "Danger Zone" (terminate session). Confirm this is desired, not an accidental side effect of the export feature. - **N+1 vote fetching** — one network request per round. For sessions with many rounds, this could be slow or hit rate limits. - **Browser-side side effect in service** — `XLSX.writeFile` inside `exportSessionVotes` couples the service to the browser DOM and prevents server-side testing. - **Non-numeric vote values** — if the domain ever supports string values (e.g., "?", "∞"), `votesByParticipantId` typed as `Record of string, number` will silently drop or misrepresent them. - **Sheet name sanitization** — `.slice(0, 31)` doesn't strip invalid Excel characters (`/ \ ? * [ ]`). ## Suggested Focus - Confirm admin access to Danger Zone is intentional - Refactor vote fetching to a single query per session instead of per-round - Move `XLSX.writeFile` call out of the service to improve testability - Evaluate whether `xlsx` should be dynamically imported to reduce initial bundle size ```
Reasoning ```md wrap Let me walk through this diff carefully. **package.json / pnpm-lock.yaml** - Adding `xlsx@^0.18.5` as a dependency. This is the SheetJS library for reading/writing Excel files. - The lockfile adds several transitive dependencies: adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word — all standard SheetJS dependencies. **game-settings-modal.tsx** - Changed the `role` array for the "General" menu item from `['owner']` to `['owner', 'admin']`. This means admins can now access the General settings tab. **general-settings.tsx** - Added an "Export" section between SessionInformationContainer and Danger Zone - New section contains a `SessionExportButton` component **session-export-button.tsx** (new file) - A button component that triggers vote export - Uses `useExportSessionVotes` mutation hook - Shows loading state with "Exporting..." text - Uses `Download` icon from lucide-react - Toast notifications for success/error **use-export-session-votes.ts** (new file) - Simple TanStack Query mutation wrapper around `exportSessionVotes` service **build-votes-workbook.test.ts** (new file) - Comprehensive test suite for the workbook builder - Tests: sheet naming, truncation to 31 chars, header-only sheets, vote filling, missing votes (empty string), spectator exclusion, sequential round numbering, null averageVote handling **build-votes-workbook.ts** (new file) - Takes session name, participants, and rounds with votes - Filters out spectators - Builds a grid: Round # | participant columns | Average - Uses XLSX.utils.aoa_to_sheet for array-of-arrays construction - Truncates sheet name to 31 chars (Excel limit) **index.ts** (new file) - Barrel export for the xlsx lib module **export-session-votes.ts** (new file) - Orchestrator service function - Checks permissions via `checkIfUserCanManageSession` - Fetches session, participants, rounds (finished/revealed only), and votes - Builds workbook and triggers download via `XLSX.writeFile` Concerns and observations: 1. **Security**: `checkIfUserCanManageSession` is called before data fetch — good. But I'd want to see what that function does to confirm proper auth. 2. **`XLSX.writeFile` in the service layer**: This is a side effect (browser download trigger) happening in a service function. This couples the service to the browser environment. It would be cleaner to have the service return the workbook or buffer, and let the caller (UI or hook) trigger the download. This would also make testing easier. 3. **N+1 query pattern**: `roundsWithVotes` fetches votes for each round sequentially via `Promise.all` — this is parallel but still one query per round. If there are many rounds, this could be a lot of queries. It might be better to fetch all votes for the session at once and group them by round. 4. **The `xlsx` package**: Version 0.18.5 is the community edition. SheetJS has had licensing changes — the newer versions (since 0.20+) moved to a more restrictive license. 0.18.5 is Apache-2.0 licensed which is fine. But the package is somewhat large. 5. **Client-side generation**: All data fetching and XLSX generation happens client-side. For large sessions, this could be slow. The data is fetched round-by-round which compounds the issue. 6. **`vote.value` type**: The code treats `vote.value` as a `number`, but in planning poker, votes can sometimes be strings (e.g., "?", "☕", "∞"). The type says `number` but edge cases might exist. 7. **Sheet name truncation**: Simple `.slice(0, 31)` could result in invalid sheet names if the first 31 chars contain invalid Excel sheet name characters. Also, duplicate sheet names aren't handled but since there's only one sheet, this is fine. 8. **Error handling**: The `onError` callback in the button just shows `error.message`. The service throws for auth failures and missing sessions, which is fine. 9. **`disabled` prop**: The button is disabled while pending — good UX. 10. **The mutation's `mutationFn` returns `Promise of void`**: This is fine since the download is a side effect. 11. **`useCallback` dependency**: `exportMutation` is included in the deps array of `useCallback`. Since `useMutation` returns a stable object, this should be fine, but it's worth noting that `exportMutation.mutate` itself is stable so the callback could just use it directly without `useCallback`. 12. **Role expansion**: Adding 'admin' to the General settings role means admins can now also see the Danger Zone (SessionTerminationButton). Is this intentional? The PR seems focused on export but this role change has broader implications. Let me also think about the `vote.value` type more carefully. The `Vote` type has `value: number` but in planning poker, special values like "?" (coffee break, infinity) might need to be represented. If the domain only allows numeric values, this is fine. The tests are well-written and cover edge cases nicely. For the N+1 concern — `Promise.all` means all vote queries fire in parallel, so it's not strictly N+1 in the traditional sense (sequential), but it does issue N separate requests. A single query with a session-level filter would be more efficient. One more thing: `XLSX.writeFile` triggers a download via `document.createElement('a')` and click — this is a browser-only API. The service function can't be used in a non-browser context (e.g., SSR, tests) without mocking. ```
### Analysis อะ รอบนี้ reasoning ออกมายาวจริง ๆ ละ content ก็ออกมายาวมากกกก ในมุม usability นิลว่ามันยาวเกินไปครับ ถ้าต้องเอาไปอ่านใน comment PR จริง ๆ นิลว่าแม้แต่นิลก็ไม่อ่านครับ 55555555 คิดว่าอาจจะต้องมี code ที่ช่วยตัดส่วน thinking ออกไปครับ อะ แต่มาที่ส่วน content ครับ ตัว thinking ที่ออกมาค่อนข้าง value มาก ๆ เลยครับ มันนั่งคิดทีละ file และทีละ change เลยว่าแต่ละ change แก้มาสมเหตุสมผลไหม เช่น ```md wrap **build-votes-workbook.ts** (new) - Pure data→workbook transformation. Filters spectators, builds array-of-arrays grid (Round # | participant names | Average). Handles missing votes with empty string. Truncates sheet name to 31 chars (Excel limit). - Concern: `vote.value` typed as `number`, but planning poker often has non-numeric values ("?", "☕", "∞"). If domain allows these, they'd be excluded or cause issues. - Concern: Sheet name truncation via `.slice(0, 31)` doesn't sanitize invalid Excel sheet name characters (`\ / ? * [ ]`). ``` ซึ่งถ้ามานั่งตามอ่านเราจะเห็นเลยว่า thinking ของมัน นั่งวิเคราะห์อะไรบ้าง และ concern อะไรบ้าง จากตรงนี้เราก็จะเห็นว่ามันคิดว่า planning poker ทั่วไปจะมีพวกการโหวตด้วย ☕ หรือ ∞ นะ ซึ่งอาจจะส่งผลต่อการคำนวณคะแนนเฉลี่ย แต่ของนิลมันไม่มีนี่สิ จากตรงนี้นิลคิดว่ามันน่าจะขาด context ของ vote value ที่เป็นไปได้ทั้งหมดในระบบอยู่ครับ จุดที่นิลมานั่งคิดอีกอันคือ พอมัน thinking มากขึ้น สิ่งที่ได้คือมัน catch potential issue ได้มากขึ้น (ซึ่งก็ไม่ valid ขนาดนั้น แต่ก็มีโอกาสเจอมากขึ้น) แต่ก็ยัง catch ตัว issue ตั้งต้นที่นิลตั้งไว้ได้ทั้งหมดเนอะ แปลว่า context code ที่มันรู้ อาจจะยังไม่พอก็ได้ และอีกสิ่งนึงที่นิลมานั่งคิดคือพอนิลให้มัน thinking ออกมาเพิ่ม output ก็ยาวขึ้นครับ และถ้านิลไม่ได้ใช้ GLM ที่เป็น Coding Plan แต่เป็นเจ้าอื่น ๆ ที่ต้องจ่ายตาม usage ดูสิครับ อู้หูวว ขนลุกครับพี่แจ๊ค ดังนั้นเดี๋ยวนิลอาจจะต้องมา balance ตัว output ที่จะออกมากับ reasoning ที่ออกมาด้วยว่ามันคุ้มในมุม cost ไหมม อะทีนี้มาสรุปผลของการลองรอบนี้เป็นตารางดูครับ #### Issue ที่นิลคาดหวังให้เจอ | Issue | จับได้ไหม? | Note | | ------------------------------- | ---------- | ------------------------------------------------ | | Query เปลือง (spectator filter) | ⚠️ | ยังเจอแค่ N+1 ไม่ได้ชี้ spectator filter layer | | Handle ชื่อซ้ำ | ❌ | ยังเงียบ แม้ reasoning จะยาวขึ้นมาก | | xlsx bundle size | ✅ | จับได้เหมือนเดิม เพิ่ม dynamic import suggestion | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | จับได้เหมือนเดิม | | Firestore indexes | ❌ | ยังไม่รู้ project convention | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Additional Note | | ----------------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------------- | | N+1 query pattern | Performance | ยังคงเจออยู่ | | Display name → formula injection | Security | ยังคงเจออยู่ครับ | | Sheet name limit ที่ 31 ตัวอักษร | Edge Case | ยังพูดถึงอยู่ครับ | | 🚀 Non-numeric vote value (อาจจะเจอ "?" หรือ "∞" ได้) | Functional | อันนี้ไม่ valid ครับ เพราะ voting value ไม่มีทางเป็นค่าอื่นนอกจากตัวเลข อาจจะเป็นเพราะ context ไม่ครบ | | 🚀 มี browser side-effect ใน service | Code Pattern | อันนี้ดีมาก นิลไม่ได้ expect ว่าจะเจอสิ่งนี้เลยครับ | ### สิ่งที่จะลองใน iteration ที่ 2 1. เพิ่ม `AGENTS.md`, `CONVENTION.md` และ Directory List แบบคร่าว ๆ เข้าไป 2. เพิ่มข้อมูลของ Scrum poker card เข้าไปโดยเอา function ที่ `getCardValue ส่งให้มันเพิ่ม` 3. เพิ่ม prompt ส่วนล่างสุดให้ถามคำถามที่ยัง missing จากการไปคิดมา 1 ที นิลคิดว่าการเพิ่ม `AGENTS.md`, `CONVENTION.md`, directory list และค่าของ Scrum poker card ที่เป็นไปได้ จะทำให้ตัว model เข้าใจมากขึ้นเกี่ยวกับ function การทำงานและ coding convention รวมถึง architecture ที่เขียนไว้ด้วยครับ ซึ่งจะสอดคล้องกับการที่นิลคิดว่ามันยังไม่รู้ context ของ project เช่น ค่าที่เป็นไปได้ในการ vote และ Firestore indexes และการเพิ่มให้ AI ตั้งคำถามที่ model ยังไม่รู้ก็อาจจะรู้ได้มากขึ้น (มั้ง) ว่ามันต้องการอะไร -- จบ iteration 1 -- ## Iteration 2: Add more project context files ในรอบนี้นิลลองเพิ่ม file พวก `AGENTS.md`, `CONVENTION.md` ละก็ file ที่กระทบ business rule ไปนะครับ นอกจากนี้นิลยังเพิ่มส่วนของการ logging เวลามาว่าการ run 1 ครั้งใช้เวลาเท่าไหร่ และนี่คือผลลัพธ์ของ iteration ที่ 2 คับ ### Prompt Used ใน iteration นี้อย่างที่บอกว่านิลเพิ่ม `AGENTS.md` กับ `CONVENTION.md` รวมถึง card value ที่เป็นไปได้ทั้งหมดเข้าไปครับ ซึ่งก็จะเพิ่มคร่าว ๆ เข้าไปแบบนี้ครับ ```diff lang="md" wrap ...existing prompt + ## Repository Context: + + ### Here is the agent's markdown file that describes the agent's capabilities and how it should use them: + + # Package Manager + + pnpm@9.14.2 + + ...AGENTS.md content + + ### Here's the convention's markdown file that describes the coding conventions that the agent should follow when analyzing the code changes: + + ...CONVENTION.md content + + ### Core Card Values: + + ... Core Card Values ``` > NOTE: สามารถ[ดู prompt ของ iteration 2 เต็ม ๆ ได้ที่นี่](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript/blob/main/outputs/iteration-2/system-prompt.md#)เลยคับ ### Output #### Token Usage ```yaml completion_tokens: 2371 - reasoning_tokens: 1010 prompt_tokens: 9278 total_tokens: 11649 ``` #### Time Usage (For iteration 2) 1:20.952 (m:ss.mmm)
AI Output ```md wrap ## Thinking **package.json / pnpm-lock.yaml** - Adds `xlsx@^0.18.5` (SheetJS community edition) for Excel file generation. This version is Apache-2.0 licensed; note that newer SheetJS versions changed to a more restrictive license, so pinning/ceiling may be wise. - Brings in 7 transitive deps (`adler-32`, `cfb`, `codepage`, `crc-32`, `ssf`, `frac`, `wmf`, `word`). SheetJS is a heavy library (~800KB+ unminified) — significant bundle size impact for a SPA. Consider dynamic `import()` to code-split. **game-settings-modal.tsx** - Adds `'admin'` to the General menu's role array (was `['owner']` only). Needed so admins can access the export feature. **general-settings.tsx** - Inserts an "Export" section with `SessionExportButton` between session info and danger zone. Clean, minimal change. **session-export-button.tsx** (new container) - Uses `useMutation` + toast for feedback, loading/disabled state. `useCallback` here is arguably unnecessary since `exportMutation` is a stable ref from TanStack Query, but harmless. **use-export-session-votes.ts** (new hook) - Thin mutation wrapper, follows project conventions. Good. **build-votes-workbook.ts** (new lib/xlsx utility) - Pure function: session name → sheet name (31-char truncation for Excel), filters out spectators, builds rows with sequential round numbering, missing votes → empty string, null average → empty string. Clean and well-documented. - `votesByParticipantId` uses `reduce` with type assertion — `Object.fromEntries` or a `Map` could be slightly cleaner but not a concern. **build-votes-workbook.test.ts** - Thorough unit tests: sheet naming, truncation, header-only, vote filling, missing votes, spectator exclusion, round numbering, null average. Good factory helpers. **export-session-votes.ts** (new service) - Access control via `checkIfUserCanManageSession`, parallel fetch of session + participants + rounds. - **N+1 query**: fetches votes per round in `Promise.all(rounds.map(...))`. Each round triggers a separate `searchVotes` call. With many rounds, this could be slow. Better: fetch all votes for the session once and group by `roundId`. - Filename `${session.name}-votes.xlsx` is not sanitized — session names with special chars (`/`, `\`, `:`) could cause issues on some OS. - `XLSX.writeFile` triggers a browser download — works fine in SPAs. **lib/xlsx/index.ts** — barrel export, follows convention. **Missing per conventions:** - No E2E test for the export flow (convention: "Add e2e tests for all flows") - No README.md update (convention: "When adding new features, add in README.md") - `lib/` is not a standard layer in the architecture table; `shared/` would be more conventional, though `lib/` is acceptable if already established. ## Summary Adds the ability for session owners and admins to export all voting data as an `.xlsx` file download. Introduces the `xlsx` library, a workbook builder utility with tests, a service orchestrator, a hook, and a UI button in the General Settings panel. ## Files Changed - **package.json** / **pnpm-lock.yaml** — Adds `xlsx@^0.18.5` dependency - **game-settings-modal.tsx** — Grants admins access to General settings menu - **general-settings.tsx** — Adds Export section with export button - **session-export-button.tsx** (new) — Container: button that triggers export mutation - **use-export-session-votes.ts** (new) — Hook: wraps export mutation - **export-session-votes.ts** (new) — Service: fetches data, builds workbook, triggers download - **build-votes-workbook.ts** (new) — Utility: pure function to build XLSX workbook from vote data - **build-votes-workbook.test.ts** (new) — Unit tests for workbook builder - **lib/xlsx/index.ts** (new) — Barrel export ## System Impact - **Bundle size**: `xlsx` adds significant weight (~800KB+). Should be code-split. - **Settings modal**: Admins can now see General settings tab - **Data layer**: `searchParticipants`, `searchRounds`, `searchVotes` called during export - **Access control**: Uses existing `checkIfUserCanManageSession` ## Risk Areas - **N+1 query in `export-session-votes.ts`**: One `searchVotes` call per round. Could degrade with many rounds. - **Bundle size**: `xlsx` imported statically; no lazy loading. - **Unsanitized filename**: `${session.name}-votes.xlsx` could contain OS-problematic characters. - **xlsx version ceiling**: v0.18.5 is last Apache-2.0 version; `^0.18.5` could theoretically resolve to a differently-licensed version if SheetJS releases under 0.18.x with new terms (unlikely but possible). ## Suggested Focus - **`export-session-votes.ts`**: N+1 query pattern — consider a single `searchVotes({ filter: { sessionId } })` then group by round - **Bundle splitting**: Lazy-load `xlsx` via dynamic import in the service or button - **Filename sanitization**: Strip/replace special characters in session name - **xlsx import style**: `import * as XLSX` pulls in the full library; check if tree-shaking applies ## Unresolved Questions 1. Is there an existing `searchVotes` that accepts a `sessionId` filter to avoid the N+1 pattern? 2. Should `xlsx` be lazy-loaded (`await import('xlsx')`) to avoid bundling it in the main chunk? 3. Should the filename be sanitized (e.g., replace `/`, `\`, `:`, etc.)? 4. Are there E2E tests planned for this export flow (per project convention)? 5. Should the `xlsx` version be pinned to `0.18.5` exactly (no caret) given SheetJS licensing changes? 6. Should the `lib/xlsx/` folder live under `shared/` per the architecture convention? ```
Reasoning ```md wrap Let me analyze this PR step by step. ## Thinking ### Package changes (package.json, pnpm-lock.yaml) - Adding `xlsx@^0.18.5` as a dependency - This brings in several transitive dependencies: `adler-32`, `cfb`, `codepage`, `crc-32`, `ssf`, `frac`, `wmf`, `word` Concerns: - The `xlsx` package (SheetJS) has had some controversy. The community edition (0.18.5) is the last fully open-source version. The project moved to a more restrictive license after this. Version 0.18.5 is Apache-2.0 licensed, which should be fine, but it's worth noting that newer versions have licensing issues. This is an older version. - Bundle size concern: xlsx is a fairly heavy library (~800KB unminified). For a SPA, this will significantly increase bundle size. ### game-settings-modal.tsx - Changed General settings menu to be accessible by both 'owner' and 'admin' roles (was only 'owner') - Makes sense since export functionality should be available to admins too ### general-settings.tsx - Added a new "Export" section with `SessionExportButton` component - Placed between SessionInformation and Danger Zone sections - Clean, simple UI layout ### session-export-button.tsx (new file) - Container component following the project's architecture - Uses `useExportSessionVotes` hook with Tanstack Query mutation - Shows loading state with "Exporting..." text - Uses toast for success/error feedback - Uses `useCallback` which is fine but arguably unnecessary here since `exportMutation` is stable ### use-export-session-votes.ts (new file) - Simple hook wrapping a Tanstack Query mutation - Clean, follows project patterns - No caching concerns since this is a mutation ### build-votes-workbook.ts (new file in lib/xlsx/) - Pure function that builds an XLSX workbook from session data - Good separation of concerns - data fetching is in the service, workbook building is here - Filters out spectators from columns - Truncates sheet name to 31 chars (Excel limitation) - Uses sequential round numbering starting at 1 - Handles missing votes with empty string - Handles null averageVote with empty string Concerns: - The `votesByParticipantId` uses `reduce` with a type assertion. This is fine but a `Map` or `Object.fromEntries` might be cleaner. - The function signature takes pre-fetched data, which is good for testability. ### build-votes-workbook.test.ts (new file) - Comprehensive test coverage with factory functions - Tests: sheet naming, truncation, header-only case, vote filling, missing votes, spectator exclusion, sequential numbering, null average - Good use of test helpers (`makeParticipant`, `makeRound`, `makeVote`) ### export-session-votes.ts (new file in services/session/) - Service layer function that orchestrates the export - Uses `checkIfUserCanManageSession` for access control - Fetches - session, participants, and rounds in parallel - Then fetches votes for each round sequentially (N+1 pattern!) - Uses `XLSX.writeFile` to trigger browser download Concerns: 1. **N+1 query pattern**: For each round, it makes a separate `searchVotes` call. If there are many rounds, this could be slow. A better approach would be to fetch all votes for the session at once and group by roundId. 2. **Error handling**: `checkIfUserCanManageSession` might throw, and `getSession` could return null (handled). But the error messages might not be user-friendly. 3. The file download is triggered via `XLSX.writeFile` which uses `writeFileXLSX` internally - this creates a download in the browser. This works in SPAs. 4. The file name uses `${session.name}-votes.xlsx` which could contain special characters. Should probably sanitize. ### Architecture concerns: - `lib/xlsx/` is a new folder that's not one of the standard layers. It's reasonable as a utility/shared module though. The project has `shared/` for utilities, so this could arguably go there instead. - The `xlsx` import in `build-votes-workbook.ts` uses `import * as XLSX from 'xlsx'` which is the standard SheetJS import pattern. ### Missing pieces I'd want to see: - E2E test for the export flow (project convention says to add e2e tests for all flows) - The `index.ts` barrel file exists for `lib/xlsx/` which follows conventions - No update to README.md for the new feature (project convention says "When adding new features, add in README.md") ```
### Analysis รอบนี้มันแปลกแฮะะ เพราะมันเจอ Issue น้อยลงครับ! มันไม่เตือนนิลเรื่อง admin ที่สามารถเห็นตัว sidebar item ได้เพิ่มเติมแล้วจากที่ตอนแรกมันเตือนนะ แล้วก็มีการเตือนเรื่องชื่อไฟล์ที่ไม่ได้ sanitize แล้วอาจจะมีปัญหากับ OS ได้เพิ่มมาแทน ซึ่งนิลก็ลองไปดูตัว `AGENTS.md` กับ `CONVENTION.md` ของนิลครับ ชัดเลย ไม่มีเรื่อง Firestore อยู่ในนั้นเลยครับ นิลว่านี่เป็นหนึ่งในสาเหตุที่มันไม่ได้พูดเรื่อง Firestore index (อีกแล้ว) รวมถึงตัวการ filter นี่นิลคิดว่าเพราะมันไม่รู้ว่า function ที่นิลใช้ fetch Firestore มันเป็นยังไง กับมันอาจจะไม่รู้ business logic ของตัว scrum poker มันเลยไม่รู้ว่าเราต้องเอา spectator ออกจากการคิดค่าเฉลี่ยด้วย ความน่าสนใจของรอบนี้คือพอให้มันถามคำถามกลับมาก็จะเห็นว่ามันถามเรื่อง function `searchVotes` ว่ามี filter by `sessionId` ไหม เพื่อให้เราสามารถ avoid N+1 Query ได้ แปลว่ามันไม่เห็นหน้าตาหรือ contract ของ function นั้น ๆ หรือการที่มันถามมาว่าเราควรเอา `/libs/xlsx` ไปวางใน `/shared` ไหม ซึ่งก็เหมือนเป็นการบอกกลาย ๆ ว่า "ถ้ามันเห็นหน้าตาข้อมูลมันก็ suggest ให้เราออกมาได้" อีกอย่างที่น่าสนใจคือ token พุ่งเลยครับ 5555555 จากตอนแรก total token ที่ใช้มัน 9,702 แต่พอเพิ่มพวก `AGENTS.md`, `CONVENTION.md` และ Context อื่น ๆ ไป รอบนี้กระโดดไป 11,649 แหนะ แปลว่าถ้าเราส่ง context เข้าไปเพิ่มอีก มันน่าจะรู้เรื่องเพิ่มแหละ แต่ค่า token ก็จะโดดขึ้นไปเรื่อย ๆ เลย อันนี้เป็นจุดที่ต้องระวังครับ ซึ่งนิลเลยได้ข้อสรุปนึงมาว่า context มากขึ้น ≠ ผลลัพธ์ดีขึ้นเสมอไปครับ อาจจะต้องเป็น context ที่เกี่ยวกับ change นั้นด้วย มันถึงจะ suggest ได้ว่าควรแก้หรือควร improve อะไร พอมี 3 รอบแล้วเจอ regression นิดนึง นิลขอทำเป็นตารางสรุปดี ๆ 1 ทีนะครับ #### Issue ที่นิลคาดหวังให้เจอ | Issue | Iter 0 | Iter 1 | Iter 2 | Note | | ------------------------------- | ------ | ------ | ------ | ------------------------------------------------------- | | Query เปลือง (spectator filter) | ⚠️ | ⚠️ | ⚠️ | ยังเจอแค่ N+1 แต่มีการถามเพิ่มถึง contract ของ function | | Handle ชื่อซ้ำ | ❌ | ❌ | ❌ | ยังเงียบ คิดว่าไม่รู้ business logic ของ feature นี้ | | xlsx bundle size | ✅ | ✅ | ✅ | จับได้เหมือนเดิม เพิ่ม dynamic import suggestion | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | ✅ | ❌ | รอบนี้ไม่เจอออ | | Firestore Indexes | ❌ | ❌ | ❌ | ไม่พูดถึง คิดว่าเพราะ `AGENTS.md` ไม่ได้เขียนไว้ | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Iter 0 | Iter 1 | Iter 2 | Additional Note | | --------------------------------------------------- | ------------ | ------ | ------ | ------ | ------------------------------------- | | N+1 query pattern | Performance | ✅ | ✅ | ✅ | ยังคงเจออยู่ | | Display name → formula injection | Security | ✅ | ✅ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | Sheet Name limit ที่ 31 ตัวอักษร | Edge Case | ✅ | ✅ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | Non-Numeric Vote Value (อาจจะเจอ "?" หรือ "∞" ได้) | Functional | ❌ | ✅ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | มี Browser Side-effect ใน service | Code Pattern | ❌ | ✅ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | 🚀 Filename sanitization for cross OS compatibility | Edge Case | ❌ | ❌ | ✅ | ดีมากที่เจอ นิลไม่ได้คิดถึงเคสนี้ครับ | ### สิ่งที่จะทำใน iteration 3 1. เพิ่ม business logic ของ Scrum poker ของนิลเข้าไป 2. เพิ่ม Firestore context พวก fetching function, การใช้ data layer ในการ fetch ในมุมนิล การไปต่อใน iteration 3 มันแอบตันนิดนึง แต่นิลก็อาจจะต้องไปต่อด้วยการเพิ่มข้อมูลเกี่ยวกับ business logic ของ scrum poker กับการเพิ่ม function ในการ fetch ของ firestore รวมถึงการเพิ่มข้อมูล Firestore เข้า `AGENTS.md` เพื่อให้มันคิดเพิ่มว่าถ้ามีการเรียกพวก search แบบมี order มันควรที่จะทักเรื่อง change ควรมี file `firestore.indexes.json` commit มาด้วยนะ หรือถ้ามีการ access data ใหม่ที่ไม่เคยมีการ access มาก่อน ควรมี file `firestore.rules` commit มาด้วยแหละ ไปลองกันต่อเลยครับ -- จบ iteration 2 -- ## Iteration 3: Add business context and Firestore context นิลให้เจ้า Claude Code เข้าไปอ่าน repo แล้วก็ช่วยสรุปตัว business logic ของ Scrum poker ของนิลออกมานะครับ แล้วนิลก็ validate แล้วก็แก้อีก 1 ที ซึ่งนิลก็เอาสิ่งนี้มาเพิ่มในส่วนแรกของ `AGENTS.md` เลยครับ แล้วอีกอย่างนึง ตัว Firestore context นี่ นิลมานั่งเขียนเองครับ ซึ่งนี่คือสิ่ง system prompt ที่นิลใช้รอบนี้ครับ ### Prompt used 1. ในรอบนี้นิลเพิ่มส่วนของ business logic เข้ามาครับ ```diff lang="md" wrap + ## Core Business Logic + + **Session** + - A session has a `name`, a `votingSystem` (e.g. fibonacci, t-shirt), an `ownerId`... + + **Participants and Roles** + - Roles: `owner`, `admin`, `player`, `spectator`. Statuses: `active`, `left`, `removed`. + - `owner` and `admin` can manage the session... + ... ``` 2. และก็มีการเพิ่ม prompt เกี่ยวกับ Firestore เข้ามาประมาณนี้ครับ ```diff lang="md" wrap + ## Firestore + + - We use Firestore as our database. We have a `firestore.indexes.json` file where we define our indexes. When you add a new query that requires an index, please add it to this file. We wrap a query with the query builder function `buildQueryConstraints` that ... + + We also have `firestore.rules` file where we define our security rules. Please make sure to update the rules if you add new collections or change the structure of existing collections. + + ### Firestore Query Builder + ... ``` > NOTE: สามารถ[ดู prompt ของ iteration 3 เต็ม ๆ ได้ที่นี่](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript/blob/main/outputs/iteration-3/system-prompt.md#)เลยคับ ### Output #### Token Usage ```yaml completion_tokens: 2932 - reasoning_tokens: 1343 prompt_tokens: 10377 total_tokens: 13309 ``` #### Time Usage (For iteration 3) 1:48.333 (m:ss.mmm)
AI Output ```md wrap ## Thinking ### package.json and pnpm-lock.yaml - Adds `xlsx@^0.18.5` (SheetJS community edition). This is the standard library for generating Excel files in the browser. The 0.18.5 version is Apache-2.0 licensed, which is fine. Lockfile updates are just the transitive deps (adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word) — all normal SheetJS internals. ### `src/containers/game-settings-modal.tsx` - Changes General settings menu `role` from `['owner']` to `['owner', 'admin']`. - Aligns with business rules: admins can manage sessions including export. Makes sense. ### `src/containers/game-settings/general-settings.tsx` - Adds an "Export" section with `SessionExportButton` between session info and danger zone. - Clean insertion, follows existing pattern. ### `src/containers/session-export-button.tsx` (NEW) - Standard mutation-triggering button component. Uses `useSession()` for session ID, `useExportSessionVotes` hook for the mutation. - Loading/disabled state handled via `exportMutation.isPending`. - Success/error toast feedback via `sonner`. - **Minor:** `exportMutation` in `useCallback` dep array is stable because React Query's `useMutation` returns a stable object, so no issue here. ### `src/hooks/session/use-export-session-votes.ts` (NEW) - Thin hook wrapping `useMutation` around `exportSessionVotes`. Follows established patterns. ### `src/lib/xlsx/build-votes-workbook.ts` (NEW) - Core pure function that builds the XLSX workbook. - Filters out spectators — correct per business rules. - Headers: `Round | participant names... | Average`. - Missing votes rendered as empty string — good. - Null average rendered as empty string — good. - Sheet name truncated to 31 chars (Excel hard limit) — good. - **Concern:** Special vote values (-1 for `?`, -2 for `🙅🏼`) will appear as `-1` and `-2` in the spreadsheet. These should use their `displayValue` instead, but the `Vote` type only stores the numeric `value`. The mapping back to display values requires knowledge of the voting system. This is a meaningful gap — exported data will be confusing for non-standard votes. ### `src/lib/xlsx/__tests__/build-votes-workbook.test.ts` (NEW) - Good test coverage: sheet naming, truncation, header-only, vote filling, missing votes, spectator exclusion, sequential numbering, null average. - Uses factory functions — clean pattern. - **Missing test cases:** special vote values (-1, -2), empty participants array, duplicate participant display names. ### `src/services/session/export-session-votes.ts` (NEW) - Orchestrates: permission check → fetch session/participants/rounds → fetch votes per round → build workbook → trigger download. - **N+1 query problem:** `rounds.map(async (round) => ({ round, votes: await searchVotes(...) }))` fires one Firestore query per round. For sessions with many rounds, this is expensive and slow. Should batch: fetch all votes for the session in one query, then group by `roundId` client-side. - **Side effect in service layer:** `XLSX.writeFile(wb, ...)` triggers a browser download. This belongs in the hook/container layer. Service should return the workbook/buffer for testability. Currently the function is untestable without mocking XLSX.writeFile. - **Double fetch of session:** `checkIfUserCanManageSession` likely fetches the session for ownership check, then `getSession(sessionId)` fetches it again. - **File naming:** `${session.name}-votes.xlsx` — session name could contain special characters. Should sanitize or use session ID. ## Summary Adds an XLSX export feature for session voting data, allowing owners and admins to download all votes across rounds as an Excel file. The export includes one row per round with participant votes and averages, filtering out spectators. ## Files Changed - **`package.json`** / **`pnpm-lock.yaml`** — Added `xlsx@^0.18.5` dependency - **`src/containers/game-settings-modal.tsx`** — General settings now accessible to admins - **`src/containers/game-settings/general-settings.tsx`** — Added Export section UI - **`src/containers/session-export-button.tsx`** — Export button container component (NEW) - **`src/hooks/session/use-export-session-votes.ts`** — Mutation hook (NEW) - **`src/lib/xlsx/build-votes-workbook.ts`** — Pure workbook builder function (NEW) - **`src/lib/xlsx/__tests__/build-votes-workbook.test.ts`** — Unit tests for workbook builder (NEW) - **`src/services/session/export-session-votes.ts`** — Export orchestration service (NEW) ## System Impact - **Session settings UI** — General tab now visible to admin role - **Data layer** — New read paths: participants by session, rounds by session (filtered), votes by round - **Firestore** — New queries on `rounds` collection with `status in ['finished', 'revealed']` filter; may need a composite index - **Bundle size** — `xlsx` adds ~900KB to the bundle (significant for an SPA) ## Risk Areas - **N+1 Firestore queries** in `export-session-votes.ts` — one `searchVotes` call per round; will degrade with many rounds - **Special vote values** (-1 = `?`, -2 = `🙅🏼`) exported as raw numbers, not display values; confusing for end users - **`XLSX.writeFile` in service layer** — side effect makes the service untestable in isolation; should return workbook and let the caller handle download - **Bundle size** — `xlsx` is ~900KB minified; no dynamic import/ lazy loading visible - **File name** uses raw `session.name` — special characters (/, \, :) could cause issues - **Firestore index** — the `status: { op: 'in', value: ['finished', 'revealed'] }` query on rounds may require a composite index; should verify `firestore.indexes.json` is updated - **Potential double session fetch** — `checkIfUserCanManageSession` + `getSession` ## Suggested Focus - Refactor N+1 votes query to a single batch fetch - Handle special vote values (-1, -2) — either map to display values or use the voting system's card definitions - Move `XLSX.writeFile` out of service layer for testability - Lazy-load the `xlsx` library (`const XLSX = await import('xlsx')`) to avoid bundle bloat - Verify/add Firestore composite index for rounds query - Sanitize filename or fallback to session ID ## Unresolved Questions 1. Should special votes (`?` = -1, `🙅🏼` = -2) be exported as their display values or remain as numbers? 2. Is there a Firestore composite index defined for the `sessionId + status(in) + createdAt` query on rounds? 3. Is the `xlsx` bundle size acceptable, or should it be dynamically imported? 4. Should `exportSessionVotes` return the workbook and let the caller trigger the download? 5. Should the filename be sanitized or use session ID instead of the user-provided session name? ```
Reasoning ```md wrap Let me analyze this PR carefully, walking through the diff line by line. ## Package Changes ### package.json - Added `xlsx` dependency at `^0.18.5` — this is the SheetJS library for creating Excel files. ### pnpm-lock.yaml - Standard lockfile updates for xlsx and its dependencies (adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word). **Concern:** The `xlsx` package (SheetJS community edition) has had some controversy around licensing. The 0.18.x version is community edition but they moved to a more restrictive license in later versions. Should verify this is acceptable. ## Container Changes ### `src/containers/game-settings-modal.tsx` - Changed General settings menu to be accessible by `['owner', 'admin']` instead of just `['owner']`. - This makes sense since the export feature is being added and according to the business rules, admins can manage sessions (including export). ### `src/containers/game-settings/general-settings.tsx` - Added a new "Export" section with `SessionExportButton` between Session Information and Danger Zone. - Imports the new `SessionExportButton` component. ### `src/containers/session-export-button.tsx` (NEW) - A button component that triggers the export mutation. - Uses `useSession()` to get the session ID. - Uses `useExportSessionVotes` hook. - Shows loading state with "Exporting..." text. - Shows success/error toasts. **Concern:** The `handleExport` callback has `exportMutation` in its dependency array. Since `exportMutation` is the return value of `useMutation`, it could be a new object on every render, potentially causing unnecessary re-renders. However, React Query's `useMutation` returns a stable object, so this should be fine. ## Hook ### `src/hooks/session/use-export-session-votes.ts` (NEW) - Simple wrapper around `useMutation` calling `exportSessionVotes`. - Clean and follows the established pattern. ## XLSX Library ### `src/lib/xlsx/build-votes-workbook.ts` (NEW) - `RoundWithVotes` interface — links a round with its votes. - `buildVotesWorkbook` function: - Filters out spectators from the columns. - Creates headers: `['Round', ...participantNames, 'Average']` - For each round, creates a row with round number (1-indexed), vote values per participant, and average. - Missing votes show as empty string. - Null averageVote shows as empty string. - Sheet name truncated to 31 chars (Excel limit). - Uses `XLSX.utils.aoa_to_sheet` to create sheet from array of arrays. **Concerns:** 1. The `votesByParticipantId` accumulator uses `{} as Record of string, number` but the value could be a number or... actually looking at the Vote type, `value` is a number. But what about special values like -1 (?) or -2 (🙅🏼)? These are numeric values so they'd appear as -1 or -2 in the spreadsheet. That might be confusing to users. They should probably display as '?' or '🙅🏼' instead. 2. The function filters out spectators, which is good. But what about participants with status `left` or `removed`? They're included in the export, which makes sense for historical data. ### `src/lib/xlsx/index.ts` (NEW) - Re-exports from `build-votes-workbook`. ### `src/lib/xlsx/__tests__/build-votes-workbook.test.ts` (NEW) - Comprehensive test suite covering: - Sheet naming and truncation - Header-only sheet - Vote filling - Missing votes (empty string) - Spectator exclusion - Sequential round numbering - Null average vote handling - Uses factory functions (makeParticipant, makeRound, makeVote) — good pattern. **Missing tests:** - What happens with special vote values (-1, -2)? - What happens with no participants? - What happens with duplicate participant names? ## Service ### `src/services/session/export-session-votes.ts` (NEW) - Orchestrates the export: 1. Checks user permissions via `checkIfUserCanManageSession` 2. Fetches session, participants, rounds 3. Fetches votes for each round 4. Builds workbook and triggers download **Concerns:** 1. **N+1 query pattern**: For each round, a separate `searchVotes` call is made. If there are many rounds, this could be very slow and expensive with Firestore. 2. The function fetches rounds with status `finished` or `revealed`. According to the business rules, a round can be `in-progress`, `revealed`, or `finished`. Exporting `revealed` rounds makes sense, but `finished` ones too. 3. `XLSX.writeFile` triggers a browser download — this is a side effect in a service function. It would be better to separate the data preparation from the download trigger, making it more testable. 4. The function returns `Promise of void` — there's no way to test the output without mocking `XLSX.writeFile`. 5. The function throws if session is not found after permission check passes. The permission check presumably already fetches the session, so this is a potential double-fetch. **Architecture concern:** The service layer should probably return the workbook or buffer, and the hook/container should handle the download. This follows better separation of concerns. **Access control:** Uses `checkIfUserCanManageSession` which should check for owner OR admin role. This aligns with the menu change allowing admins access to General settings. ## Overall Assessment This PR adds a vote export feature as an XLSX download. The architecture generally follows the layered approach but has some concerns: 1. **N+1 queries** in the service layer — should batch vote fetching 2. **Side effects in service** — `XLSX.writeFile` should be moved to the container/hook layer 3. **Special vote values** — -1 and -2 will appear as numbers instead of their display values 4. **xlsx package licensing** — SheetJS community edition 0.18.5 uses Apache 2.0, which should be fine, but worth noting Let me structure my review. ```
### Analysis ในรอบนี้หลังจากใส่ context ของ Firestore เข้าไปใน `AGENTS.md` เพิ่มก็ค้นพบว่าใน Risk Areas ของ code review มีการเพิ่มว่าให้ไป verfiy ว่า `firestore.indexes.json` ถูกอัปเดตนะ และมีการเจอ potential double session fetch ด้วยจากการที่เราโยนตัว query builder function เข้าไปให้ นอกจากนี้จากการโยน context ของ project มันยังเจอพวกการที่ค่า vote value มีโอกาสเป็น -1 หรือ -2 แล้วเอาไปแสดงใน sheet ด้วย บอกเลยว่าของจริงงง รอบนี้นิลว่าจากการให้ business logic context + Firestore context ทำให้มัน catch issue ได้มากขึ้นจาก business context และ project convention ที่ให้ไปเรื่อย ๆ แปลว่าถ้าเราให้ context ได้ถูกจุด ตัว model ก็น่าจะตอบเราได้มากขึ้นเรื่อย ๆ ครับ แปลว่าสมมติฐานที่บอกว่าเพราะมันยังขาด context มันเลยจับ issue ไม่ได้ก็ดูทรงจะจริงขึ้นมาครับ กลับมาที่ downside มันยัง diagnosis ไม่เจอตัว query ที่ filter ซักทีเลยครับ มันยังมองเรื่อง N+1 Query อยู่มากกว่าครับ ซึ่งถ้าดู thinking มันนี่ไม่มีเรื่อง query ที่ service layer เยอะเกินแล้วไปเอาออกที่ xlsx utility เลยครับ 😭 นิลแอบจนปัญญาแล้วแฮะ 555555 ไม่งั้นนิลอาจจะต้องส่งไปเพิ่มว่าให้มันพยายาม fetch ของที่ data layer เท่าที่จำเป็นแหละ ซึ่งไว้ iteration หน้าแล้วกัน 55555555 ซึ่ง ๆๆๆ สิ่งที่ตามมาจากการส่ง context ไปเยอะขึ้นคืออออ ใช้ token มากขึ้น 55555555 ไอ่บ้าเอ้ยยย และก็ใช้เวลาเหมือนจะเพิ่มขึ้นด้วย 🥶 สั่นกลัววว ถ้าต้องจ่าย token จริง หรือใช้ model ที่แพงกว่านี้ (เช่น ใช้ Claude Opus 4.6 หรือ Gemini 3.1 Pro) นี่น่าจะขนหน้าแข้งร่วงจริง ๆ เลยครับ #### Issue ที่นิลคาดหวังให้เจอ | Issue | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Note | | ------------------------------- | ------ | ------ | ------ | ------ | ---------------------------------------------------------------------------------------------- | | query เปลือง (spectator filter) | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ยังเจอแค่ N+1 🥹 | | handle ชื่อซ้ำ | ❌ | ❌ | ❌ | ❌ | ยังเงียบ คิดว่าไม่รู้ business logic ของ feature นี้ | | xlsx bundle size | ✅ | ✅ | ✅ | ✅ | จับได้เหมือนเดิม แต่รอบนี้ไม่ได้ suggest มา แค่บอกว่าเราไม่ได้ dynamic import/lazy loading | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | ✅ | ❌ | ❌ | รอบนี้ไม่เจอออ คิดว่าจาก `AGENTS.md` บอกถึง structure มันเลยคิดว่าสิ่งนี้ intend อยู่แล้วก็ได้ | | Firestore Indexes | ❌ | ❌ | ❌ | ✅ | รอบนี้เจอออ | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Additional Note | | -------------------------------------------------------- | ------------ | ------ | ------ | ------ | ------ | -------------------------------------------------- | | N+1 query pattern | Performance | ✅ | ✅ | ✅ | ✅ | ยังคงเจออยู่ | | display name → formula injection | Security | ✅ | ✅ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | sheet Name limit ที่ 31 ตัวอักษร | Edge Case | ✅ | ✅ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | non-numeric vote value (อาจจะเจอ "?" หรือ "∞" ได้) | Functional | ❌ | ✅ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ <- ซึ่งถูกแล้วที่ไม่พูดถึง | | มี browser side-effect ใน service | Code Pattern | ❌ | ✅ | ❌ | ✅ | ยังคงเจออยู่ | | filename sanitization for cross OS compatibility | Edge Case | ❌ | ❌ | ✅ | ✅ | ยังคงเจออยู่ | | 🚀 handle vote value (พวก vote value ที่เป็น -1 หรือ -2) | Functional | ❌ | ❌ | ❌ | ✅ | อันนี้ดีมาก นิลก็เพิ่งเจอเหมือนกันครับ 💀 | ### สิ่งที่นิลจะทำใน iteration 4 1. ส่ง PR issue title, description ไปด้วย 2. ส่ง Linear issue ไปด้วย 3. ส่ง domain entity schema ไปด้วย เอาไปให้หมด 4. เพิ่มใน `AGENTS.md` ให้บอกว่าช่วยลด fetching จาก Firestore หน่อย 5. ส่ง `firestore.indexes.json` ไปเพิ่ม -> นิลคิดว่าสิ่งนี้จะช่วยบอกได้ว่า change ที่ทำไป ต้องสร้าง index เพิ่มไหม -- จบ iteration 3 -- ## Iteration 4: Add issue details and business domain entities ในรอบนี้ นิลส่งข้อมูลที่คิดว่า missing ทั้งหมดไปเลย เช่น Linear issue details, GitHub PR content, ส่งเรื่องการลดการ fetch จาก Firestore และส่ง Firestore Indexes ที่มีให้มันไปด้วย คิดว่าถ้าส่งหมดน่าจะติ๊กเขียวหมดละ ซึ่งมาลองดูกันว่าเขียวหมดจริงไหม ### Prompt used 1. นิลเพิ่มส่วน business domain entities เข้าไปครับ ```diff lang="md" wrap ...existing prompt + ### Here are the domain entities that are relevant to the code changes: + ... Domain entities ... ``` 2. นิลเพิ่มในส่วนของ Requirement จาก project management tool เข้าไปอีกครับ ```diff lang="md" wrap + ### Issue Details: + #### As an session owner, I want to export current session vote as xlsx + ... Requirement details ... ``` 3. และนิลก็เพิ่มข้อมูลจาก PR ใน GitHub เข้าไปด้วยครับ ```diff lang="md" wrap + ### Pull Request Details: + #### feat(session): add export votes as xlsx for admin and owner + ... PR Description ... ``` > NOTE: สามารถ[ดู prompt ของ iteration 4 เต็ม ๆ ได้ที่นี่](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript/blob/main/outputs/iteration-4/system-prompt.md#)เลยคับ ### Output #### Token Usage ```yaml completion_tokens: 3414 - reasoning_tokens: 2004 prompt_tokens: 11578 total_tokens: 14992 ``` #### Time Usage (For iteration 4) 1:31.324 (m:ss.mmm)
AI Output ```md wrap ## Thinking ### package.json / pnpm-lock.yaml - Adds `xlsx@^0.18.5` (SheetJS community edition) and its transitive deps (adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word). - xlsx is ~800KB minified — will materially increase bundle size. No lazy loading strategy applied. ### src/containers/game-settings-modal.tsx - Changes General tab role from `['owner']` to `['owner', 'admin']`. - This means admins now see **all** content in General settings: session info, export, **and the Danger Zone (terminate session)**. - Need to verify `SessionTerminationButton` has its own role check restricting to owner-only. The business rules say only owner can terminate. ### src/containers/game-settings/general-settings.tsx - Adds an "Export" section between SessionInfo and Danger Zone with the new `SessionExportButton`. ### src/containers/session-export-button.tsx - Container component wiring the mutation hook to a Button with loading state and toasts. - `useCallback` with `exportMutation` dep — TanStack Query v5 returns a stable mutation object, so this is fine but also unnecessary since the component re-renders on `isPending` anyway. - No role check at the UI level — relies on the tab visibility and service-layer guard. Acceptable. ### src/hooks/session/use-export-session-votes.ts - Thin `useMutation` wrapper. Clean, follows conventions. ### src/lib/xlsx/build-votes-workbook.ts - Core logic: filters spectators, builds `['Round', ...names, 'Average']` header, maps rounds to rows with 1-based indexing, uses empty string for missing votes/null average. - Sheet name truncated to 31 chars (Excel limit). - **No duplicate participant name handling**: The AC says "If the player name is duplicated, we might add their uids to the header after their name e.g. name-uid." This is not implemented — duplicate names will produce identical column headers. - Vote values are shown as raw numbers. For t-shirt sessions, values 0–5 will appear instead of "XS"–"XXL". Not addressed. ### src/lib/xlsx/__tests__/build-votes-workbook.test.ts - Good coverage: sheet naming, truncation, header-only, vote filling, missing votes, spectator exclusion, sequential numbering, null average. - **Missing test**: duplicate participant names behavior. ### src/services/session/export-session-votes.ts - Access control via `checkIfUserCanManageSession` — correct. - Fetches session, participants, rounds in parallel — good. - **N+1 query problem**: For each round, a separate `searchVotes` call is made. The architecture doc explicitly warns against this. Should batch using `roundId` with `in` operator (Firestore supports up to 30 values per `in` clause, batch if more). - `XLSX.writeFile` side effect in the service layer — a download is triggered directly. Service functions ideally shouldn't have browser side effects, but this is pragmatic for a client-side app. - Rounds filter uses `status: { op: 'in', value: ['finished', 'revealed'] }` — correct per AC. ### src/lib/xlsx/index.ts - Barrel export. Follows convention. --- ## Summary Adds an "Export votes (.xlsx)" feature allowing session owners and admins to download all voting data as an Excel file. Includes a new `buildVotesWorkbook` utility with unit tests, a service function that fetches data and triggers download, and UI wiring in the General Settings tab. ## Files Changed - **package.json** — adds `xlsx` dependency - **pnpm-lock.yaml** — lockfile update - **src/containers/game-settings-modal.tsx** — admins can now see General tab - **src/containers/game-settings/general-settings.tsx** — adds Export section - **src/containers/session-export-button.tsx** — new export button container - **src/hooks/session/use-export-session-votes.ts** — mutation hook - **src/lib/xlsx/build-votes-workbook.ts** — workbook builder utility - **src/lib/xlsx/__tests__/build-votes-workbook.test.ts** — unit tests - **src/lib/xlsx/index.ts** — barrel export - **src/services/session/export-session-votes.ts** — orchestrates data fetch + download ## System Impact - **Data layer**: `searchParticipants`, `searchRounds`, `searchVotes` all used; N+1 pattern on votes - **Service layer**: new `exportSessionVotes` function - **UI**: General Settings tab now visible to admins; new export button - **Bundle**: xlsx library adds significant size (~800KB) with no code splitting ## Risk Areas 1. **N+1 query on votes** — one Firestore call per round; will degrade with many rounds 2. **Admin sees Danger Zone** — `game-settings-modal.tsx` change exposes terminate button to admins; verify `SessionTerminationButton` enforces owner-only 3. **Duplicate participant names** — AC mentions appending uid but not implemented; identical headers possible 4. **T-shirt vote display** — numeric values (0–5) shown instead of display values (XS–XXL) 5. **xlsx bundle size** — statically imported, not lazy-loaded 6. **xlsx@0.18.5 licensing** — community edition; later versions changed license. 0.18.5 is Apache 2.0, acceptable, but be aware of future upgrades ## Suggested Focus - **`src/services/session/export-session-votes.ts`** — N+1 vote fetching is the most impactful issue; refactor to batch `searchVotes` with `in` operator on round IDs - **`src/containers/game-settings-modal.tsx`** — confirm terminate button has independent owner-only guard now that admins see General tab - **`src/lib/xlsx/build-votes-workbook.ts`** — duplicate name deduplication logic missing per AC - **Bundle impact** — consider `await import('xlsx')` in the service to lazy-load only on export click ## Unresolved Questions 1. Should duplicate participant names append uid to headers as mentioned in AC? 2. Should t-shirt votes display "XS"/"S"/"M" etc. instead of numeric values in the spreadsheet? 3. Is the terminate button in Danger Zone protected by owner-only role check independent of tab visibility? 4. Should xlsx be lazy-loaded to avoid bundle size impact on initial load? 5. Should the export button be disabled when there are no revealed/finished rounds? ```
Reasoning ```md wrap Let me analyze this PR carefully, going through each file change. ## Thinking ### package.json and pnpm-lock.yaml - Adding `xlsx@^0.18.5` as a dependency. This is the SheetJS library for generating Excel files. - The lockfile shows all the transitive dependencies: adler-32, cfb, codepage, crc-32, frac, ssf, wmf, word. ### src/containers/game-settings-modal.tsx - Changed the "General" menu's `role` from `['owner']` to `['owner', 'admin']`. - This means admins can now see the General settings tab, which includes the export button. - This aligns with the acceptance criteria that both owner and admin can export. ### src/containers/game-settings/general-settings.tsx - Added a new "Export" section with `SessionExportButton` component. - Placed between SessionInformation and Danger Zone sections. ### src/containers/session-export-button.tsx - New container component for the export button. - Uses `useExportSessionVotes` hook and `useSession` provider. - Has loading state with "Exporting..." text. - Shows success/error toasts. ### src/hooks/session/use-export-session-votes.ts - Simple React Query mutation wrapper around `exportSessionVotes` service. - Clean and follows the pattern of other hooks. ### src/lib/xlsx/build-votes-workbook.ts - Core utility function that builds the XLSX workbook. - Takes sessionName, participants, and roundsWithVotes. - Filters out spectators from columns. - Builds header row: `['Round', ...participantNames, 'Average']` - Each data row: `[roundIndex+1, ...voteValues, averageVote ?? '']` - Sheet name truncated to 31 chars (Excel limit). ### src/lib/xlsx/index.ts - Barrel export file following project conventions. ### src/services/session/export-session-votes.ts - Orchestrates the export flow: 1. Checks user can manage session (owner/admin) 2. Fetches session, participants, and rounds in parallel 3. Fetches votes for each round (N+1 pattern!) 4. Builds workbook and triggers download via `XLSX.writeFile` **Concerns:** 1. **N+1 query problem**: For each round, a separate `searchVotes` call is made. If there are many rounds, this could be very slow. The issue description mentions avoiding N+1 queries. We should fetch all votes for all rounds in a single query using `roundId` with `in` operator, or fetch votes by `sessionId` if that's available. 2. **`XLSX.writeFile` in service layer**: The `XLSX.writeFile` triggers a browser download. This is a side effect that happens in the service layer. It might be better to return the workbook or a Blob from the service and handle the download in the container/hook layer, but this is a minor concern. 3. **Duplicate participant names**: The acceptance criteria says "If the player name is duplicated, we might add their uids to the header after their name e.g. name-uid". The current implementation does NOT handle duplicate names - it just uses `p.displayName` directly. This could lead to confusing column headers. 4. **`buildVotesWorkbook` uses `id` for matching votes to participants**: This is correct but worth noting that it relies on participant IDs matching between the `participants` array and the `votes` array. 5. **Vote value display**: The current code uses numeric `value` directly. For t-shirt sizing, the values are 0-5 (XS-XXL). The acceptance criteria doesn't specify, but it might be nice to show display values instead of numeric values for t-shirt sessions. Actually, looking at the card definitions, t-shirt values are 0-5, so they'd just show as numbers in the spreadsheet, which might be confusing. 6. **xlsx library version**: xlsx@0.18.5 - There have been concerns about the SheetJS community edition. The package has had licensing changes. The newer versions (0.20+) moved to a different license. 0.18.5 is Apache 2.0, so it should be fine for most uses. 7. **The export button shows for all users who can see General settings**: Since admin was added to the General menu roles, admins can now also see the SessionInformationContainer (which might include session editing) and the Danger Zone (terminate session). Wait, let me re-check... The General settings tab contains SessionInformationContainer, Export section, and Danger Zone. By adding 'admin' to the General tab's role array, admins can now see ALL of these, including the terminate button. The terminate button might have its own access control, but this is worth flagging. 8. **Missing access control in the button itself**: The `SessionExportButton` doesn't check the role - it relies on the fact that only owners/admins see the General settings tab. But the service layer does check via `checkIfUserCanManageSession`, so this is fine from a security standpoint. Let me also think about whether there are missing tests or concerns: - The `buildVotesWorkbook` tests cover: sheet naming, truncation, header-only, vote filling, missing votes, spectator exclusion, sequential numbering, null average. Good coverage. - No tests for the service function or the hook, but those are harder to test (require mocking Firebase). - No test for duplicate participant names handling (because it's not implemented). Let me check the round status filter: `status: { op: 'in', value: ['finished', 'revealed'] }`. The acceptance criteria says "Each row represents one revealed/finished round". This looks correct - it includes both revealed and finished rounds. Wait, but in the issue it says "revealed/finished round" - does that mean rounds that are in "revealed" status? Looking at the Round type: status is "finished" | "in-progress" | "revealed". The AC says revealed/finished rounds, which maps to these two statuses. So the filter is correct. One more thing: the `searchVotes` query filter uses `roundId`. Looking at the indexes, there's a `votes` index on `roundId` + `updatedAt` and `roundId` + `value`. The query only filters by `roundId`, so it should be fine without a specific index. Let me also consider: should the service return something instead of void? The mutation expects a return type. Currently it returns `Promise of void`, and the `onSuccess` callback doesn't use the result. This is fine. Actually, wait - the N+1 query is a real concern. For each round, a separate `searchVotes` call. If a session has 20 rounds, that's 20 separate Firestore reads. The convention says to minimize queries and use `in` operator. We could fetch all votes for all round IDs in batches. Let me also check: does the `searchVotes` function accept `sessionId` as a filter? Looking at the Vote type, it has `roundId` and `participantId` but no `sessionId`. So we can't fetch all votes by session. We'd need to use `roundId` with `in` operator. Actually, we could batch the vote queries using `roundId` with `in` operator, fetching votes for multiple rounds in a single query. Firestore's `in` operator supports up to 30 values. If there are more than 30 rounds, we'd need to batch. Let me also note that the `useCallback` in `SessionExportButton` includes `exportMutation` in its dependency array. Since `exportMutation` is the return value of `useMutation`, it changes on every render (the mutation object is recreated). This means `handleExport` is recreated on every render, making `useCallback` essentially useless. A better approach would be to not wrap in `useCallback` or to only include stable dependencies. Actually, wait - `useMutation` returns a stable object in TanStack Query v5. Let me think... In TanStack Query v5, the returned mutation object is stable (doesn't change between renders unless options change). So the `useCallback` should work correctly here. But it's still unnecessary since the component re-renders on `isPending` change anyway. One more thing: `xlsx` library size. The xlsx library is quite large (~800KB minified). This will significantly increase the bundle size. Considerations: - Dynamic import/Code splitting: The library could be dynamically imported only when the export button is clicked, reducing initial bundle size. - Alternative libraries: There might be lighter alternatives for just writing xlsx files. The current implementation imports `xlsx` statically in the service and in the build-votes-workbook utility. This means it will be included in the main bundle. Let me also check the Players tab - it still has `role: ['owner']`. So admins can't see the Players tab, only the General tab. This seems intentional. Summary of my concerns: 1. **N+1 query**: Fetching votes per round individually 2. **No duplicate name handling**: AC mentions it should handle duplicate names 3. **xlsx bundle size**: Should consider lazy loading 4. **Admin can now see General tab**: Which includes Danger Zone (terminate). Need to verify terminate has its own role check. 5. **T-shirt vote values**: Shown as numbers (0-5) instead of display values (XS-XXL) ```
### Analysis ในรอบนี้นิลคิดว่ามันจะติ๊กถูกหมดนะะ แต่ตัว filter นี่ยังไงก็ไม่เจออะะ ซึ่งนิลก็ยังตอบไม่ได้นะครับ ว่าทำยังไงถึงให้มันเจอ แต่ขอยอมแพ้ที่ iteration นี้ล้า โฮฮฮฮฮ 😭 ไว้ว่ากันใน summary ส่วนอันที่เหลือพอให้ context ไปครบ ๆ มันก็เจอครับ แปลว่านอกจาก context ทั่วไปเกี่ยวกับ repository แล้วเนี่ย มันต้องการ requirement ของ feature นั้น ๆ รวมถึงการให้พวก business domain entity เนี่ย ก็ค่อนข้างช่วยมันให้ค้นพบ missing implementation ได้อีกด้วย ส่วนเรื่อง business context เนี่ย พอโยนเข้าไปเพิ่ม มันก็จะเจอ issue เพิ่มจริง ๆ ครับ จากตอนแรกที่นิลคิดว่าโยนแค่ `AGENTS.md`, `CONVENTION.md` หรือ พวก basic function ไปน่าจะพอ สรุป ไม่พอ มันก็ต้องการ context ครบ ๆ แบบคนนั้นแหละ ถ้า context ไม่ครบ มันก็มั่ว ๆ มา (เหมือนปรัชญายังไงก็ไม่รู้) ทีนี้เรื่องการ handle vote value ทีเป็น -1 กับ -2 ที่หายไปน่าจะเพราะว่ามันเจอตัว vote ที่เป็น T-Shirt แทนครับ คิดว่ามันอาจจะมอง 2 issues นี้ใกล้ ๆ กันจน report ตัว issue T-Shirt Vote มาก่อน นิลมานั่งดู reasoning ละเอียด ๆ อีกทีก็พบว่ามันเอาพวก minor concern ออกจาก final concern หมดเลย ซึ่งอันนี้ก็ยังเป็นอีก 1 unknown ที่นิลยังไม่รู้ว่าทำไมมันถึงไม่เอา minor concern ออกมาด้วยนะคับ ข้อสังเกตนิลคือมันตัดสินใจว่าสิ่งนี้ไม่ critical พอจะเอาของขึ้นมา ซึ่งก็เป็น unknown ว่า threshold ของมันอยู่ตรงไหนนะ #### Issue ที่นิลคาดหวังให้เจอ | Issue | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Iter 4 | Note | | ------------------------------- | ------ | ------ | ------ | ------ | ------ | --------------------------------------------------------- | | query เปลือง (spectator filter) | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ยังเจอแค่ N+1 🥹 | | handle ชื่อซ้ำ | ❌ | ❌ | ❌ | ❌ | ✅ | เจอแล้ววว คิดว่าเพราะ requirement ที่ให้ไปเพิ่ม | | xlsx bundle size | ✅ | ✅ | ✅ | ✅ | ✅ | รอบนี้ยังเตือนเรื่อง static import เหมือนเดิม | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | ✅ | ❌ | ❌ | ✅ | รอบนี้กลับมาเจอแล้ว | | Firestore Indexes | ❌ | ❌ | ❌ | ✅ | ✅ | รอบนี้เจอออ คิดว่าเพราะให้ firestore.indexes.json ไปเพิ่ม | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Iter 4 | Additional Note | | ------------------------------------------------------------------------------- | ------------ | ------ | ------ | ------ | ------ | ------ | --------------------------------------------------------------------------- | | N+1 query pattern | Performance | ✅ | ✅ | ✅ | ✅ | ✅ | ยังคงเจออยู่ | | display name → formula injection | Security | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | sheet name limit ที่ 31 ตัวอักษร | Edge Case | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ | | non-numeric vote value (อาจจะเจอ "?" หรือ "∞" ได้) | Functional | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ ไม่พูดถึงแล้วในรอบนี้ <- ซึ่งถูกแล้วที่ไม่พูดถึง | | มี browser side-effect ใน service | Code Pattern | ❌ | ✅ | ❌ | ✅ | ✅ | รอบนี้อยู่ใน reasoning แต่ไม่ได้อยู่ใน risk areas | | filename sanitization for cross OS compatibility | Edge Case | ❌ | ❌ | ✅ | ✅ | ❌ | รอบนี้ไม่ได้พูดถึง น่าจะเพราะ Requirement เรื่อง filename ที่ไม่มีเรื่องนี้ | | handle vote value (พวก vote value ที่เป็น -1 หรือ -2) | Functional | ❌ | ❌ | ❌ | ✅ | ❌ | ไม่เจอแล้ว ฮือออ ทำไมกันนะะ | | 🚀 ถ้า session ใช้ vote แบบ T-Shirt จะแสดงในตารางเป็นตัวเลขแทนที่จะเป็น S, M, L | Functional | ❌ | ❌ | ❌ | ❌ | ✅ | อันนี้ดีมาก เพราะนิลเองก็ลืมไปแล้วว่ามันมี feature นี้ในเว็บด้วย | | 🚀 disable ปุ่มเมื่อไม่มี session ที่ finished | Edge Case | ❌ | ❌ | ❌ | ❌ | ✅ | อันนี้ค่อนข้าง edge case ครับ นิลไม่ได้นึกถึงสิ่งนี้เลย | -- จบ iteration 4 -- ## ช่วงพักชม AI Code Reviewer เจ้าอื่น ก่อนที่จะปิดจบ นิลอยากรู้ว่าสิ่งที่ทำมาทั้งหมดนี้มันสู้กับ tool ที่ทำเรื่องนี้โดยเฉพาะได้ไหม นิลเลยลองส่ง PR เดิมให้ 2 เจ้าครับครับคือ [Claude Code Review](https://github.com/anthropics/claude-code-action) ที่เป็น GitHub App นะ ไม่ใช่เจ้า service ใหม่ที่ออกมาแล้วแพง ๆ นะ กับ [GitHub Copilot Code Review](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review) ครับ ซึ่งอันนี้คือผลที่ Claude review มานะ ขอเอามาแค่ part ที่มันอยากให้ปรับนะ ```md wrap ## ✅ Overall Assessment This is a **well-implemented feature** that follows the project's conventions and includes comprehensive testing. The code is clean, secure, and properly structured. ## 🔍 Minor Observations ### **Potential Enhancements** (Not blocking) 1. **File naming**: Consider adding timestamp to avoid filename conflicts ```ts // Current: `${session.name}-votes.xlsx` // Suggestion: `${session.name}-votes-${new Date().toISOString().split('T')[0]}.xlsx` ``` 2. **Export scope**: Currently only exports finished/revealed rounds. Consider adding a comment explaining this business logic choice in `src/services/session/export-session-votes.ts:27-33` ``` ส่วนของ GitHub Copilot ก็จะให้แก้พวกนี้มาครับ 1. N+1 Query 2. sheet name sanitization 3. file name sanitization 4. 🚀 function `checkIfUserCanManageSession` ไม่ throw error ออกมา ตัว Claude review นี่นิลแอบรู้สึกว่ามัน comment ออกมาน้อยมากเลยครับ ส่วนตัว GitHub Copilot ก็ยัง catch issue หลัก ๆ ที่นิลตั้งธงไว้ไม่ได้เนอะ แต่ก็เจอ issue น่าสนใจ เช่น เรื่อง function `checkIfUserCanManageSession` ที่ไม่คืน error กลับมาด้วย สิ่งที่นิลยังไม่รู้คือ tool พวกนี้มันวาง prompt/context ยังไง ใช้ agent architecture แบบไหน ซึ่งอันนี้แหละที่นิลอยากไปขุดต่อใน iteration ถัด ๆ ไป ## สรุปผลการทดลอง อย่างแรกขอเริ่มที่ผลการ iterate ไปเรื่อย ๆ ก็เจอว่า ด้วยการให้ project context, business context, issue context ไปเรื่อย ๆ ตัว AI ก็จะสามารถที่จะค้นหา potential issues ที่เราวางไว้ได้เรื่อย ๆ นะครับ แต่ก็จะมีบางจุดที่ complex จริง ๆ เช่นตัว filter ที่มันอาจจะยังจับไม่ได้ สิ่งนี้ก็ต้องหากันต่อไปว่าทำไมมันถึงไม่เจอจุดนี้นะ ทีนี้หลาย ๆ คนก็สร้าง `AGENTS.md` หรือ `CLAUDE.md` ขึ้นมา 1 file แล้วก็คาดหวังให้ LLM อ่านสิ่งนี้แล้วเข้าใจทุกอย่าง แต่ในความเป็นจริงคือ Review ด้วยว่ามันมีของครบถ้วนที่ LLM ต้องการหรือเปล่า project ของคุณมีอะไรที่พิเศษกว่าแค่ Vite React App ทั่วไปไหม ต้องส่งอะไรเพิ่มไปอีกไหม เช่นอย่างของนิลก็ต้องส่ง Firestore เข้าไป section ใหญ่ ๆ 1 อันเลยมันถึงจะเริ่ม detect เรื่อง query index นะ มาต่อในส่วนต่อไปคือปริมาณของที่ส่งไปครับ ยิ่งส่งของไปเยอะ ยิ่งใช้ token เยอะ ซึ่งจะเห็นแนวโน้มการใช้ token ที่เพิ่มขึ้นจากการให้ context เพิ่มขึ้นเรื่อย ๆ รวมถึง reasoning token ที่เพิ่มขึ้นเรื่อย ๆ ด้วยครับ แปลว่ายิ่งเรา prompt ไปเยอะเท่าไหร่ และบอกให้ตัว model มันคืน thinking ออกมา มันจะยิ่งคิดเยอะขึ้น และก็จะมีแนวโน้มที่จะได้ผลลัพธ์ที่ดีตามไปด้วยครับ ถ้าสรุป token & time usage ก็จะเป็นไปตามตารางนี้ครับ | | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Iter 4 | | ---------------- | ------ | ------ | ------ | ------ | ------ | | Reasoning tokens | 43 | 1,245 | 1,010 | 1,343 | 2,004 | | Prompt tokens | 7,199 | 7,277 | 9,278 | 10,377 | 11,578 | | Total tokens | 7,891 | 9,702 | 11,649 | 13,309 | 14,992 | | Time | - | - | 1:20 | 1:48 | 1:31 | > NOTE: 2 Iteration แรกนิลไม่ได้จับเวลาไว้นะครับ สุดท้ายก่อนสรุป goal ก็อาจจะต้องพูดถึงสิ่งที่ตั้งสมมติฐานไว้ใน iteration แรกนิดนึงครับ > ถ้า reasoning content เพิ่มขึ้น นิลคาดว่าจะเห็นได้ว่า model หยุดคิดตรงไหน และนั่นจะบอกได้ว่าต้องเพิ่ม context อะไรใน Iteration ถัดไป ประโยคนี้หลังจากนิลลองไป 4 iteration นิลพบว่ามันจริงบางส่วนอ่า จะเห็นว่า observation หลาย ๆ อย่างนิลมาจากตัว reasoning จริง ๆ เช่น เรื่องการเอา minor concern ออก หรือการเติม business context เข้าไปเพิ่ม ตัว requirement เข้าไป ก็มาจากการเห็น reasoning ของ model แต่ ๆๆๆ ถ้ามันไม่คืน reasoning อะไรออกมาเลย เราก็คิดต่อไม่ได้เลยเหมือนกันครับว่าเราต้องเติมข้อมูลอะไร เช่น เรื่องการ filter spectator เป็นต้น ขอเอาตารางสรุปมาลงตรงนี้อีกทีเพื่อให้เห็นกันชัด ๆ ไปเลยว่าแต่ละ iteration เราผ่านอะไรกันมาบ้าง #### Issue ที่นิลคาดหวังให้เจอ | Issue | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Iter 4 | | ------------------------------- | ------ | ------ | ------ | ------ | ------ | | query เปลือง (spectator filter) | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | | handle ชื่อซ้ำ | ❌ | ❌ | ❌ | ❌ | ✅ | | xlsx bundle size | ✅ | ✅ | ✅ | ✅ | ✅ | | สิทธิ์ admin เห็น sidebar เพิ่ม | ✅ | ✅ | ❌ | ❌ | ✅ | | Firestore Indexes | ❌ | ❌ | ❌ | ✅ | ✅ | #### Issue ที่ GLM เจอเพิ่ม | Issue | Issue Type | Iter 0 | Iter 1 | Iter 2 | Iter 3 | Iter 4 | | ---------------------------------------------------------------------------- | ------------ | ------ | ------ | ------ | ------ | ------ | | N+1 query pattern | Performance | ✅ | ✅ | ✅ | ✅ | ✅ | | display name → formula injection | Security | ✅ | ✅ | ❌ | ❌ | ❌ | | sheet Name limit ที่ 31 ตัวอักษร | Edge Case | ✅ | ✅ | ❌ | ❌ | ❌ | | non-numeric vote value (อาจจะเจอ "?" หรือ "∞" ได้) (อันนี้ไม่ควรเจอ) | Functional | ❌ | ✅ | ❌ | ❌ | ❌ | | มี browser side-effect ใน service | Code Pattern | ❌ | ✅ | ❌ | ✅ | ✅ | | filename sanitization for cross OS compatibility | Edge Case | ❌ | ❌ | ✅ | ✅ | ❌ | | handle vote value (พวก vote value ที่เป็น -1 หรือ -2) | Functional | ❌ | ❌ | ❌ | ✅ | ❌ | | ถ้า session ใช้ Vote แบบ T-Shirt จะแสดงในตารางเป็นตัวเลขแทนที่จะเป็น S, M, L | Functional | ❌ | ❌ | ❌ | ❌ | ✅ | | disable ปุ่มเมื่อไม่มี session ที่ finished | Edge Case | ❌ | ❌ | ❌ | ❌ | ✅ | อะ งั้นกลับมาที่ goal ของนิล 3 ข้อกัน - ✅ อยากลองเล่น AI with TypeScript ดู - อันนี้อาจจะได้ลอง openai sdk ครับ แล้วก็พอเข้าใจแล้วว่าทำไมเขาถึงมีพวก [vercel ai sdk](https://ai-sdk.dev/docs/introduction), [Mastra.ai](https://mastra.ai/) หรือ [VoltAgent](https://voltagent.dev/) ครับ การขึ้นเองจาก 0 น่าจะยาก แถมถ้าต้อง orchestrate agent อีกน่าจะไม่รอดแน่ ๆ - ❌ อยากเข้าใจ agent architecture มากขึ้น - อันนี้ไม่ได้ทำเลยครับ แค่ prompting กับ context engineering ก็หมดเวลาแล้ว ฮืออออ - ✅ อยากได้ tteration ถัดไปของ code review agent - อันนี้เห็นภาพมากขึ้นนะ เริ่มเข้าใจละว่าทำไมรอบแรกมันถึงไม่ work แล้วเราจะเริ่มทำให้มัน work ขึ้นได้ยังไง รวมถึงใน iteration นี้ นิลสามารถทำให้มัน catch known potential issue ได้ 4 จาก 5 อัน (80%) และได้ unknown issues มาอีกเพียบเลย (4 อันใน iteration สุดท้าย) นิลว่ามัน work เลยนะ ทีนี้จาก goal ข้อ 3 เนี่ย ทำให้นิลกลับมาคิดครับว่าจริง ๆ ที่นิลทำตอนนี้มันคือการส่ง context ให้ AI แบบทีละ file ซึ่งตอนนี้เป็นนิลเองที่ตัดสินใจว่าจะส่ง context อะไรบ้าง แต่ในความเป็นจริง ลองคิดดูสิครับว่าถ้านิลจะ reivew PR ไหนแล้วต้องส่งไปเองว่าต้องใช้ file ไหนบ้าง สู้ review เองแล้วประหยัด token ไปไม่ดีกว่าหรอ 🤔 แต่เกมส์อาจจะเปลี่ยนเล็กน้อยครับ ถ้าใน iteration หน้า นิลสามารถทำให้ AI มันช่วย list file ที่เกี่ยวข้องเพื่อส่งไป review ด้วย ตัว AI ก็จะได้ context ที่เกี่ยวข้องอย่างครบถ้วน ซึ่งถ้าเราทำได้จริง มันน่าจะช่วยลดแรงนิลในการ catch potential issues ได้ดีเลยครับ สิ่งที่ได้ Learning เลยคือสุดท้ายตัว AI มันมีความฉลาดส่วนตัวของมันประมาณนึงแหละ ดูจาก iteration แรกที่เราแทบไม่ให้อะไรเลย มันก็เจอ unknown issue อีกเพียบ แต่ในขณะเดียวกัน มันก็ยังต้องการ basic context ที่เกี่ยวกับ project เราอยู่นะครับ อันนี้แอบมองว่าเหมือนเราต้อง train น้อง junior คนนึงเลย อย่าลืมใจดีและให้ context project กับน้อง ๆ เหมือนที่เราทำกับ AI กันนะครับ 🥹 --- จบไปแล้วกับ ~~Weekend~~ Holiday Hack ช่วงสงกรานต์คร้าบ เป็น blog ที่ใช้พลังสูงที่สุดเท่าที่เคยเขียนมาเลยครับเพราะใช้ 3 วันในการทำสิ่งนี้ครับ แต่บอกเลยว่าอย่างมันส์เพราะตอนแรกนิลคิดว่าแปปเดียวก็เสร็จเดี๋ยวเอาเวลาที่เหลือไปนั่งเล่นเกมส์ ทำ side project อื่น สรุปกิน 3 วันเต็ม (ฮา) รอบนี้ไม่ได้ celebrate small win ด้วยการกินแหละครับ แต่เดี๋ยวไปนั่งเล่นเกมส์ชิว ๆ เอา ทุกคนอย่าลืมพักผ่อนกันด้วยน้า รอบหน้าเดี๋ยวนิลจะทำไรหนุก ๆ อีกเดี๋ยวมาแชร์กับทุกคนนะครับ 😎 ขอให้สนุกกับการทดลอง นิล ## Links used in this experiments อ้อๆๆๆ นิลแปะลิงก์ของ Experiment Repository กับ Pull Request ไว้ดีกว่า เผื่อใครอยากเห็น data หรืออยากลอง [Experiment Repository](https://github.com/peeranat-dan/weekend-hack-code-review-agent-typescript) [E-Mate PR: Add export as xlsx function](https://github.com/peeranat-dan/scrum-poker/pull/290) --- # Weekend Hack: ลองแก้ Bottleneck การรีวิว Pull Request ขนาดกลางและใหญ่ - URL: https://blog.ninprd.com/blog/weekend-hack-solving-medium-large-pull-request-review/ - Published: 2026-03-19 - Tags: dev, weekend-hack, n8n, automation, ai, Y2026 - Summary: PR ใหญ่ขนาดไหนถึงจะ "ใหญ่เกินไป"? นิลลองสร้าง Workflow ด้วย n8n และ Kimi K2.5 เพื่อคำนวณ PR Complexity และให้ AI ช่วย Review แทน จะเป็นยังไง ไปดูกันครับ สวัสดีครับ ช่วงนี้นิลกำลังเจอปัญหาเกี่ยวกับ PR Size กลาง - ใหญ่หลาย ๆ อันเข้ามาใน Sprint ครับ และนิลยังติดอยู่ใน Loop เก่ามั้งครับ ที่ Code จำนวนมากกำลังหลั่งไหลมาให้นิล Review ซึ่งใน Sprint ที่แล้วนิลก็ Review ไปเยอะมากเลยครับ ช่วงวันอาทิตย์นิลว่าง ๆ เลยนั่งคิดดูครับว่าจะแก้ปัญหานี้ยังไงดี ## Crack ปัญหากันก่อนจะ Hack ปัญหาของนิลตอนนี้คือ 1. ในทีมเปิด PR ขนาดกลางกับใหญ่มาเยอะ ทำให้นิลใช้เวลา Review เยอะ แต่จริง ๆ แล้วนิลไม่ได้มีเวลาเยอะขนาดนั้นในการ Review เพราะยังต้องรับผิดชอบของใน Sprint อยู่ 2. มุมมองของนิลคือ การเปิด PR ขนาดใหญ่ ทำให้เหนื่อยคนที่ต้อง Review และเพิ่ม Cognitive Load ให้กับ Reviewer โดยไม่จำเป็น ซึ่งตัวนิลเองมี Condition เหล่านี้อยู่ครับ 1. ช่วงนี้ทีมอยู่ใน Priority mode ที่โฟกัสเรื่อง Delivery ก่อนเป็นหลัก Code Quality/Code Review อาจจะเป็นเรื่องรอง 2. แต่ทั้งนี้ทั้งนั้น นิลต้องรับรู้ว่า Code ที่น้องในทีมเพิ่มเข้ามา สร้าง Impact อะไรให้กับระบบหรือมีกระทบ Business Logic อะไรบ้าง 3. นิลไม่มีสิทธิ์ในการ Add Custom App เข้า GitHub บริษัท แปลว่านิลไม่สามารถเพิ่มพวก Claude App ในบริษัทได้ ## แล้วนิลทำอะไรเพื่อแก้ปัญหาล่ะ ในมุมนิลสิ่งนี้ดูสามารถแก้ได้ที่หลายจุดครับ นิลมองในแง่ที่ง่ายที่สุดก่อนคือการแก้ให้กับตัวเองก่อนซึ่งนิลก็คิดว่าถ้าสร้าง Workflow อันนึง ให้ AI Model ไปอ่าน git diff จาก PR แล้วก็ช่วยสรุปส่วนที่สำคัญและ Business Logic ที่มันทำ รวมถึง Impact/Possible Flaws ของ Code ที่เอาเข้าไป โดยให้มันสรุปสั้น ๆ และ Sacrifice Grammar ทิ้งไป ถ้ามันไม่มีอะไรที่น่าเป็นห่วง นิลก็สามารถที่จะ Accept PR บางอันไปด้วยความไม่ต้องไปอ่าน Code ทั้งหมดแล้ว Prompt ที่นิลเขียนไปก็ประมาณนี้ครับ ```md You are a senior software engineer reviewing a PR for the engineering team. The user will provide the git diff and PR complexity metadata. Always structure your response in this exact format: ## Summary What this PR does in 2-3 sentences. ## Files Changed Key files and their roles. Be extremely concise. ## System Impact Which system components are affected and how. ## Risk Areas Potential breaking changes or side effects. If none, say "None identified." ## Suggested Focus Where reviewers should pay most attention. Sacrifice grammar for the sake of concision. Use bullet points, not paragraphs. ``` อีกส่วนนึง นิลยังเชื่อในมุม Engineering Practice ครับว่า Pull Request ไม่ควรใหญ่หรือซับซ้อนเกินไปเพื่อให้มนุษย์ทุกคนในทีมสามารถทำงานร่วมกันอย่างง่ายดาย นิลเลยมองว่านิลอยากเพิ่ม Label ใน Pull Request ว่า Pull Request นี้ซับช้อนแค่ไหน ซึ่งสูตรในการคำนวณเนี่ย นิลก็ขอยืมมาจากของ Atlassian ที่ใช้ในงาน Developer Productivity Engineering 2024 นะครับ ซึ่งเขาก็มีการ[คำนวณสูตรคร่าว ๆ จากใน Repository นี้แหละครับ](https://bitbucket.org/atlassian/forge-bitbucket-pr-complexity-score/src/main/src/prComplexity.ts) ทีนี้นิลก็เอาสูตรมาดัดแปลงต่อเพื่อให้เข้ากับน้อง ๆ ในทีมมากขึ้นครับ นิลกลับไปนั่งใน Get Git Diff มาเพื่อเช็คว่าโดยเฉลี่ยแล้วทีมนิลจะเปิด Pull Request มาประมาณไหน ซึ่งนิลก็ปรึกษาเจ้า Claude เพื่อให้ได้สูตรคำนวณออกมาครับ ซึ่งเราก็จะได้สูตรตามนี้ $$\Sigma Score=0.4×Score_{LoC}​+0.6×Score_{File}$$​ หลัก ๆ แล้วในมุมของ Atlassian ค่า Complexity ของ Pull Request นั้นขึ้นอยู่กับจำนวนบรรทัด (LoC) กับจำนวนไฟล์ (File) ที่มีการแก้ไขภายใน PR นั้น ๆ ครับ (จริง ๆ ของต้นทางเขาจะเอาบรรทัด Comment ที่เพิ่มมาคิดด้วยนะ แต่นิลขอถอดความวุ่นวายนั้นออกไปก่อน) และนิลก็ได้เพิ่มส่วนการถ่วงเฉลี่ยเพราะการที่แก้ไฟล์เยอะ แปลว่า 1 PR เราอาจจะเจอ Context เยอะมาก นิลเลยถ่วงฝั่ง File เยอะกว่านิดนึง (เพื่อการทดลอง) ซึ่ง ๆ จาก Complexity ตรงนี้นิลมองว่ามันสามารถเข้าไป Integrate เข้ากับ GitHub ได้เพื่อติด Label ไว้ว่า Pull Request นี้ขนาดเท่าไหร่ ซึ่งถ้าใครในทีม (รวมถึงนิลด้วยนะ) เปิด PR ขนาด High/Critical มาบ่อย ๆ เนี่ย นิลว่าเราน่าจะต้องคุยกันแล้วแหละ 👀 555555555555 แค่อยากให้เราทำงานกันง่ายขึ้นนะ 🥹 ## เอาล่ะ Crack เสร็จแล้ว ก็เข้าสู่ช่วง Hack Weekend อย่างแรกนิลมานั่งคิด Flow เล่น ๆ ครับ นิลคิดว่า Flow มันน่าจะเป็นแบบนี้นะ ```md 0. (Trigger): เมื่อมีคนเปิด PR มา / Rebase Branch 1. ดึงข้อมูล `git diff` 2. คำนวณความซับซ้อน (Pull Request Complexity Calculation) 3. ติด Label ใน GitHub 4. ส่งไปให้ AI สรุป 5. เอาสรุปจาก AI มา Comment กลับใน GitHub ``` ซึ่งนิลก็กลับมาคิดอีกทีว่า ถ้า PR เล็ก ๆ แล้ว นิลก็ไม่ต้องพึ่ง AI นี่นา นิลก็เลยคิดว่านิลจะส่งให้ AI ต่อเมื่อ PR นั้นขนาดกลางขึ้นไป นั่นคือ Complexity มากกว่า 300 ครับ ซึ่งน่าจะช่วยลดค่าใช้จ่ายให้นิลได้ ในส่วนต่อไปหลังจากนิล List แล้วว่ามันมีขั้นตอนอะไรบ้างนิลก็จะมาดูที่ Tools ครับว่านิลจะใช้อะไรเพื่อตอบโจทย์บ้าง ```md 0. (Trigger): เมื่อมีคนเปิด PR มา / Rebase Branch -> GitHub Webhook 1. ดึงข้อมูล `git diff` -> GitHub API 2. คำนวณความซับซ้อน (Complexity Calculation) -> Code 3. ติด Label ใน GitHub -> GitHub API 4. ส่งไปให้ AI สรุป -> ??? 5. เอาสรุปจาก AI มา Comment กลับใน GitHub -> GitHub API ``` จะเห็นว่านิลยัง Question Mark กับ AI นะครับเพราะ AI ในตลาดเนี่ยก็มีหลายเจ้ามาก นิลก็ไม่รู้ว่าเจ้าไหนเนี่ย Review Code ได้ดีมั่ง ซึ่งช่วงนี้นิลเจอ Post Facebook หลายอันเกี่ยวกับเจ้า Kimi K2.5 ว่าเก่งด้าน Coding แบบเทียบ ๆ Claude ในราคาที่ถูกกว่ามาก ทำให้นิลสนใจที่จะใช้เจ้า Kimi K2.5 กับ Project นี้มาก (เพราะหนูจน หนูไม่มีตังค์ 555555555) ส่วนตัว Platform ที่นิลจะใช้ Run workflow นี้ก็แน่นอนว่าต้องเป็น n8n คนดีคนเดิม 555555 นิลมองว่าไหน ๆ นิลมี n8n ที่เคยตั้งค่าพวก GitHub Credentials ไว้แล้ว นิลก็ทำใน n8n ไปเลยละกัน ซึ่งพอทำเสร็จแล้วนิลก็จะได้ Workflow หน้าตาประมาณนี้ครับ ![](assets/workflow-code-review.webp) ซึ่งนิลใช้เวลาประมาณ 3 ชั่วโมงกับ Flow ทั้งหมดนี้แหละ ซึ่งโดยคร่าว ๆ นิลมองว่าตอนนี้มันน่าจะช่วยนิลได้แหละ เดี๋ยวผ่านไปอีกซักพักนิลจะเอาผลลัพธ์มาเล่าให้ฟังว่ามันช่วยแก้ปัญหาให้นิลไหม 5555555 ## Learning หลังลองไป 2 วัน นิลเอา Workflow นี้ไปลอง 2 วันครับ โดยวันแรกลองใช้ Kimi K2.5 และวันที่ 2 ลองใช้ Claude Sonnet 4.6 ดูเพื่ออยากลองเปรียบเทียบผลลัพธ์ ซึ่งนิลได้ Learning แบบนี้กลับมาครับ 1. การออกแบบ Prompt ของ AI Agent `!==` การออกแบบ Prompt ของ Code Reviewer Agent: ปกติแล้ว เวลาเราเขียน Prompt คุยกับพวก AI Agent ที่อยู่ใน Code Editor หรือ Terminal เราจะก็คุยแค่สิ่งที่อยากได้ แต่เรื่อง Structure ของ Repo เนี่ย มันจะเข้ามาอ่านเองเนอะ แต่ Code Review Agent ที่นิลออกแบบมามันไม่ได้ทำงานงั้นอ่า มันเอาแค่ Git Diff ไปวิเคราะห์เลย แปลว่ามันไม่รู้ Context เลยว่า Repo นี้ทำอะไร มันก็จะสรุปกลับมาแบบที่มันเข้าใจอะคับ (ซึ่งอาจจะถูกหรือไม่ถูกก็ได้) 2. ควรตั้งสติตอนออกแบบ Workflow: จากที่เห็น Workflow จะเห็นว่าสายมันระโยงระยางเต็มไปหมดเลยครับ นั่นเป็นเพราะตอนที่ทำนิลคิดไม่รอบเองว่ามันสามารถตัดไอสายระโยงระยางฝั่งขวาได้เลย 3. ควรออกแบบ Flow ให้ดี: นิลออกแบบให้ Flow นี้ Trigger ทุกครั้งที่ Synchronize (Rebase Branch มา) แปลว่ามัน Trigger Review ทุกรอบเลย บอกเลยว่าค่า Token นี่แอบจุกสุด ๆ ยิ่งพอวันที่ 2 ลองย้ายมาใช้ของ Claude แล้วเนี่ย กิน Token สุด ๆ เลยครับ 4. ควรมี Skip Files หรือ Skip Labels: เช่นพวก `package-lock.json` `yarn.lock` หรือ `pnpm-lock.yaml` หรือถ้ามีเป็น File เกี่ยวกับ Migration ควรไม่เอาไปคิด Complexity ด้วย เพราะไม่งั้นยังไงก็ Complexity สูงทันทีครับ ## ท้ายที่สุดแล้ว นิลใช้อะไร และไม่ใช้อะไรบ้าง? สุดท้ายตัว Workflow ที่นิลใช้เหลือแค่ส่วนที่ Apply Complexity Label ครับ อันนี้ได้รับ Feedback ที่ดีเรื่องการช่วย Set Expectation ก่อนเข้ามาอ่าน Review ว่าจะเจอ Context หนักแค่ไหน และก็ยังต้องปรับปรุงสูตรคำนวณให้เหมาะกับน้อง ๆ ในทีมมากขึ้นด้วย ส่วน AI Review เดี๋ยวขอไปวาง Flow ดี ๆ ก่อน เดี๋ยวลองมาลุยอีกครั้งครับ มาแน่ เย่! --- ก็จบไปแล้วกับ Blog แรกของ 2026 และเป็นการทำ Weekend Hack ครั้งแรกของนิลในปีนี้ครับ ตอนแรกนิลว่าจะแก้ปัญหาเรื่องการช่วยสรุป PR แต่ก็ได้ Learning เรื่องพวก AI กับการออกแบบ Workflow มาแทน 55555 ทำสิ่งนี้เสร็จนิลก็ไปกินข้าวหมูทอดร้านโปรดฉลอง Small Win 1 ที เย้ 555555 ขอบคุณทุกคนที่อ่านมาถึงตรงนี้ด้วยนะครับ เดี๋ยวปีนี้มีอะไรสนุก ๆ อีกแน่นอน ขอให้ทุกคนสนุกกับการลองแก้ปัญหาอะไรซักอย่าง นิล --- # 2025 Year In Review - URL: https://blog.ninprd.com/blog/2025-year-in-review/ - Published: 2025-12-21 - Tags: year-in-review, Y2025 - Summary: จะจบปี 2025 แล้ว นิลทำอะไรไปมั่ง มาดูกัน สวัสดีครับทุกคนที่ยังอ่าน blog ของนิลอยู่นะครับ 🥹 ปีนี้เป็นยังไงกันบ้างครับ หวังว่าทุกคนคงจะสบายดีนะครับ สำหรับนิลแล้ว ปีนี้เป็นปีที่เหนื่อยเอาตายเลยครับ มีเรื่องราวเกิดขึ้นมากมาย (ซึ่งส่วนใหญ่จะเป็นงาน 5555555) และก็ตามธรรมเนียมของทุกปีครับ ที่นิลจะมี Year In Review ที่จะมาสรุป Highlight/Lowlight ของนิลปีนี้ จะเป็นยังไง ไปดูกันเลยครับ ## บินไปดู Fan Meet ครั้งแรก สิ่งนี้เกิดขึ้นจากการที่พี่ Senior ที่เคยดูแลนิลช่วงแรก ๆ ที่ออฟฟิศมาโชว์ [post นึงของเพจเชียงใหม่ว้าวมาก](https://www.facebook.com/share/p/1CoWrqYDQV/) ซึ่งเป็นการจัด Fan Meet พี่เอิ๊ต ภัทรวีกับวง SERIOUS BACON และจัดฟรี ✨ แต่จัดที่เชียงใหม่นะ 55555 ซึ่งนิล FC พี่เอิ๊ตละอยากไปมากกก ซึ่งชวนกันลงทะเบียนวันพุธ รู้ผลวันศุกร์ว่าได้ไป กดตั๋วเครื่องบินวันเสาร์ ละงานจัดวันอังคารถัดไป บอกเลยว่าสุดจัด 5555555555 สุดท้ายวันอังคารนิลก็บินจากกรุงเทพไปเชียงใหม่ช่วงเช้าแล้วก็ได้ไปฟังพี่เอิ๊ตร้องเพลง เหมือนได้ฟัง Mini Concert ที่เชียงใหม่ด้วยแหละ นับว่าเป็นประสบการณ์ที่แปลกใหม่และหาทำมาก 5555555 ละวันต่อมานิลก็ได้ไปนั่งดื่มกาแฟและชมบรรยากาศแถว ๆ นิมมานยามเช้าด้วย เป็นสิ่งที่ทำให้นิลอยากมาเชียงใหม่อีกครั้งเลยครับ ปีหน้าไปซ้ำอีกแน่นอน 😁 ![](assets/airport-to-cnx.webp) ## กล้ารับงานนอก WordPress แล้ว ก่อนหน้านี้นิลทำงานประจำในบริษัทด้วย WordPress อยู่ Project นึงซึ่งนิลก็ได้ทำ[คอร์สสอน Basic WordPress ง่าย ๆ ไว้ในนี้](https://learn.ninprd.com/)ครับ แต่นิลก็ยังไม่มีโอกาสที่จะรับงานนอกที่เป็น WordPress เลยครับ ซึ่งนิลมีติดอยู่ 2 เรื่องคือโอกาสกับความกล้าครับ นิลรู้สึกว่ากลัวจะทำไม่ได้แหละ จนกระทั่งมีโอกาสมาจากน้องที่เคยเจอกันตามงาน Conference น้องก็ได้ชวนไปทำเว็บไซต์โดยใช้ WordPress เป็น Solution ครับ นิลเลยตัดสินใจรับดูครับ ใน Part ของ Web Structure นิลไม่ติดเลยครับ แต่นิลแอบ Struggle กับการทำ Styling นิดนึงครับ เพราะเป็น Tailwind Bro แบบเต็มตัว เริ่มจำ CSS จริง ๆ ไม่ได้แล้ว ซึ่งแทนที่นิลจะแก้ปัญหาให้ตรงจุดคือการไปนั่งจำ syntax CSS นิลกลับซื้อ Plugin automatic.css มาครับ ซึ่งทำให้นิลสามารถใช้ styling แบบคล้าย ๆ Tailwind ใน WordPress ได้ครับ บอกเลยว่าฟินมาก 55555555 ซึ่งการรับงานครั้งนี้ก็แอบปลดล๊อคนิลว่าจริง ๆ นิลก็รับงานแนว ๆ นี้ได้นี่นา ปีหน้าถ้ามีโอกาสก็น่าลองทำอีกนะ เป็นอะไรที่ดีและสนุกมากเลย ## ได้ Lead Team ใหญ่ครั้งแรก ปีที่แล้วนิลเล่าใน [2024 Year In Review](2024-year-in-review.md) ว่านิลได้ลอง Lead Team ครั้งแรก ซึ่งในตอนนั้นก็เป็น Lead ทีมนึง (ดูแลทีม 3 คน) ในทีมใหญ่ (12 คน) แต่ปีนี้บอกเลยว่าไปกันต่ออออ เพราะนิลได้ Lead Dev Team นึงซึ่งดูแลการส่งมอบโปรเจคแบบเต็มตัว ออกแบบ Architecture ของ Project ดูแลเพื่อน/น้องในทีมด้วย บอกเลยว่า ว้าว ว้าว ว้าววว เหนื่อยมาก 555555555 รู้สึกว่าใหญ่เกินตัวนิลไปมากกก ซึ่งผ่านหน้าที่ Team Lead มาปีกว่านิลก็รู้สึกว่านิลยังมีจุดที่ต้อง Improve ไปเรื่อย ๆ จากที่ปีที่แล้วบอกว่าจะศึกษาเรื่อง People เพิ่มก็ยังไม่ได้ทำ มัวแต่ปั่นงานให้เสร็จ ยังคงเป็นนักดับเพลิงอยู่ววว TT ได้แต่บอกตัวเองว่า ฮึบๆ ปีหน้าว่ากันใหม่ ## กล้าจ่ายตังเรียนคอร์สสด เมื่อก่อนนิลจะรู้สึกว่าการจ่ายตังเรียนอะไรซักอย่างนึงเป็นเรื่องที่แพง (เพราะสวัสดิการของพนักงาน Skooldio คือเรียนคอร์ส + Workshop ของ Skooldio ฟรียังไงล่ะ 😎) ยิ่งถ้าคอร์สสดแล้ว นิลจะมีอีกปัจจัยที่จะไม่ไปคือไม่กล้าเจอคน 555555 ไม่ชอบการเจอคนประมาณนึง แต่พอปีที่ผ่านมานิลได้ไป Meetup/Conference เยอะ ๆ เรื่องความกลัวคนก็ลดลงประมาณนึงครับ ซึ่งในจังหวะที่นิลกำลังคิดเรื่องนี้ นิลก็ไถเฟซไปเจอ[โพสต์ที่พี่ตรังจากเพจ Growth Game มาเปิดสอนคอร์ส Personal Strategy](https://www.facebook.com/share/p/17Wc5xr4v2/) พอดีครับ ทำให้นิลเลือกตัดสินใจไปลง ซึ่งก็ถือว่านิลตัดสินใจไม่ผิดเลย ได้อะไรกลับมาเยอะมาก เข้าใจภาพของการออกแบบชีวิตตัวเองมากขึ้น เรียกได้ว่าสุดยอดมาก แนะนำให้มาเรียนกันครับ (ps. เดี๋ยวนิลมีรีวิวลง blog อีกที รอติดตาม review กันได้ครับ แต่แนะนำให้ไปเรียนสดกันนะะ) ซึ่งพี่ตรังก็พูดเล่น ๆ ว่าจะเปิดคอร์สนี้ปีละครั้งแหละ 555555555 ใครสนใจติดต่อทาง[เพจ Growth Game](https://www.facebook.com/GrowthGameIdea) กันไปก่อนเลย เผื่อพี่ตรังจะยอมเปิดมากกว่าปีละครั้งครับ 🤣 ![](assets/personal-strategy-by-growth-game.webp) ## กล้าซื้อตั๋ว Fan Meet ปีนี้นอกจากซื้อคอร์สแล้ว นิลยังกดตั๋วไปดู Fan Meet ของ Spin9arm ซึ่งวันที่กดก็งัวเงียมากเพราะกดตั๋ว 9 โมง 9 นาที นิลตื่นมา 9 โมง แต่ก็ได้ไปดูแหละ ถือว่าเปิดประสบการณ์ดีครับ เพราะนิลก็ไม่กล้าไปงานอะไรแบบนี้เท่าไหร่ แต่พอไป Conference กับ Meetup บ่อย ๆ ก็พอจะรู้สึกว่าตัวเองไม่ Awkward ตรงนั้นแหละ ![](assets/spin9arm-fanmeet.webp) ## ได้ Organize Event ด้วย อันนี้เป็นสิ่งที่เกิดขึ้นงง ๆ เพราะอยู่ดี ๆ วันนึงพี่อั้ม WordPress Bangkok ก็ทักมาชวนนิลไปช่วยกันจัด WordCamp Bangkok 2025 แหละ ซึ่งนิลก็กล้า ๆ กลัว ๆ เพราะว่าไม่มีประสบการณ์การจัดงาน Conference เลย แต่พี่อั้มก็บอกว่าให้นิลมาลองแหละ ซึ่งตอนแรกนิลก็ได้ทำทีม Contributor กับ Speaker แต่ด้วย Load งานประจำของนิล นิลเลยเหลือรับแค่ทีม Speaker แหละ การทำทีม Speaker ทำให้นิลได้รู้ขั้นตอนการตามหา Speaker ขั้นตอนการรีวิวสไลด์ รวมถึงรู้ว่าตัวเองควรปรับปรุงเรื่องวิธี Approach Speaker และวิธีการเตรียมข้อมูลเพื่อให้ทีมอื่น ๆ ทำงานง่ายขึ้นด้วย และที่สำคัญได้เรียนรู้วิธีการใช้ Walkie Talkie ด้วย โคตรจะเท่ รู้สึกว่าได้ Learning เยอะแยะไปหมดเลย เปิดช่วง Honorable Mention ขอขอบคุณพี่อั้มที่ชวนมาทำอะไรสนุก ๆ พี่ยูกิที่มาช่วย Support ทุก ๆ อย่างใน WordCamp และก็นิวมาก รวมถึงพี่ ๆ ทีม Organizer คนอื่น ๆ รวมถึงน้อง ๆ Volunteer ด้วยครับ เหนื่อยและสนุกมาก หวังว่าจะได้ร่วมงานกันอีก ![](assets/wordcamp-bangkok-2025.webp) --- รีวิว Action Item ที่ทิ้งไว้ใน Year In Review ปีที่แล้วกันดีกว่า - เขียน blog ที่ Content Technical มากขึ้น ❌ เขียนได้ตอนเดียว เรียกว่าทำได้ไหมนะ 555555 - เปลี่ยนชื่อเพจ ❌ สรุปคิดว่าไม่เปลี่ยนละ ตอนนี้ชื่อเพจยาว แต่มีแต่คนจำได้ 555555 - อ่านหนังสือมากขึ้น ❌ จบ 1 เล่มเท่าเดิม 🤣 เป็นปีที่ไม่ได้ทำ resolution อะไรได้สำเร็จเลย แต่ก็สนุกดีนะปีนี้ ปีนี้เหมือนนิลใช้ชีวิตแบบ กุมภา มีนา และก็กระโดดมาต้นตุลา รู้สึกตัวอีกทีก็ปลายธันวาเลยครับ เป็นปีที่เร็วมากสำหรับนิล แล้วสำหรับทุกคนล่ะครับ เป็นไงกันบ้าง ทักมาแชร์กันได้นะครับ หวังว่าปีหน้าทุกคนจะได้ทำในสิ่งที่อยากทำกันนะครับ และก็ขอบคุณทุกคนที่อ่านมาถึงตรงนี้ด้วย --- # จด ๆ จากงาน Typhoon เฮ็ดให้ AI ใจอีสาน - URL: https://blog.ninprd.com/blog/typhoon-ai-isan/ - Published: 2025-11-27 - Tags: ai, Y2025 - Summary: สวัสดีครับ วันนี้นิลไปงาน Typhoon เฮ็ดให้ AI ใจอีสานมาครับ มาดูสิ่งที่น่าสนใจที่นิลจดมากัน สวัสดีครับ วันนี้นิลไปงาน Typhoon เฮ็ดให้ AI ใจอีสานมาครับ มาดูรายละเอียดที่นิลจดมากัน ## Keynote: AI for Low Resource Languages: TYPHOON จากปัญญาประดิษฐ์เชี่ยวชาญภาษาไทยสู่ภาษาถิ่น ความเชื่อของทีม Typhoon คืออยากให้ AI เข้าใจภาษา แต่ไม่ใช่แค่ภาษากลาง แต่ควรมีทุกภาคเลย ในช่วงปีนี้ Typhoon ออก Model ใหม่เยอะมาก ซึ่งตัวที่เด่น ๆ เลยคือ Typhoon ASR (Automatic Speech Recognition) ซึ่งมีจุดเด่นเรื่องความเร็วโดยสามารถถอดความแบบ Real Time ได้ และมีราคาถูกกว่า Commercial Model กว่า 400 เท่า ทั้งนี้ตัว Typhoon ASR ยังมี Gap เรื่องภาษาที่รองรับเพราะยังรับได้แค่ไทยกลาง ทีมเลยมี Initiative ที่จะทำ Model ภาษาถิ่น ซึ่งในประเทศอื่นก็มีความคิดที่จะทำภาษาถิ่นของประเทศตัวเอง เช่น Africa, India, หรือ Middle American ที่เลือกภาษาอีสานเพราะคนอีสานเป็น 1/3 ของประเทศไทยและมี GDP 1/10 ของประเทศ นอกจากนี้ยังมีความเด่นเรื่องการแพทย์และสุขภาพ สิ่งที่ Typhoon เปิดตัววันนี้มี 3 อย่างคือ - **Typhoon Isan ASR (Automatic Speech Recognition)**: Model ถอดเสียงภาษาอีสาน - *Typhoon Isan ASR Real-Time*: เหมาะกับงานถอดเสียงสด Model เล็ก ใช้ทรัพยากรต่ำ - *Typhoon Isan ASR Whisper*: เหมาะกับงานถอดเสียงสำหรับไฟล์ที่บันทึกมาก่อนแล้ว Model ใหญ่ ใช้ Resource เยอะ แต่แม่นยำขึ้น - **Typhoon Isan Speech Corpus**: Open-source คลังข้อมูลเสียงภาษาอีสาน - Isan Speech Corpus: ชุดข้อลูเสียงพูดพร้อม Transcription - Isan Spelling Standard: มาตรฐานการสะกดคำอีสานออกแบบโดยอิงหลักภาษาศาสตร์ - Isan Speech Transcriptipn Convention: แนวทางการถอดเสียงอีสานเชิงภาษาศาสตร์ - Phoenetic Dictionary: พจนานุกรมอักษรจับคู่คำอีสานกับการอ่าน - **Typhoon Isan TTS (Text to Speech)**: Model สังเคราะห์เสียงภาษาอีสาน --- ## Panel Discussion: Behind the Scene: เบื้องหลัง TYPHOON AI ภาษาอีสาน โปรเจคนี้ใช้เวลาประมาณ 1 ปีโดยมีความยากที่ภาษาอีสานเป็น Very Low Resource Language การเก็บข้อมูลยากมาก รวมถึงต้องดู Landscape ของภาษาอีสานและ Dataset ที่มีด้วย รวมถึงภาษาอีสานยังมี Gap เรื่อง Spelling Standard เพราะมีแต่ภาษาพูดแต่ไม่มีภาษาเขียนที่ตายตัว จึงต้องมี Linguist มากำหนด Process ของการทำงานของข้อมูลให้ชัด ### กระบวนการการจัดการข้อมูลของนักภาษาศาสตร์ 1. **กำหนดนิยามของภาษาอีสาน** - หา Common Ground ของภาษา เราจะนับว่าใครพูดภาษาอีสาน? ใช้เกณฑ์ของภาษาศาสตร์ - ใครพูด 6 วรรณยุกต์ = เอามาเป็น Data 2. **กำหนดระบบสะกดคำ** - ต่างคนต่างสะกดไม่เหมือนกัน หลัก ๆ แล้วจะสะกดตามเสียงที่ออก แต่อิงกับเสียงวรรณยุกต์อีสาน แล้วเราจะรู้จักวรรณยุกต์อีสานได้ยังไง ทีม Linguist เลยเอากล่องวรรณยุกต์ (Tone Box) ของภาษากลางกับภาษาอีสานมาเทียบ 3. **วิธีการเก็บข้อมูล** ใช้หลายวิธี เช่น ให้ตอบคำถาม หรือให้คนอีสานเติมบทสนทนา หรือ ให้ดูภาพแล้วบรรยายภาพที่เห็น จากการเก็บข้อมูลเลยได้ Isan Corpus มี File เสียงที่คู่กับ File Transcription รวมทั้งมี Test Data และมี Metadata รวมถึงมีปฏิภาคของการภาษาไทยกลาง - อีสาน 4. **สร้างกระบวนการการกำกับข้อมูล** มีการกำหนด Annotation Guidelines และให้ Internal Team ช่วยกันพัฒนาและนำไปให้ External Team ช่วย Labeling เพื่อช่วยกำกับข้อมูล รวมถึงมี Annotation Platform ที่ช่วยให้การ Filtering ว่าเป็นภาษาอีสาน Dialect ไหน เสียง Clean ไหมและการทำ Audio Transcription ง่ายขึ้น ในอนาคตอยากให้คนที่พูดภาษาอีสานมาช่วยกัน Contribute ที่ Annotation Platform นี้เพื่อช่วยกัน Train Model สามารถอ่านเพิ่มเติมได้ที่ https://github.com/scb-10x/typhoon-isan ### แนวทางการพัฒนาและบทเรียนจาก Typhoon TTS 1. ศึกษา TTS ในตลาดหลายตัว สุดท้ายทีมเลือก Orpheus เพราะเป็น Open-source และ LLM กำลังมาแรง 2. ปรับให้เหมาะสมกับ Usage เช่น ต้องประสิทธิภาพดี ต้นทุนต่ำ 3. ต้องใช้ข้อมูลเสียงแบบคุณภาพดี 2 ชั่วโมงให้ TTS ใช้งานได้จริง 4. ต้องค่อย ๆ ปรับให้ออกเสียงให้ถูกต้องเป็นธรรมชาติและเหมือนคนอีสานจริง ๆ ซึ่งตัว Model TTS สามารถเอาไปต่อยอดเป็น Voice Agent ได้ ทีม Typhoon ได้ลองทำ Voice Agent และแสดง E2E Architecture ของเจ้า Agent ตัวนี้ให้ดู นอกจากการใช้งาน Model ตัว LLM, ARS, และ TTS ยังมีการทำ Turn Detection เพื่อ Detect ว่าคนพูดจบหรือยัง และก็ยังมี Interuption Detection เพื่อให้เราสามารถพูดแทรก Model ได้ทำให้เป็นธรรมชาติมากขึ้น นอกจากนี้การทำ Agent ระบบใหญ่ ๆ ก็จะต้องมีการทำ Context Management ที่ดีด้วย ## แนวทางการพัฒนาและบทเรียนจาก Voice Agent 1. ผู้ใช้งานต้องการการตอบกลับจาก Agent ในเวลา 236 milliseconds ซึ่งเป็น Standard ที่สูงมาก 2. การใช้งาน ARS, LLM, และ TTS ไปด้วยกันมักเกิดคอขวดที่ LLM ซึ่งถ้าเรา Optimize LLM ได้ จะช่วย Performance ได้ดีมาก 3. เริ่มสร้างบน [LiveKit](https://livekit.io/) ซึ่งเป็น Platform สำหรับการทำ Voice Agent ที่มีระบบกรอง Noise ที่ดี รวมถึงมี Edge Network ที่ Latency ต่ำมาก Typhoon เชื่อว่า AI ไทยจะได้มีที่ยืนในเวที AI โลก และ Thai AI Community จะเติบโตไปพร้อม ๆ กัน --- ## Panel Discussion: Inspiration & Collaboration: AI บ้านเฮา กับอนาคตของอีสานดิจิทัล Panel นี้เขามาเสวนากันชิว ๆ กันครับ หลัก ๆ นิลไม่ได้จดมาครับ แต่มี Usecase ที่ Panelists เขาคุยกันประมาณนี้ครับ - ใช้ Train คนที่ต้องไปอีสาน เพื่อสื่อสารให้ได้ - ใช้เพื่อสื่อสารแบบ Real-time กับลูกค้าเพื่อทำให้ลูกค้าเปิดใจเพราะใช้ภาษาเดียวกัน - หมอใช้ ARS เพื่อให้สามารถสื่อสารภาษาอีสานกับคนไข้ได้ - ใช้ทวงหนี้สื่อสารด้วยภาษาอีสาน ## จด ๆ จาก Q&A - ตอนนี้ยังไม่มีการประเมินว่า Model เข้าใจภาษาอีสานแค่ไหน - ตอนนี้ยังไม่มี Evals ภาษาอีสาน - ตอนนี้เป็นจุดตั้งต้น ยังอิงจาก Region ที่ใช้ 6 วรรณยุกต์ แล้วเดี๋ยวค่อยขยายผลไปยังพื้นที่อื่น ๆ - มองว่า Typhoon เป็น Hard Power, Soft Power ของประเทศไทย - มี Benchmark ที่เทียบใน Model Garden - มีความพยายามจะหาวิธีการสะกดคำภาษาอีสาน ทำให้ต้อง Re-invent the wheel ในการสะกดคำภาษาอีสาน --- # สรุป Session - Monetizing AI Innovations - URL: https://blog.ninprd.com/blog/summarize-fof-bkk-duolingo-monetizing-ai-innovations/ - Published: 2025-05-31 - Tags: summary, ux, ai - Summary: สวัสดีครับเมื่อ 3 วีคก่อนนิลได้ฟัง Live ของงาน Friends of Figma Bangkok มาครับ ละก็เพิ่งมีเวลามาเรียบเรียงเนื้อหาดี ๆ ซึ่งชื่อ Session คือ Monetizing AI Innovations โดย Speak คือคุณ Leah Lee, Product Designer จาก Duolingo ซึ่ง Leah จะมาเล่าการเดินทางของ Duolingo Max ซึ่งเป็น Feature ที่มีการเอา AI มาใช้งานด้วย จะเป็นยังไงไปดูกันครับ สวัสดีครับเมื่อ 3 วีคก่อนนิลได้ฟัง Live ของงาน Friends of Figma Bangkok มาครับ ละก็เพิ่งมีเวลามาเรียบเรียงเนื้อหาดี ๆ ซึ่งชื่อ Session คือ Monetizing AI Innovations โดย Speak คือคุณ Leah Lee, Product Designer จาก Duolingo ซึ่ง Leah จะมาเล่าการเดินทางของ Duolingo Max ซึ่งเป็น Feature ที่มีการเอา AI มาใช้งานด้วย จะเป็นยังไงไปดูกันครับ ## ประวัติของ Duolingo Max: AI Feature ของ Duolingo ในอดีตทาง Duolingo ขาด Feature การฝึกพูดที่มีประสิทธิภาพ รวมทั้งการฝึกพูดยังเป็น Feature ที่ผู้เรียน Request เข้ามาเยอะมาก ในปี 2018 พวกเขาเลยสร้าง Feature ชื่อว่า "Duolingo Live" ซึ่งเป็น Feature ที่ทำให้ผู้เรียนได้คุยกับ Tutor จริง ๆ หลังจากนั้นทีมก็เลือกจะ Discontinue เพราะว่าไปเจอ Insights ว่าคนที่เพิ่งเริ่มเรียนภาษาจะมีความกังวลที่จะคุยกับคนจริง ๆ รวมทั้งการที่ต้องใช้ Tutor เท่ากับจำนวนผู้เรียนก็ทำให้ธุรกิจนั้น ยากที่จะ Scale (ถ้ามีคนเรียน 20 ล้านคน = ต้องมี Tutor 20 ล้านคนด้วย) ในปี 2022 Duolingo ได้ Early Access จาก GPT-4 และเริ่ม Ideate จนในปี 2023 เริ่มมีการ Role out Duolingo Max ซึ่งมี Feature Explain My Answer กับ Role Play ออกมาให้ใช้งาน ทำให้คนเรียนได้เจอบทสนทนาและได้ฝึกการพูดกับบทสนทนาจริง ๆ (แต่ยังไม่มีการตอบกลับมาจากตัวแอป) ในช่วง Q2 ของ 2024 Duolingo เริ่มได้ Feedback มาว่า User ยังไม่สามารถตอบโจทย์การฝึกพูดคุยภาษาได้อย่างเต็มที่ ทีม Learning R&D เลยพัฒนา Feature Video Call ซึ่งถือเป็น Core Experience ของ Duolingo และในช่วง Q2 ของ 2025 Video Call กลายเป็น Hero Feature ของ Duolingo Max เพราะมันแก้ปัญหาเรื่องการฝึกพูดที่มี User Request มาเยอะมากและสร้างรายได้ให้กับบริษัทอย่างมาก ## Design Principles for promoting AI feature 1. **AI itself isn't the value prop, the outcome is**: อย่าเน้นว่าฟีเจอร์นี้ "ใช้ AI" แต่เน้นว่าผู้ใช้จะได้อะไรจากมันจริง ๆ 2. **Design with Cost in Mind**: เพราะเบื้องหลังของ Duolingo Max มีการใช้ OpenAI ทำให้ต้องมาออกแบบว่าจะให้ผู้เรียนลองที่จะใช้ฟรีกี่ครั้งเพื่อให้คนเรียนได้รู้ว่าถ้าจ่ายเงินแล้วจะได้รับประสบการณ์แบบไหน 3. **Use relatable metaphors users instantly recognize**: ออกแบบให้ผู้ใช้เข้าใจง่าย โดยเปรียบเทียบกับสิ่งที่ผู้ใช้คุ้นเคยแล้ว เช่น ออกแบบ Feature Video Call ให้เหมือนกับการทำ Video Call ทั่วไป 4. **Brand it as a premium experience**: เน้นคุณภาพของ Artwork, สี, และ Special Effects ให้ดูดี มีความน่าดึงดูด เพื่อสร้างความรู้สึกว่าเป็นฟีเจอร์ระดับพรีเมียม 5. **Make it delightful and fun, not intimidating**: นำเสนอ Feature ในรูปแบบที่น่าสนใจ เช่นตัว Video Call ก็มีการวางอยู่ในด่านเป็นกล่องของขวัญพร้อม Animation น่ารัก ๆ ให้ลองใช้ฟรี 6. **Integrate the feature into core UX**: วาง Video Call ไว้ใน Tab ของฟีเจอร์ปกติ เพื่อให้ผู้ใช้เห็นชัดเจนว่าเมื่อจ่ายเงินแล้วจะได้อะไร ## Case Study ในส่วน Case Study คุณ Leah จะมาเล่า Journey ของการ Promote Duolingo Max แบบ In Detail มากขึ้นครับ โดย Leah เริ่มเล่าว่า Goal ของเขาคือการทำ Promo ของ Video Call Feature เพื่อให้คนมาสมัคร Duolingo Max เยอะขึ้น โดยต้องแสดง Value ให้กับ Feature โดยไม่ใช้ Cost ด้าน AI เลย จากโจทย์ Leah และทีมก็ได้ Brainstorm กันผ่าน FigJam และได้ Initial Design มาซึ่งได้รับ Feedback ว่ามัน Generic เกินไปและไม่ได้แสดง Value ของ Feature Video Call ขนาดนั้น จากนั้น Leah เลยไป Research ต่อเกี่ยวกับหน้าจอเวลาที่มีคนโทรเข้ามาเพราะว่า User จะสนใจจอเมื่อเวลามีคนโทรเข้ามา นอกจากนี้ Leah ก็ยังไป Research มาต่ออีกว่าเราสามารถทำให้โฆษณาใน App สามารถคลิ๊กเล่นได้จริง (จากพวกโฆษณาเกมในมือถือ) ทำให้ Leah ออกแบบ Version ใหม่มาเป็นเหมือน Lily กำลังโทรเข้ามา ![](assets/fof-duolingo-video-call-promo-iteration-2.webp)

Iteration ถัดมาของ Video Call Promo

ใน Version นี้ Leah ได้รับ Feedback มาว่าทำ Feature Tie In ได้ดีขึ้น แต่ User สามารถ Skip ได้ง่าย ทำให้สุดท้าย Leah ออกแบบมาเป็นหน้าจอแบบ Slide to answer และเมื่อ Slide ไปก็จะเป็นหน้า Lily มาทักทายด้วยภาษาที่ผู้เรียนคนนั้น ๆ กำลังเรียนอยู่พร้อมบอกว่าจะได้อะไรบ้างเมื่อสมัคร Duolingo Max ![](assets/fof-duolingo-video-call-promo-final-design.webp)

Prototyping ของ Final Design ของ Video Call Promo

ซึ่ง Iteration สุดท้ายก็ผ่าน Product Review กับ CEO และเป็น Version ที่ปล่อยใช้งานใน App และ Promo อันนี้ก็ช่วย Drive ยอด Subscription ให้กับ Duolingo เป็นอย่างมาก Leah ฝากเกี่ยวกับการใช้งาน AI ใน Product ไว้ว่า > AI doesn't sell itself, it shines when presented the right way --- # Basic n8n ฉบับ DevDev - URL: https://blog.ninprd.com/blog/basic-n8n-for-developers/ - Published: 2025-05-01 - Tags: dev, n8n, ai, automation, Y2025 - Summary: วันนี้นิลจะพาชาว Dev มาทำความรู้จักกับเครื่องมือที่มีชื่อว่า n8n เพิ่มขึ้นครับ n8n มีไว้ทำอะไร ทำอะไรได้บ้าง มี use case อะไรที่อาจจะช่วยชีวิตชาว Dev ได้บ้าง มาดูกันครับ สวัสดีครับ นิลหายไป 2 เดือนแหนะะ ช่วงก่อนหน้าน้ีติดงานแบบวุ่น ๆ กับไปนั่งทำ Project เล่น ๆ ของตัวเองมาอันนึง ช่วงนี้นิลเห็น Content เกี่ยวกับ n8n เยอะมากแล้วก็นิลก็ได้มีโอกาสไปช่วย Facilitate Workshop [AI Automation for Business Transformation รุ่นที่ 1](https://www.skooldio.com/workshops/ai-automation-for-business-transformation) มาครับ ทำให้นิลได้ลองเล่น n8n มาในหลาย ๆ use case เลยครับ ทำให้นิลอยากมาแชร์เป็น Basic ของ n8n สำหรับชาว Dev ได้เข้าใจและเข้ามาลองเล่น Tool ตัวนี้ได้ง่ายขึ้นแหละครับ ## n8n คืออะไร n8n เป็น Tool ที่เข้ามาช่วยในการทำ Automation ครับโดยจะเริ่มต้นจากการวางสิ่งที่เรียกว่า Trigger เพื่อเป็นตัวเริ่มทำงาน และจะใช้การลากกล่อง (Node) ที่มี Function ต่าง ๆ แล้วเชื่อมต่อกันด้วยเส้น (Edge) ให้เกิด Workflow ขึ้นมาครับ ซึ่งเมื่อ Run Workflow ก็จะเหมือนการวิ่งเริ่มจาก Trigger ไปตาม Node ผ่าน Edge ต่าง ๆ ครับ ซึ่งเจ้า Node นี้ก็จะมี Function ที่สำเร็จรูปแล้วครับ ไม่ต้องเขียนเอง เช่น ต่อ Google Sheets, ส่ง HTTP Request,ส่ง Email ด้วย Gmail, Database, AI Agent, etc. รวมทั้งสามารถบันทึกพวก Credentials ที่เอาไว้ต่อกับบริการต่าง ๆ ไว้ได้ด้วยครับ ซึ่งจริง ๆ แล้ว 1 Node ก็เหมือน 1 Function ครับ และ 1 Workflow ก็เหมือนการประกาศ Function ที่เอา Function อื่น ๆ มาต่อกันไปเรื่อย ๆ แหละครับ เดี๋ยวนิลลองเทียบ Side by Side ด้วย Code ดูครับ ![](assets/n8n-to-code-example.webp) และยังไม่หมดครับ เรายังสามารถสร้างเจ้า Workflow เป็น Sub Workflow เพื่อเอาไปใช้ใน Workflow ต่าง ๆ อีกด้วยครับ ซึ่งภาพก็เหมือนเราทำ Function เล็ก ๆ แล้วก็เอาไป Compose ให้เป็น Function ใหญ่ ๆ ครับ ## ความเก่งเจ๋งของ n8n ด้วยความที่ Node ต่าง ๆ ที่มี Function ที่เขียนให้แบบเสร็จสรรพแล้ว ทำให้เราไม่ต้องมาเขียนเองครับ นอกจากนี้ยังมี UI ให้ลากวางเพื่อให้เกิด Workflow ขึ้นมาได้เลยครับ ทำให้ n8n มีความสะดวกสบายและรวดเร็วในการสร้าง Automation ครับ นอกจากนี้สำหรับชาว JavaScript แล้ว n8n ยังมี Node ที่เป็น Code ให้เราสามารถเขียน Function ภาษา JavaScript เข้าไปได้ด้วยครับ อีกสิ่งที่ไม่พูดไม่ได้เลยคือเจ้า Node AI Agent ที่พูดถึงไปก่อนหน้านี้ครับ Node ตัวนี้จะสามารถต่อกับ AI Model เจ้าต่าง ๆ ไม่ว่าจะเป็น Google, OpenAI, Anthropic รวมถึงสามารถต่อกับ Ollama ได้ด้วย รวมทั้งสามารถต่อ Memory หรือเชื่อมต่อกับ Tool ต่าง ๆ เพื่อให้ AI Agent สามารถทำงานต่าง ๆ เช่น ส่ง Email, แก้ไข Google Sheets ได้อีกด้วยครับ และตัว n8n ยังสามารถ Expose ตัวเอง ออกไปเป็น URL เพื่อรับ Webhook ได้อีกด้วยครับ ถือว่ามีอรรถประโยชน์มาก ๆ ## ลองสร้าง Workflow ใน n8n กัน เดี๋ยวจะพาทุกคนไปสร้าง Basic Workflow กันฮะ แต่ก่อนจะพาไปเริ่มกัน ขอ Make Sure ว่าทุกคนมี node.js ติดตั้งในเครื่องครับ แล้ว run command ```sh npx n8n ``` จากนั้นให้เราไปที่ http://localhost:5678 แล้วเราจะเจอกับหน้าตา Interface ของ n8n ครับ เสร็จแล้วให้ทำขั้นตอนดังนี้ครับ 1. กด Create Workflow ที่มุมบนขวา 2. เมื่อเข้าหน้า Workflow มาให้กด "Add First Step" 3. ให้หาคำว่า "Trigger Manually" จากนั้นกดเพื่อเลือก Trigger นี้เข้า Workflow ครับ 4. กดปุ่ม "+" ที่อยู่ทางขวาของตัว Trigger ของเราครับ จากนั้นหาคำว่า "Customer Datastore (n8n training)" ครับ กดที่ชื่อเพื่อเอา Node นี้เข้า Workflow ของเราครับ 5. พอเพิ่มแล้วจะมีหน้าต่างเด้งขึ้นมา ให้กด Esc หรือกดข้างนอกหน้าต่างนั้นเพื่อปิดไปก่อนครับ 6. ให้ลองกด Test Workflow ดูครับ เราจะเห็น Interface มันมีการขยับเพื่อบอกว่าตอนนี้มัน Run ถึงตรงไหนแล้ว เท่านี้เราก็สร้าง Workflow ของตัวเองเป็นที่เรียบร้อยแล้วครับ ซึ่งปลายทางทุกคนจะได้ Workflow หน้าตาตามรูปนี้เลย ![](assets/basic-n8n-workflow.webp) ทีนี้ถ้าลองกดที่ Node Customer Datastore เราก็จะเจอกับหน้าตาแบบนี้ครับ ![](assets/example-workflow-run-n8n.webp) ซึ่งเจ้านี้คือผลลัพธ์ของการ Run Node ตัวนั้น ๆ ครับ Input จะเป็นข้อมูลที่อยู่ฝั่งซ้าย Output จะเป็นข้อมูลที่อยู่ฝั่งขวาครับ เราสามารถกดที่แต่ละ Node เพื่อดูแบบนี้ได้เลยครับ ## มาดู Basic use case ของ n8n แบบ DevDev กันดีกว่า ### ส่งข้อมูล Pull Requests ใน GitHub เข้า Slack รายวัน เราอาจจะตั้ง Schedule ไว้ เช่น ทุก 9 โมงให้ไปดึงข้อมูล Pull Requests ทั้งหมด (หรืออาจจะดึง Issues ด้วย) มา แล้วเอาไป Post ลงไปใน Slack ในทีม Dev เพื่อให้ทุกคนสามารถเห็น Summarize ข้อมูลก่อนที่จะเริ่มงานวันนั้น ๆ ได้ ![](assets/basic-n8n-use-case-github-to-slack.webp) ## ทำ Bot Daily Standup เราสามารถตั้งเวลาไว้แล้วตั้งให้ส่งข้อความลงใน Discord เพื่อเตือน Standup รายวันได้ครับ นอกจากนี้ถ้าบริษัทเรามีการใช้ Google Calendar เราก็สามารถปักวันหยุดบริษัทได้ แล้วตั้งให้มันไม่ส่งข้อความหากวันนั้นเป็นวันหยุดได้ด้วย ![](assets/basic-n8n-use-case-standup-board-to-discord.webp) นอกจากนี้ยังสามารถทำอีก Workflow นึงให้เป็น Webhook ที่ส่งข้อความเข้ามาเรื่อย ๆ แล้วถ้ามีคนพิมพ์คำว่า End ใน Thread เราก็สามารถที่จะกวาดข้อความทั้งหมดใน Thread นั้น มาให้ AI Agent ทำเป็น Summarize ว่าวันนี้แต่ละคนจะทำอะไร เพื่อให้ทีมเห็นภาพรวมกันง่ายมากขึ้นด้วยครับ ![](assets/basic-n8n-use-case-summarize-from-discord-thread.webp) ## แล้วนิลใช้ n8n ทำอะไร ถ้าสารภาพบาปเลยตอนนี้คือ เอาตรง ๆ นิลยังไม่ได้เอา n8n ไปใช้เพื่อ Personal Task ครับ เพราะว่าเราต้องเอา n8n ไป Self-Hosted หรือถ้าใช้ n8n cloud ของฟรีก็มีการจำกัดจำนวน Workflow ด้วย นิลมองว่าถ้าไม่จำเป็นจริง ๆ นิลก็อาจจะไม่ใช้กับงานอะไรที่นิลต้องทำคนเดียวครับ สู้ไปเขียน Code อาจจะง่ายกว่าครับ แต่ ๆๆๆ ถ้าเป็นงานที่ต้องทำงานร่วมกับคนอื่น ๆ ที่ไม่ได้เป็นสาย Tech จ๋า ๆ หรือไม่ต้องการเขียน Code นิลก็แนะนำให้ใช้ n8n ครับ เพื่อให้สามารถทำงานร่วมกันได้อย่างเห็นภาพและสะดวกขึ้นครับ --- จบไปละกับ Basic n8n for devs ครับ ตอนแรกนิลอยากเอาอันนี้ไปวางไว้ที่ https://learn.ninprd.com/ แหละ แต่รู้สึกว่ามันเป็นเนื้อหาคร่าวมาก ๆ ผนวกกับตอนนี้นิลยังไม่ได้ลองเล่น n8n แบบเยอะมาก ๆ หรือเจอ use case ที่นิลต้องใช้ n8n มาก ๆ ด้วยครับ ถ้าได้ลองเล่นเยอะ ๆ นิลอาจจะไปนั่งทำเป็นเนื้อหาวางไว้ในเว็บ learn ของนิลก็ได้ครับ ถ้าใครอยากลองศึกษา n8n เพิ่มเติม ทาง n8n เขามี Tutorial นะครับ ลองไปศึกษากัน[ดูได้ที่นี่เลย](https://docs.n8n.io/try-it-out/tutorial-first-workflow/) หรือสามารถติดตาม Tutorial จากหลาย ๆ เพจได้เลย ไม่ว่าจะเป็น [เทพเอ็กเซล](https://www.facebook.com/thepexcel) [QWERTY is a DUCK](https://www.facebook.com/duckgitalist) หรือ [Prompt Alchemist](https://www.facebook.com/PromptAlchemist) ก็มี Tutorial อยู่ประปรายครับ ใครมี Workflow เจ๋ง ๆ มาแชร์กันใน Comment ที่ Page ตากล้องที่เขียนโค้ดได้นิดหน่อยได้เลยนะครับ นิลรออ่านอยู่ ขอบคุณทุกคนที่อ่านมาถึงตรงนี้นะครับ เดี๋ยวจะพยายามกลับมาเขียน Monthly Blog ให้ได้เลยย มี Topic อยากแชร์เพียบเลยครับ ขอให้สนุกกับการทำ Automation ด้วย n8n ครับ นิล --- # ปฎิบัติการหนี WordPress ของนิล - URL: https://blog.ninprd.com/blog/nin-mission-to-bye-bye-wordpress/ - Published: 2025-02-24 - Tags: experience-sharing, software-engineer, WordPress, Y2025, blog - Summary: สวัสดีครับ หลังจากผ่านการใช้งาน WordPress ของฟรีมาเกือบ ๆ จะ 1 ปี ตอนนี้มันใกล้ช่วงที่นิลจะต้องจ่ายตังละ ผนวกกับช่วงก่อนหน้านี้ก็มีดราม่ากันเล็กน้อย นิลเลยเกิดไอเดียปฏิบัติการหนี WordPress ขึ้นมาครับ ซึ่งปฏิบัติการนี้จะเป็นยังไงไปดูกันครับ สวัสดีครับ หลังจากผ่านการใช้งาน WordPress ของฟรีมาเกือบ ๆ จะ 1 ปี ตอนนี้มันใกล้ช่วงที่นิลจะต้องจ่ายตังละ ผนวกกับช่วงก่อนหน้านี้ก็มีดราม่ากันเล็กน้อย นิลเลยเกิดไอเดีย**ปฏิบัติการหนี WordPress** ขึ้นมาครับ ซึ่งปฏิบัติการนี้จะเป็นยังไงไปดูกันครับ > ⚠️ คำเตือน: ใน Blog นี้อาจจะมี Technical ผสมอยู่เรื่อย ๆ นะครับ เดี๋ยวนิลจะเขียนบอกไว้นะเผื่อคนที่ไม่ได้สนใจ Technical มากจะได้ข้ามได้ครับ เอาล่ะ งั้นมาเริ่มกันเล้ย ## จะย้ายออกอีกละหรอ? ถึงจะเป็นการย้ายออกจาก Platform รอบที่ 4 ของนิลแล้ว (Medium, Notion, WordPress.com, WordPress.org) แต่ถ้าถามแบบนี้ก็ต้องตอบว่าใช่ครับ 55555555 เหตุผลที่นิลจะย้าย CMS ในครั้งนี้ หลัก ๆ เลยคือต้นทุนครับ ถ้านิล Host WordPress.org ต่อไป นิลก็จะมีต้นทุนในการเช่า Server ของเขาอยู่ครับ ซึ่งเป็นต้นทุนที่นิลเริ่มรู้สึกว่ามันไม่คุ้มถ้านิลจะลงทุนเองในตอนนี้ครับ จริง ๆ อีกเหตุผลคือนิลอยากถือ Content ไว้กับตัวเองครับ เวลาเราเอา Content ไปฝากไว้กับ WordPress เนี่ย เราเอารูป เอา Content ของเราไปฝากไว้กับ Server ของเขา ซึ่งวันใดวันนึง ถ้า Service ซักอันนึงล่มขึ้นมา ข้อมูลนิลอาจจะหายไปตลอดกาลเลยก็ได้แหละครับ เหตุผลสุดท้ายเลยก็คือปีนี้นิลยังอยากลองเล่น Tools ใหม่ ๆ ลองหา CMS ใหม่ ๆ ดูอยู่ครับ ซึ่งการที่นิลต้องดึงข้อมูลจาก Platform ต่าง ๆ มาเพื่อแสดงผลเนี่ย ทำให้นิลต้องหาท่า Hack เยอะมากเพื่อให้มันทำงานได้ครับ ซึ่งก็บอกเลยว่าเสียเวลาเป็นอย่างมาก ทั้งหมดนี้เลยเป็นเหตุผลที่ทำให้นิลเริ่มหาทางเลือกออกจาก WordPress ครับ อย่างที่ชื่อ Blog บอกเลยครับว่านี่คือ **ปฏิบัติการหนี WordPress** (เว่อชิบหาย 555555555) ## เริ่มขั้นตอนการค้นหาทางเลือกใหม่ พอพูดถึงปฏิบัติการแล้ว สิ่งที่ต้องทำอย่างแรกคือวางแผนครับ นิลลองหา **WordPress Alternatives** ก่อนเลย เพื่อลองดูว่ามี CMS เจ้าไหนบ้างที่ตอบโจทย์การเขียน Blog ใส่รูปง่าย ใส่ Content ดี และต้องสามารถนำมาเชื่อมกับเว็บ Blog เดิมของนิลที่เขียนด้วย Astro ได้ด้วย ตอนแรกที่นิลหามา มี CMS หลายตัวมาก ไม่ว่าจะเป็น Strapi, Directus, Ghost, Contentful, PayloadCMS แต่สุดท้ายพอเทียบกับสเปคด้านบนแล้ว นิลก็เหลือตัวเลือกเดียวคือ Ghost เลยครับ นิลเลยลองไปเล่นเจ้า Ghost เพื่อมาเปรียบเทียบ Experience กับ WordPress ดูครับ > ℹ️ จริง ๆ นิลลองเล่น Strapi, Directus, Contentful มาละครับ ถ้าใครอยากรู้ข้อดีข้อเสีย เดี๋ยวนิลมาเขียนไว้ครับ ผลที่ออกมาคือ Ghost ก็พอฟัดพอเหวี่ยงนะครับ ในด้าน Editor Ghost ทำได้ดีมากเลย แถมมี Theme ให้เลือกใช้ได้ประมาณนึงด้วย แปลว่านิลแทบจะสามารถโยนเว็บที่นิลเขียนด้วย Astro มาทิ้งได้เลยนะ 5555555 ปรากฎว่านิลลืมดูครับ Ghost มันต้องจ่ายตังรายปี โอ้แม่เจ้า ก็ว่าทำไมมันดูดีจังวะ 55555555 คือกด Free-Trial ไปแล้วด้วยนะ บ่งบอกถึงความไร้สติตอนกด Free-Trial สุด นิลแม่งไม่ได้อ่านอะไรเลยนี่นา 5555 ## หมดความหวังนั่งน้ำตาริน หลังจากเห็นราคา Ghost แล้ว นิลก็นั่งคอตกแบบมนุษย์เงินเดือนที่เดือนชนเดือนเลยครับ แบบซึมไปเลยแหละ จนกระทั่งนิลนึกถึงบทสนทนาที่คุยกับชุน (เจ้าของเพจ [LearnAlgorithm.com](https://www.facebook.com/learnalgorithm)) ว่าชุนก็ทำเว็บเหมือนกัน แต่หลังบ้านของชุนจริง ๆ แล้วคือการเขียน File Markdown ผ่าน App ที่มีชื่อว่า [Obsidian](https://obsidian.md/) ครับ ต้องเท้าความก่อนว่า Obsidian จริง ๆ แล้วเป็น Note Taking App ครับ โดยเวลาเขียนเราจะเขียนใน Format ที่เรียกว่า Markdown แหละ จุดเด่นของเจ้านี่คือความ Flexible ในการใช้งานครับ เราสามารถมาแบบ No-Brain แล้วใช้มันเป็นเหมือน Notes ของ Apple หรือเราจะทำตัวเป็น Hackerman แล้ว Custom มันเยอะ ๆ ก็ได้ และที่น่าจะสำคัญที่สุดสำหรับนิลครับ คือเวลาเขียนมันสร้าง File Markdown จริง ๆ ไว้ในเครื่องเราครับ หลาย ๆ คนอาจจะสงสัยว่า แล้วการได้ไอเจ้า Markdown มาไว้ในเครื่องสำคัญยังไง จำได้ไหมครับว่าตอนแรกนิลบอกว่านิลอยากเก็บ Content ไว้กับตัวเองครับ ซึ่งการที่เราสามารถสร้าง File Markdown และเก็บไว้ก็คือเราสามารถนำ Content ไปแปรรูปได้ง่ายมากครับ โดยที่ไม่ต้องพึ่งพาความสามารถของ Platform ใด ๆ เลย การลองเล่น Obsidian ช่วงแรก ๆ ก็ต้องบอกเลยว่าอิหยังวะสุด ๆ ตอนแรกนิลพยายามทำความเข้าใจทุก Feature ของมัน พยายามลองหา Tutorial ให้ใช้เป็นทุกอย่างเลยดูเยอะมาก ๆ แบบโคตร Overwhelm เลยครับ ตอนแรกก็แอบมีความคิดจะถอดใจละ แต่พอนิลเกิดความคิดที่ว่าลองใช้แล้วค่อย ๆ เรียนรู้ไป นิลก็ลองใช้ไป อยากรู้ตรงไหนค่อยไปหาเพิ่ม ซึ่งตอนนี้มันก็ทำให้นิลเริ่มกลับมาตาเป็นประกายอีกครั้งเลยแหละครับ 🤩 ประสบการณ์การเขียนโดยรวมคือค่อนข้างดีเลยครับ จนตอนนี้นิลก็ Setup มันมาค่อนข้างเยอะแล้วแหละ 55555 บอกเลยว่า "ของดีย์" ## สรุป Stack ตอนนี้ใช้อะไรบ้าง > ⚠️ เข้าสู่ช่วง Technical ใครไม่สนใจข้ามไปที่ [บทส่งท้าย](#บทส่งท้าย) ได้เล้ย ตอนนี้ Stack ของ blog.ninprd.com คือหน้าเว็บใช้ [Astro](https://astro.build/) เป็น Web Framework ที่เก่งเจ๋งเรื่องของการทำ Content รวมทั้งยังเขียนด้วย Syntax ที่คล้ายกับ HTML สุด ๆ รวมถึงมี Official/Community Integrations เยอะโคตร ทำให้จะทำอะไรก็ง่ายไปหมดเลย และก็นิล Build เป็น Static Web ครับ จะได้ไม่ผูกติดกับ Platform ใด Platform หนึ่งมากเกิน ตัว Content ตอนนี้นิลเขียนเป็น File Markdown (.md) ธรรมดาเลยครับ ซึ่งนิลเลือกเขียนผ่าน Obsidian ครับ นอกจากเรื่องของประสบการณ์การเขียนที่กล่าวไปข้างต้นแล้ว อีกอย่างที่ทำให้นิลชอบมากคือ Graph View ของ Obisidian ครับ สิ่งที่ Graph View ให้คือความเชื่อมโยงกันของ Blog นิลครับ ทำให้นิลเห็น Pattern และหมดหมู่ของที่ตัวเองเขียนไปว่า เอ้ะ ปีนี้เขียนไปกี่บทความ เป็นบทความเรื่องอะไรบ้าง เชื่อมอะไรกันอยู่บ้างครับ ![obsidian-graph-view](assets/obsidian-graph-view.png)

Graph View ของ Blog ของนิลเอง

วิธีการที่เราจะใช้ Obsidian กับ Astro ได้คือให้เราสร้าง Vault ของ Obsidian ใน Folder ของ Project Astro เลยครับ จากนั้นให้เราสร้าง Content Collection ของ Blog ใน Astro เลย โดยการตั้งค่าเป็นไปตามนี้ครับ ```ts title="content.config.ts" const blog = defineCollection({ loader: glob({ pattern: ['**/*.{md,mdx}', '!templates/**', '!src/blog/.obsidian/**'], base: '', }), ``` ซึ่งหลายคนก็อาจจะสงสัยว่าแล้วไฟล์ภาพจะไปเก็บที่ไหน ซึ่งส่วนตัวแล้วนิลก็เก็บไว้ใน Vault นี้แหละครับ นิลก็จะไปตั้งค่าที่ Obsidian ครับ กดปุ่ม `Cmd + ,` เพื่อเปิด Settings จากนั้นไปที่เมนู Files and links ครับ ให้เราหาการตั้งค่าที่ชื่อว่า "Default location for new attachments" แล้วเลือก "In the folder specified below" แล้วในช่องต่อมาก็กรอกว่าอยากให้รูปอยู่ตรงไหน ส่วนตัวนิลสร้างเป็น Folder ชื่อว่า assets ไว้ครับ ![Nin's Obsidian attachments settings](assets/obsidian-attachments-settings-by-nin.webp)

การตั้งค่า Attachments ใน Obsidian ของนิล

นอกจากนี้ ตัว Web ก็ยังอยู่ใน [Turborepo](https://turbo.build/) ครับ ซึ่งเป็น Monorepo Tools ตัวนึงที่เด่นเรื่องของความเร็วกับความง่ายในการ Setup ครับ ซึ่งสาเหตุที่ทำให้นิลเลือกใช้ Turbo ก็คือออ นิลทำเว็บใหม่แยกออกมาอีกเว็บครับโดยต้องการ Share Styling, UI Component กันครับ เว็บใหม่ที่นิลทำมาเพื่อเอาไว้แบ่ง Content อันไหนที่เป็น Technical Knowledge Sharing ที่เป็น Series ต่อกัน หรืออันที่นิลอยากเก็บเอาไว้ ก็จะเอาไปไว้ที่ตรงนู้น เช่น WordPress Basic Series ก็กำลังย้ายไปเว็บใหม่ครับ ส่วนตรงนี้ก็จะยังเป็น Content เล่าชีวิต สรุป Meetup, Conference สัพเพเหระเหมือนเดิมครับ ใครสนใจ รอติดตามที่[ลิงก์นี้](https://learn.ninprd.com)เลยครับ เดี๋ยวทำเสร็จแล้วจะลงเพจอีกทีครับ ## บทส่งท้าย ต้องบอกว่า Blog นี้เป็น Blog ที่ใช้เวลาค่อนข้างนานมากในการเขียนเพราะว่านิลนั่งย้าย Content ออกจาก WordPress นานมากกกก แล้วก็ยังใช้เวลากับการศึกษากับ Obsidian ค่อนข้างเยอะครับ เลยเป็นเหตุผลที่นิลไม่ได้เขียน Blog ของเดือนมกรา (อันนี้อ้างแหละ จริง ๆ แล้วคืองานเยอะเกิน 55555) อีกปัจจัยนึงที่ทำให้นิลเลือกมา Obsidian คือตอนนี้นิลกำลังจะเอาของจำพวก Learning ไปจดใน Obsidian แทน Notion ครับ เพราะ Obsidian มันแอบไวกว่าอะ 5555555 ละก็มันเห็น Graph View ด้วย ทำให้เราเห็นว่าแต่ละเรื่องที่เราเรียนมามันเกี่ยวข้องกับเรื่องอะไรบ้างครับ จบไปแล้วกับ Blog อันร่ายรำอารัมภบทมาอย่างเยอะสุดท้ายก็คือย้ายบ้านนั่นแหละ 55555555 ถือว่าภารกิจสำเร็จแล้วกันครับ ขอบคุณชุนมากที่แนะนำ Obsidian มาให้ลองใช้ ใครอยากอ่าน Tech Stack ตึง ๆ ของ [LearnAlgorithm.com](https://learnalgorithm.com/) สามารถไปอ่านได้[ที่นี่](https://www.facebook.com/share/p/1HMWmGmGEW/)เลยนะ นอกจากนี้นิลก็ขอขอบคุณทุกคนที่ยังอ่านมาถึงจุดนี้นะครับ ทุกคนเก่งมาก 555555 ขอบคุณทุกคนที่ติดตามนิลนะครับ ปีนี้เดี๋ยวมี Content สนุก ๆ มาอีกเยอะเลย รอได้เลยครับ 😎 ขอให้ทุกคนสนุกกับการเขียน -- นิล -- --- # 2024 Year In Review - URL: https://blog.ninprd.com/blog/2024-year-in-review/ - Published: 2024-12-28 - Tags: year-in-review, Y2024 - Summary: สวัสดีครับทุกคน มาดูสรุปปี 2024 ของนิลกันครับ ^^ สวัสดีครับทุกคน ปีนี้นิลรู้สึกว่ามีอะไรเกิดขึ้นกับนิลเยอะมากเลย ก่อนอื่นเลยน่าจะขอขอบคุณทุก ๆ คนที่ยังอ่าน Blog ของนิลอยู่ หรือเพิ่งมาเจอกันใน Blog อันนี้ก็ตามครับ และเหมือนเดิมนิลอยากที่จะสรุป Highlight/เรื่องสำคัญ ๆ ที่เกิดขึ้นกับนิลในปีนี้ครับ เป็นปีที่สมบุกสมบันของนิลมาก จะเป็นยังไง ไปดูกันเลยครับ ## เป็นโควิดครั้งแรก… ช่วงวันเกิด… เปิดเรื่องแรกมาก็ไม่ดีเลย 555555 ตอนช่วงกุมภาอยู่ดี ๆ นิลก็รู้สึกเจ็บคอขึ้นมา นิลก็แบบเอ้ะ ไข้หวัดหรือเปล่านะ เริ่มเป็นซัก 3 วันเริ่มรู้สึกแปลก ๆ ลองจิ้มจมูกดู เรียบร้อยเลย 5555555 2 ขีดเข้ม ๆ วันนั้นก็คอตกเลย เพราะช่วงก่อนหน้านั้นคือเจอคนเยอะมาก และช่วงนั้นนิลก็มีจะต้องไปสอนลูกค้าใช้ระบบอีกเลยต้องรีบถ่ายงานให้น้องในทีมเลย เป็นวันเกิดที่นอนซึม ๆ + ป่วยอยู่บ้าน ปีหน้าไม่เอาละนะ ## ไปต่างประเทศคนเดียวครั้งแรก หลังจากที่ปีที่แล้ว นิลติดอยู่กับ Project WordPress อันที่พูดถึงปีที่แล้วอย่างยาวนาน ซึ่งช่วงมกราอยู่ดี ๆ นิลก็คิดอุตริอยากจะไปต่างประเทศแหละ นิลเลยกดตั๋วไปไต้หวัน 6 วันในช่วงมีนาไปเลย แบบไม่ไหวแล้วโว้ย สิ่งที่ตอนนั้นคิดคือ เงินไม่ใช่ปัญหา ตอนนี้ขอแค่เอาตัวเองออกจากงานได้ก่อนคือโอเคละ (แต่ตอนนี้เงินเริ่มเป็นปัญหาละ 555555) ตอนนั้นก็สนุกดีฮะ ได้เดินทางด้วยตัวเอง ได้เปิดประสบการณ์นอน Hostel (แต่คราวหน้าไม่เอาละ 55555) ได้ไปลง Hot Spring ครั้งแรกด้วย 5555 ถือว่าเป็นประสบการณ์ที่ดีครับ ใครอยากอ่านเรื่องราวของนิลในไต้หวันสามารถอ่านได้[ที่ Blog อันนี้](alone-in-taipei-2024.md)ได้เลยครับ ## ไปงาน Conference ที่ต่างประเทศ จริง ๆ เหตุผลที่ทำให้นิลไปไต้หวันที่นิลเล่าไปในข้อก่อนหน้าคือการที่นิลวู่วามกดตั๋วไป Conference WordCamp Asia 2024 แหละ ซึ่งก็เป็นอีกจุดนึงที่เปิดประสบการณ์และเปิดโอกาสให้กับนิลในการไปงานต่าง ๆ ในปีนี้ด้วย ได้รู้จักชาว WordPress Bangkok กับพี่ไทและก็ชุนแห่ง LearnAlgorithm.com เพิ่มอีกด้วย ถือว่าเป็นการอัปเกรดตัวเองจาก Social Akward Boy เป็นชาว Social Akward ชุดแป้งทอดเลย 555555 อาจจะไม่ได้เขียนไว้ในนี้เยอะ แต่ก็สามารถอ่านแบบละเอียดได้[ที่ลิงก์นี้](wordcamp-asia-2024-with-nin.md)เลยครับ และ ๆๆๆๆ [WordCamp Asia 2025](https://asia.wordcamp.org/2025/) บัตรขายแล้วนะครับ ใครสนใจเข้าหน้าเว็บไปซื้อได้[ที่นี่](https://asia.wordcamp.org/2025/tickets/)เลย ## เป็น TA ของ Web Dev Bootcamp ของ Skooldio อันนี้เป็นสิ่งที่ตัวนิลอยากทำในช่วง Cooldown จาก Project WordPress เพื่อรื้อความรู้ React ของตัวเองอีกครั้งครับ เป็นช่วงเวลาที่ได้ช่วยเหลือคนเรียน ได้เห็นคนบางคนรู้สึกสำเร็จ เป็นความรู้สึกที่ใจฟูมาก ๆ เลยครับ และในขณะเดียวกันก็เป็นช่วงที่เหมือนได้ย้อนเวลาไปตอนที่ตัวเองเริ่มเขียนโค้้ดและสวมวิญญาณคนที่เราอยากได้คำแนะนำในช่วงแรก ๆ ของการเขียนโค้ดเลยแหละ รวมถึงได้เจออาจารย์ข้างนอกเก่ง ๆ ทั้งพี่ไมค์ พี่จุ้น พี่ไท ริฟฟี่ ถือเป็นช่วง 3 เดือนที่ดีมากครับ ใครสนใจเรียนรู้ Skill Web Development สามารถลงทะเบียนความสนใจรุ่นต่อไปได้[ที่ลิงก์นี้](https://landing.skooldio.com/web-development-bootcamp)เลยครับ ## เรียน UX/UI Bootcamp #7 อันนี้เป็น Cannon Event ที่นิลเลือกก้าวไปเองครับ คือส่วนตัวนิลก็สนใจเรื่องของ UX อยู่แล้ว และนิลก็เห็นว่าช่วงกลางปี Skooldio มีเปิด [UX/UI Bootcamp](https://landing.skooldio.com/ux-ui-bootcamp) พอดี นิลก็ด้วยความอยากเรียนก็ติดต่อพี่ Manager ไปเพื่อขอเรียนครับ เป็นช่วงเวลาที่นิลได้เข้าใจศาสตร์ของ UX/UI มากขึ้น ได้เรียนกับพี่ ๆ ตัวตึงในวงการและก็ได้พัฒนา Skill ของตัวเองแบบก้าวกระโดดด้วย ถือว่าเป็นการลงทุนเวลาที่คุ้มค่าที่สุดในชีวิตครั้งนึงเลยก็ว่าได้ครับ ปีหน้าน่าจะเปิดรับสมัครอีกรอบ ยังไงใครสนใจสามารถลองอ่าน[รีวิวของนิลได้ที่นี่][skooldio-ux-ui-bootcamp-7-review.md]เลยครับ ## ไป Conference กับ Meetup แบบฉ่ำ ๆ ปีนี้เป็นปีที่ออกนอก Safe Zone มาก ๆ เลย ในความรู้สึกนิล นิลเป็นแค่ Introvert หนึ่งคนที่ Social Akward มาก ๆ แต่ด้วยความอยากลองและก็อยากได้ความรู้ด้วยก็เลยต้องไปเยอะมาก ๆ เดี๋ยวลองไล่คร่าว ๆ ว่าไปไหนมามั่ง ### Conference - WordCamp Asia 2024 - UXTH Conference 2024 - GameChanger Conference - JavaScript Bangkok 2.0.1 - LINE DEV CONF 2024 - ODDS| CONF 2024 ### Meetup - WordPress Meetup: Growing WordPress in Thailand - WordPress Meetup: Let’s Share our WordPress Workflow - WordPress Meetup: WordPress Security - Supabase Meetup 1.0 - UXTH Meetup Biometrics - Google Cloud Dev Fest - SCBX Unleash: Figma Meetup Bangkok - SCBX Unleash: Designing for Maximum Impact and Scale ## พักการรับงานถ่ายรูป หลาย ๆ คนพอเห็นชื่อเพจครั้งแรกอาจจะแบบว่า “ตากล้องที่เขียนโค้ดได้” นี่ ส่วนไหนของนิลเป็นตากล้องนะ แต่ถ้าเป็นคนที่รู้จักนิลตั้งแต่ช่วงก่อนเปิดเพจจะรู้ว่านิลรับงานถ่ายรูปก่อนที่จะเขียนโค้ดซะอีก 555555 ซึ่งนิลก็รับถ่ายรูปมาได้หลายปีแล้วและช่วงที่ผ่านมาพอนั่งเขียนโค้ดด้วย ถ่ายรูปด้วย (ตีแบดด้วย) ข้อมือนิลอักเสบบ่อยมากครับ และนิลต้องเลือกที่จะหยุดกิจกรรมซักอย่างนึงเพื่อรักษาข้อมือนิลไว้ (ฟังดูยิ่งใหญ่ปะ 555555) นิลก็เลยเลือกหยุดที่จะรับงานถ่ายรูปครับ เพราะพอมา Review แล้ว Goal ของนิลไม่ได้อยากไปทางนั้นแล้วด้วย ## เติบโตเป็น Team Lead ในปีนี้นิลก็ได้รับโอกาสจากพี่เมเนท่านหนึ่งให้ลองขึ้นเป็น Team Lead ครั้งแรกครับ ถือว่าเป็น Challenge ที่ใหญ่ที่สุดเลยก็ว่าได้ครับ ซึ่งในฐานะที่นิลไม่เคยอยู่ในทีมแบบยาว ๆ มาก่อน นิลเองก็ไม่รู้ว่าทีมต้องการอะไรจากนิล และนิลก็ไม่รู้จะ Provide อะไรให้ทีมบ้าง ก็อาศัยครูพักลักจำละก็พยายามสื่อสารกับทีมมาเรื่อย ๆ ครับ ผ่านมา 4 เดือนแล้ว แต่นิลก็รู้สึกว่าตัวเองยังต้องพัฒนาเรื่อย ๆ อยู่ ช่วงนี้ก็ต้องซื้อหนังสือมาอ่านเพิ่มอยู่ครับ ปีหน้าก็น่าจะเป็นปีที่น่าสนุกของนิลเลยแหละ --- ผ่านพ้นไปอีกปีแล้วกับปีที่วุ่นวายมาก ขอบคุณทุกคนที่ยังอ่าน Blog ของนิลอยู่ นิลรู้สึกว่าเป็นปีที่เหมือนนั่งบนรถไฟเหาะเลยครับ มีทั้งความชิบหายและความสนุกมาก ๆ รู้สึกว่าได้เติบโตมาก ๆ เลยครับ หวังว่าปีถัด ๆ ไปจะเป็นปีที่ดีและได้เรียนรู้อะไรเพิ่มอีกครับ ปีหน้านิลกำลังเล็งว่าจะ Re-structure เว็บไซต์และเขียน Content ที่เป็น Technical มากขึ้น และๆๆ เล็งว่าจะเปลี่ยนชื่อเพจ ด้วย 555555 ขอให้ยังติดตามกันแบบนี้ต่อไปนะครับ 🥺 --- # สรุปคลาส Web For Impact ของแอดทอย DataRockie - URL: https://blog.ninprd.com/blog/summarize-web-for-impact-class/ - Published: 2024-12-18 - Tags: knowledge-sharing, summary - Summary: เมื่อวันเสาร์ที่ผ่านมา นิลไปเรียน Web For Impact กับพี่ทอย DataRockie มาครับ มีสรุปมาฝากประมาณนี้ ๆ เมื่อวันเสาร์ที่ผ่านมา นิลไปเรียน [Web For Impact](https://webforimpact.com/) กับพี่ทอย [DataRockie](https://datarockie.com/) มาครับ มีสรุปมาฝากประมาณนี้ ๆ 1. Meta Skills ที่สำคัญอย่างมากคือการอ่านและการเขียน 2. “You can only cook what’s in the fridge” เราจะเขียนอะไรได้ ต้องมีวัตถุดิบก่อน 3. Website เป็น First Principle ในการหาลูกค้า/รายได้ ต้องมีหน้าร้านที่ดีก่อน 4. การเขียน ไม่ได้สักแต่เขียน แต่เราต้องเขียนเพื่อสร้าง Impact ซักอย่างนึง 5. การเขียนเปรียบเสมือนการฝากธนาคาร ยิ่งสั่งสมทักษะการเขียน ยิ่งทำให้เราเก่งขึ้น 6. ถ้าอยากทำเว็บให้ติด Google Search หน้าแรก ให้ลองเอา Keyword ที่อยากติดไปหา จากนั้นแทรก Keyword นั้น ๆ ลงในเนื้อหาของเรา 7. เวลาเริ่มเขียนแล้วยังไม่เก่ง รู้สึกยังไม่ดี อย่าเพิ่งท้อ ให้วัด Timeframe ซัก 2 ปีก่อน 8. ไม่อยากให้ยิง ads เพื่อ Promote เพราะมันเป็นอะไรที่ชั่วคราว ตังหมดคนก็หาย 9. ที่อื่น ๆ มักจะสอน Writing, SEO, Website Skills แยกกัน แต่ความเป็นจริง 3 เราไม่สามารถแยก 3 สิ่งนี้ออกจากกันได้ มันเชื่อมโยงกัน 10. Content ควรเริ่มที่ Website ก่อน แล้วค่อยกระจายไปตาม Social Media 11. เวลาที่เราเป็น Nobody อย่าเขียนเรื่องตัวเอง ให้เขียนเรื่องคนอื่นที่ดังกว่าเรา 12. จากหนังสือ CopyWrong to CopyWriter นั้น ถ้าเรามี Strong Strategy กับ Interesting Voice จะทำให้ได้ Great Copy แหละ 13. Strategy คือกลยุทธ์ในการทำ Content โดยพื้นฐานแล้วมีอยู่ 2 อย่าง คือ Action (อยากให้คนทำอะไรให้เรา) กับ Education (ให้ความรู้) 14. Voice คือ Style การเขียนและการเลือกใช้คำ เช่น ของพี่ทอยจะใช้คำว่า ยั๊งงงง ใน Copy/Content โดยของแบบนี้เราจะต้อง Develop ไปเรื่อย ๆ ให้เป็น Style ของตัวเอง 15. “Write For One Person” ให้เราเขียนให้กับคน ๆ เดียวโดยกำหนดเป็นเหมือน Persona ขึ้นมาว่าเขาชื่ออะไร อายุเท่าไหร่ แล้วจึงออกแบบว่าในขณะที่เขากำลังอ่าน เขากำลังทำอะไร ชอบอ่านอะไร และมีความรู้สึกยังไงตอนจะอ่าน และปิดจบด้วยการกำหนด Strategy 16. One Person ที่ง่ายที่สุดคือเขียนให้ตัวเราในอดีต ลองเขียนให้เราเมื่อ 10 ปีที่แล้วมาอ่าน 17. ถ้าไม่รู้จะเริ่มเขียนอะไร ให้เริ่มเขียนเกี่ยวกับ Eternal Markets – Health, Wealth, Relationship, Happiness ยังไง Content เหล่านี้ก็มีคุณค่าตลอดกาล 18. Google ชอบ Content ที่ดีและ E-E-A-T ย่อมาจาก Experience (ประสบการตรง) Expertise (ความชำนาญ) Authority (ได้รับการ Backlink จาก Web อื่น ๆ) และ Trustworthy (ความน่าเชื่อถือและความโปร่งใส) 19. นอกจากข้อข้างบน Google ชอบให้เว็บมีการสร้าง Content (ที่ดี) บ่อย ๆ ด้วย 20. Brand Top 10 ของโลก 7/10 ชื่อมีเสียงสูงกว่าไม้โท เช่น Google, Apple, Microsoft แนะนำให้ตั้งชื่อ Brand ของตัวเองด้วย เสียงสู๊งงงง ([ninprd.com](http://ninprd.com/) นี่โคตรเรียบเลย หรือนี่ทำให้เรายังไม่ดัง 55555) --- สรุปจบพี่ทอยฝากไว้ 4 ข้อครับ ✨ Everyone should have a website ✨ Writing is a critical skills ✨ Creating Ridiculously Good Content Everyday ✨ Good Things Come to Those Who ~~Wait~~ **Write** --- # สรุป OC24: LeSS Architecture - URL: https://blog.ninprd.com/blog/summary-oc24-less-architecture/ - Published: 2024-12-03 - Tags: ODDSCONF24, OC24, conference, summary - Summary: ก่อนจะเข้าสู่เนื้อหา พี่รูฟบอกว่าหัวข้อ LeSS Architecture เนี่ย ในวันนี้พี่รูฟจะใช้เป็น Let’s Start talking about Software Architecture ก็คือไม่ได้เกี่ยวกับ LeSS (Large Scale Scrum) แต่เกี่ยวกับ Software Architecture นั่นเอง เป็น Session สุดตึงยามเช้าเพราะกำลังงัวเงียเลย 5555555 เช้าสุด ๆ จะเป็นยังไงมาลุยไปด้วยกันครับ ก่อนจะเข้าสู่เนื้อหา พี่รูฟบอกว่าหัวข้อ LeSS Architecture เนี่ย ในวันนี้พี่รูฟจะใช้เป็น Let’s Start talking about Software Architecture ก็คือไม่ได้เกี่ยวกับ LeSS (Large Scale Scrum) แต่เกี่ยวกับ Software Architecture นั่นเอง เป็น Session สุดตึงยามเช้าเพราะกำลังงัวเงียเลย 5555555 เช้าสุด ๆ จะเป็นยังไงมาลุยไปด้วยกันครับ 1. เราชอบเอา Software ไป Map กับงานก่อสร้างและสถาปัตยกรรม แต่เราเข้าใจกันจริง ๆ หรือเปล่าว่าคำว่า Architecture มันหมายความว่ายังไง 2. ถ้าพูดถึง Architecture จะมีตึกนึงที่สวยมากใน London ชื่อ Senate House ที่เป็นตึกของ University of London 3. พี่รูฟเล่าไปถึงตอนที่สร้างตึกว่าตึกนี้ได้รับโจทย์มาให้เป็นตึกที่ต้องไม่ถูกลอกเลียนแบบด้วยคนอื่น และออกแบบด้วย Architecture Style แบบ Art Deco ซึ่งได้รับแรงบันดาลใจจากยุคกลาง 4. เมื่อเลือกแล้วว่าจะใช้ Architecture Style แบบนึง ภายในตึก รวมถึงของตกแต่งก็ต้องสอดคล้องไปกับ Style นั้น ๆ เราเรียกสิ่งนี้ว่า Architecture Pattern 5. ระหว่างการก่อสร้างตึกนี้เกิดสงครามโลกครั้งที่ 2 ทำให้ถูกตัดงบ ทำให้สร้างได้ไม่ตามแบบที่วางไว้ 6. แม้จะไม่เหมือนที่วางไว้ แต่ส่วนที่สำคัญมันก็เสร็จและก็เป็นไปตาม Architecture ที่วางไว้ 7. จากจุดนี้แปลว่าการทำ Architecture ก็มี Priority เหมือนกันว่าควรสร้างตรงไหนก่อน ไม่ได้สามารถสร้างมั่ว ๆ ได้ 8. จริง ๆ แล้ว Architecture นั้นประกอบไปด้วย Style และ Pattern โดย Style นั้นมีไว้เพื่อกำหนด Pattern โดยที่ตัว Architecture นั้นไม่ได้มีความหมายอะไรไปมากกว่าสิ่งที่เราอยากได้มันคืออะไร บอกแค่เพียงแค่จุดสำคัญของมันคืออะไร 9. Software Architecture ตามนิยามคือภาพ High-Level ของระบบ Software เพื่อใช้ตัดสินใจในการทำงานในองค์กร (เป็นนิยามที่โคตร Abstract) 10. ซึ่งความสำคัญของ Software Architecture คือทำให้ Developer รู้ว่าอะไรคือสิ่งของที่สำคัญ รวมถึงสิ่งนี้สามารถใช้สื่อสารระหว่าง Stakeholders 11. จริง ๆ ในเนื้อหาจะมีอีก 2 ข้อคือเรื่องของ Scalability กับ Maintainability แต่พี่รูฟตั้งแง่กับมัน โดยมองว่า 2 สิ่งนี้ถ้ามีเงินเดี๋ยวมันจะตามมาเอง 12. ในฝั่งของ Software Architecture จะไม่เหมือนกับงานก่อสร้างอย่างนึงคือ Architecture ของงานก่อสร้างจะคงทนอยู่อย่างงั้นตลอด แต่ของงาน Software จะต้องเปลี่ยนไปตาม Requirement ยุคสมัย และงบ 55555 13. Architecture Styles และ Patterns ของฝั่ง Software มีให้เลือกเยอะมาก เลือกตามความสามารถของทีมกับความเร่งรีบของธุรกิจ เมื่อมีข้อจำกัดมา เราจะถูกบีบให้เลือกตามข้อจำกัดเอง 14. ถ้าเราต้องทำของที่ Requirement ไม่ชัดและไม่เคยมีใครทำมาก่อน เราจะเหมือนเท Resource ไปเรื่อย ๆ และตัว Software ก็ขยายไปเรื่อย ๆ 15. หลาย ๆ คนมักบอกว่าตัวเองกำลังทำสิ่งที่ไม่เคยมีใครทำมาก่อน แล้วก็จะข้ามขั้นไม่ยอมทำ Architecture Design และระบบก็จะบวมไปเรื่อย ๆ 16. แต่จริง ๆ แล้วมักจะตกหลุมพรางเพราะตัวเองกำลังทำสิ่งที่คนอื่นทำมาอยู่แล้ว ภาพใหญ่สุดมันคือการขาย Products & Services นั่นแหละ 17. มีสิ่งที่เรียกว่า eTOM (Enhanced Telecom Operations Map) ซึ่งเป็นเหมือน Blueprint ว่าถ้าจะทำ Products & Services ใด ๆ ต้องมี Process อะไรบ้าง ถ้าอยากทำ Products หรือ Services อะไร เข้าไปดูในนั้นแหละ ไม่ต้องคิดเอง 18. เวลาลูกค้ามาจ้างแล้วถามว่า “ที่ดีคืออะไร” อย่าไปแบบสมองโล่ง ๆ แล้วบอกว่าจะเรียนรู้ด้วยกัน อันนั้นลูกค้าอาจจะขอเงินคืน 555555 19. เวลาเรารับ Requirement มา ให้เปิด eTOM ดูว่า Requirement ที่เรารับมาประกอบด้วย Service อะไรบ้าง ถ้าเป็นของที่มีคนทำอยู่แล้วและไม่ใช่ Core หลักให้ Buy ถ้าเป็น Core หลักให้ Build 20. Architecture ที่ดีที่สุดไม่มีอยู่จริง ให้เราเลือกและบอกว่าคิดยังไงถึงได้ Architecture นี้มาดีกว่า 21. จากประสบการณ์พี่รูฟ ในระบบ Software ขนาดใหญ่ ไม่เคยมีของที่ใช้ Pattern เดียวกัน เราต้องค่อย ๆ ดูแต่ละจุดเพื่อดูว่า Pattern ไหนตอบโจทย์แต่ละจุดที่สุด 22. เราไม่จำเป็นต้องเลือก Pattern ที่ยิ่งใหญ่ตั้งแต่ Day 1 ของระบบ ต้องรีบ Launch ละให้ Business ไปขาย 23. เรามีโอกาสที่จะฝันอยากจะใช้ Pattern แบบหล่อเท่ แต่ให้หันมาถาม Business ด้วยว่าไหวไหม ไม่ไหวก็ลืมความฝันนั้นไปก่อน 24. อย่าเป็นคนที่ Design Architecture แต่ไม่เคยเห็น Code ที่ตัวเอง Design ถ้า Software Architect ไม่เคยเขียน Code = กลับไปขายก๋วยเตี๋ยวไป๊! 25. Key หลักคือ ก่อนจะเอาอะไรให้ลูกค้า ทำการบ้านเยอะ ๆ อ่านหนังสือเยอะ ๆ 26. หลังจากวาง Architecture เสร็จแล้ว ค่อยคิดว่าจะ Tech Stack อะไรในการ Implement สิ่งนั้น ๆ Session สมองบวมจบลงแต่เพียงเท่านี้ ขนาดมานั่ง Rewrite เอง ยังสมองบวมอีกรอบ พี่รูฟสุดยอดจริง ๆ ครับ FC พี่รูฟ เย้ ๆ --- # สรุป OC24: LeSSExample - URL: https://blog.ninprd.com/blog/summary-oc24-lessexample/ - Published: 2024-11-23 - Tags: ODDSCONF24, OC24, conference, summary - Summary: มาต่อกับอีก 1 Session ของพี่ส่ง Product Developer แห่งทีม LeSSExample ที่จะพาทุกคนมารู้จักกับ LeSSExample ให้มากขึ้นครับ มาทำความรู้จักกับ LeSSExample กันครับ มาต่อกับอีก 1 Session ของพี่ส่ง Product Developer แห่งทีม LeSSExample ที่จะพาทุกคนมารู้จักกับ LeSSExample ให้มากขึ้นครับ 1. LeSSExample คือ LeSS + Example เดี๋ยวอธิบายแต่ละอันให้ฟัง 2. ก่อนจะรู้จัก LeSS ต้องรู้จัก Scrum ก่อน 3. ตามหลักของ Scrum จะดีจะแย่ เรารู้ตัวก่อนเสมอ 4. ในทีม Scrum 1 ทีมประกอบไปด้วย Product Owner, Scrum Master, Team แต่ละคนมีศักดิ์เท่ากันแต่มี Focus แตกต่างกันไป 5. Product Owner (PO) จะเป็นคนที่ต้อง Focus เรื่องของ Return of Investment 6. PO ยังต้องเลือกและตัดสินใจว่าจะให้ Team แก้ปัญหาอะไร ทำไปทำไม ทำแล้วได้อะไร และทำแล้วได้ Value อะไร 7. Team เป็นคนที่ต้อง Focus เรื่อง Solution จาก Business Requirement นี้ จะไปทางไหนได้บ้าง ใช้ Effort เท่าไหร่ 8. Team ต้องรับผิดชอบ Solution ที่ตัวเองเลือกด้วย เช่น ถ้าเลือก Deploy เย็นวันศุกร์ เสาร์เว็บบึ้ม Team ต้องมาแก้ให้เว็บใช้งานได้ในวันเสาร์ด้วย 9. Scrum Master เป็นคนที่ Focus ว่าจะทำยังไงให้ Scrum มัน Work สำหรับคนทั้งองค์กร และทำยังไงให้ PO ทำงานร่วมกับทีมได้ 10. นอกจากนี้ Scrum Master ยังต้องเป็นคนหาว่าเราสามารถปรับเปลี่ยนอะไรในเชิงโครงสร้างองค์กรได้ไหม เพื่อทำให้ทีมแสดงศักยภาพได้มากที่สุด 11. LeSS คือการเอา Scrum มาใช้ในภาพใหญ่ขึ้น ซึ่งรองรับ Scrum 2-8 ทีม 12. ส่วนคำว่า Example คือทำให้เป็นตัวอย่างแหละ 13. เอามารวมกันเลยแปลว่าเดี๋ยวเราทำ LeSS ให้เป็นตัวอย่างนะน้อนๆ 5555555 14. LeSSExample ประกอบไปด้วย 3 Scrum Team และมี 1 Backlog ร่วมกัน 15. LeSSExample เคยอยากทำ Product การเงินชื่อว่า “ออม” ซึ่งมี Target Group เป็น Freelance แบบชาว ODDS| นี่แหละ แต่ทีมไม่มี Domain Knowledge เกี่ยวกับ Investment Product 16. ทีมเลยไปรับ Turnkey Project เกี่ยวกับ Investment เพื่อเติม Domain Knowledge และหา Revenue Stream เพื่อเอาไปทำ Investment Product ที่อยากทำ 17. ตอนนี้ทีมทำอยู่ 13 Projects ซึ่งรวมกันเป็น Backlog ที่มีชื่อ Investment Product 18. อีก 1 Ceremony ที่เกิดใน LeSS ที่น่าสนใจคือ Product Backlog Refinement (PBR) เป็น Session ที่เราจะพา Team พยายามเข้าใจปัญหาที่ PO ต้องการให้ Team แก้ 19. Session นี้จะเป็นการแบ่ง Team ออกเป็น Mixed-up Group คือคละ ๆ คนจากแต่ละทีมแหละ 20. เสร็จแล้ว Scrum Master ก็จะบอก Goal ที่ PO ต้องการและให้ Team เข้า Process ของ PBR 21. ขั้นแรกเรียกว่า Diverge ซึ่งใช้เวลา 20 นาทีคือให้แต่ละ Mixed-up Group หยิบการ์ด ถอดความเป็น Technical ออกและพยายามทำความเข้าใจมุมลูกค้า หรือถ้าเป็น Product ใหม่ ก็พยายามทำความเข้าใจ Journey ของลูกค้า เมื่อเสร็จแล้วให้จดว่าใครบ้างที่อยู่ใน Mixed-up Group ของตนลงในการ์ดใบนี้ 22. ในช่วง Diverge ถ้ามีคำถามสงสัยเราสามารถคุยกับ PO เพื่อเอาข้อมูลเพิ่มเติม หรือถ้าสงสัยจุดไหนที่เป็น Requirement ลูกค้า สามารถคุยกับลูกค้าได้โดยตรง 23. จากนั้นจะเข้าสู่ขั้นตอนต่อไปนั่นคือ Merge ซึ่งจะใช้เวลา 10 นาที โดยเราจะเอา Mixed-up Group ทุกกลุ่มมารวมกัน และสุ่มคนมาเล่าการ์ดที่เพิ่งถูก Refine มา 24. ซึ่งถ้าสมมติมีคนที่มี Domain Knowledge เกี่ยวกับการ์ดที่กำลังถูกพูดถึงอยู่ก็สามารถเสริมให้กับคนที่กำลังเล่าได้ 25. จากนั้นเราจะเข้าสู่ขั้นตอนที่ 3 ของ PBR นั่นคือ Repeat ก็คือเราจะวนกลับไป Diverge กับ Merge เรื่อย ๆ 26. ส่วนใหญ่แล้ว PBR จะเกิดขึ้นวันพุธที่ 2 ของ Sprint และใช้เวลา Session ละ 2 ชั่วโมง 27. หลังจากที่จบ PBR ทีมจะกล้าเคลมได้ว่าทุกคนในทีมเข้าใจ Backlog Item ที่ผ่าน Process นี้ไปได้ 28. ปัจจุบันทีม LeSSExample ยังเปิดให้คนภายนอกสามารถเข้ามาดูได้ว่าทีมทำงานกันยังไง โคตรโหดโคตรอันตราย ถ้าใครอ่านมาถึงตรงนี้แล้วสนใจเข้าไปศึกษา LeSS จากทีม LeSSExample สามารถติดต่อไปได้ที่ [https://lessex.odds.team/](https://lessex.odds.team/) --- # สรุป OC24: Deploy Production every sprint!? Is it possible? - URL: https://blog.ninprd.com/blog/summary-oc24-deploy-production-every-sprint-is-it-possible/ - Published: 2024-11-22 - Tags: conference, OC24, ODDSCONF24, summary - Summary: มาอย่างต่อเนื่องกับอีก Session ที่สนุกเพราะแปะมีมตลอดทางกับ Deploy Production every sprint!? Is it possible? ใน ODDS| CONF 2024 ซึ่งเอาตรง ๆ ตอนนิลอ่านหัวข้อครั้งแรกนิลก็แบบ มันจะเป็นไปได้หรอวะ ส่งของให้ User ใช้ Sprint ละครั้ง แต่สำหรับพี่จี๊บแห่ง ODDS| กับทีมของเขาแล้ว มันเป็นไปได้ครับ ทีมพี่เขาทำได้วิธีไหน มารู้ไปพร้อม ๆ กันครับ มาอย่างต่อเนื่องกับอีก Session ที่สนุกเพราะแปะมีมตลอดทางกับ Deploy Production every sprint!? Is it possible? ใน ODDS| CONF 2024 ซึ่งเอาตรง ๆ ตอนนิลอ่านหัวข้อครั้งแรกนิลก็แบบ มันจะเป็นไปได้หรอวะ ส่งของให้ User ใช้ Sprint ละครั้ง แต่สำหรับพี่จี๊บแห่ง ODDS| กับทีมของเขาแล้ว มันเป็นไปได้ครับ ทีมพี่เขาทำได้วิธีไหน มารู้ไปพร้อม ๆ กันครับ 1. สิ่งที่จะพี่ิจี๊บเล่าต่อไปนี้เป็นแค่ประสบการณ์ที่พี่เขาเจอ ไม่ได้แปลว่าใช้ได้กับทุกที่ แค่มาเล่าสู่กันฟัง 2. ทีมทำ Product Jago มี Active User 14M คน มีทีมย่อยข้างใน 3 ทีม 3. ทีมทำงานกันในรูปแบบ [LeSS](https://less.works/) แต่ยังไม่ Fully LeSS (ขอแรกตัวเองว่ายังเป็น LeSS Practitioner) 4. ด้วยวิธีการทำงานแบบ LeSS ทำให้เกิดการกระจาย Knowledge ทั้งทีม 5. วิธี Development ที่เลือกใช้คือ [Trunk-Based Development](https://trunkbaseddevelopment.com/) ก็คือทุก ๆ คนทำงานกันที่ Branch Main/Master เพื่อให้ทุก ๆ คนได้ Code ที่อัปเดทและ Stable อยู่เสมอ 6. แล้วเมื่อไหร่เราจะกล้าเอาของขึ้น Branch Master/Main ล่ะ ก็คือเราต้องเขียน Test Coverage ไว้ 100% 7. แต่เอาจริง ๆ Test Coverage 100% ยากมาก เอาเป็นว่าถ้าเราสามารถนอนหลับสนิทได้โดยไม่ต้องพะวงว่า Code เราจะไปบึ้มบน Production หรือเปล่า = Coverage ดีแล้ว 55555 8. เวลาจะทำ Feature เพิ่ม ต้องคิดเผื่อ Backward Compatibility เช่น มือถือเครื่องเก่า ๆ ยังต้องใช้งานได้ 9. สิ่งหนึ่งที่สามารถช่วยทำ Backward Compatibility ได้คือการทำ Feature Toggle (หรือที่ชาวบ้านเรียกกันว่า Feature Flag) 10. เสร็จแล้วจะมี Process ในการ Deploy ขึ้น Staging เพื่อให้ QA ทำ Regression Testing ต่อไป 11. เมื่อ QA นั่งทำ Manual Regression Testing เสร็จ แต่ละทีมก็ต้องส่งคนไปประสานกับ QA ว่า Feature ที่แต่ละทีมทำไปมี Bug อะไรไหม 12. พอ Regression Testing เยอะ ๆ และนั่งทำกัน Manual เกิด Pain ขึ้นทำให้ทีมเริ่มทำ Automation E2E Testing กันเพื่อช่วยลด Pain ให้ QA 13. ทีมคุยงานกันผ่าน [gather.town](https://www.gather.town/) ทำให้ทีมเอาผลการทำ E2E Testing มา Integrate กับ gather ให้ต้นไม้ 1 ต้น = 1 Case ถ้า Pass ต้นไม้เป็นสีเขียว ถ้า Fail ต้นไม้เป็นสีแดง 14. หลัง Test เสร็จก็จะยิง Meeting ที่ชื่อว่า “Go/No-Go Meeting” เพื่อมาคุยร่วมกันว่าของที่จะเอาขึ้นมีอะไรบ้างและของที่จะเอาขึ้นมี Known Issues อะไรบ้าง เพื่อตัดสินใจว่าจะ Go (Deploy ขึ้น Production) หรือ No-Go (ยังไม่ Deploy) 15. นอกจากนี้ยังคุยกันถึงวัน Deploy ด้วยเพื่อหลีกเลี่ยงวันที่อาจจะมี Traffic เข้ามาเยอะ เช่น ไม่ Deploy ช่วงสงกรานต์ 16. ถ้ามี Known Issues ที่ Product Owner ยอมรับได้ ทุกคนโอเคหมด ก็ Let’s Go เข้า Process เอาขึ้น Prod ละะ 17. ในขั้นตอนการ Deploy ตอนแรกใช้ GitLab CI แต่ทีมเจอ Tool ที่ดีกว่านั่นคือ Harness 18. ดีกว่ายังไง? ดีกว่าเพราะสามารถทำ Canary Deployment ได้ 19. แล้ว Canary Deployment คืออะไร มันคือการ Deploy App เราไปใช้ User แค่กลุ่มนึงใช้ก่อน แล้วพอเราได้ Feedback จาก User กลุ่มนั้นมาแล้วว่า App ทำงานได้ปกติ เราก็จะ Deploy App ไปให้ User ที่เหลือใช้ 20. Process ที่เล่ามาจะใช้เวลาประมาณ 8 วันทำการ นานที่ Regression Testing 21. ปัจจัยที่ทำให้เกิดการ Deploy Prod ทุก Sprint ได้คือการที่คิดเผื่อ Backward Compatibility, การมี Team Collaboration, การ Share Knowledge กันในทีม, การมี Test Coverage และ Regression Testing, มีการ Monitor กันและการทำ Canary Deployment 22. พี่จี๊บเล่าให้ฟังว่าปีนึงแล้วจะเกิดเหตุการณ์ No-Go ขึ้นปี 2-3 ครั้ง ซึ่งจะเกิดขึ้นเมื่อ Known Issue นั้นใหญ่มากจน Product Owner ไม่ปล่อยผ่าน ฟังแล้วแบบ Inspired มาก อยากเอาของขึ้น Production ทุก Sprint เลย 55555 --- # สรุป OC24: อะไรคือการทำ Software ต้องสนุก - URL: https://blog.ninprd.com/blog/summary-oc24-what-does-it-mean-for-software-development-to-be-joyful/ - Published: 2024-11-20 - Tags: conference, ODDSCONF24, OC24, summary - Summary: วันนี้มาแบบสรุป Topic ที่เนื้อหาสั้นแต่ได้ใจสุด ๆ ของพี่แชมป์แห่ง ODDS| จากงาน ODDS| CONF 2024 ครับ เรื่องมันมีอยู่ว่าปกติแล้วชาว ODDS| จะเชื่อว่าการทำ Software ต้องสนุกครับ พี่แชมป์บอกว่าคนข้างนอก ODDS| อาจจะไม่รู้ หรือไม่เข้าใจว่าทำไมการทำ Software ต้องสนุก พี่แชมป์เลยมาขยายเล่าให้ฟังครับ จะเป็นยังไงไปดูกันครับ วันนี้มาแบบสรุป Topic ที่เนื้อหาสั้นแต่ได้ใจสุด ๆ ของพี่แชมป์แห่ง ODDS| จากงาน ODDS| CONF 2024 ครับ เรื่องมันมีอยู่ว่าปกติแล้วชาว ODDS| จะเชื่อว่าการทำ Software ต้องสนุกครับ พี่แชมป์บอกว่าคนข้างนอก ODDS| อาจจะไม่รู้ หรือไม่เข้าใจว่าทำไมการทำ Software ต้องสนุก พี่แชมป์เลยมาขยายเล่าให้ฟังครับ รอบนี้นิลลองมาสรุปเป็น Bullet ดูครับ 1. สิ่งที่ชาว ODDS| เชื่อมาเสมอคือ “การทำ Software ต้องสนุก” 2. คำว่าสนุกของแต่ละคนไม่เหมือนกัน บางคนสนุกอาจจะหมายถึงได้ Challenge บางคนอาจจะหมายถึงการได้ชนะอะไรซักอย่าง หรือบางคนอาจจะรู้สึกเหมือนได้เปลี่ยนโลก 3. คำว่าเหนื่อยกับสนุกไม่เหมือนกัน บางครั้งเราทำงานหนักเราอาจจะรู้สึกเหนื่อย แต่ถ้ามันยังสนุกอยู่ = การทำ Software เรายังสนุกอยู่ 4. ทำไมการทำ Software ต้องสนุก เพราะถ้าไม่สนุก เราก็จะนั่งหมดใจในออฟฟิศรอให้เวลาผ่านไปเรื่อย ๆ 5. คนที่เป็น Lead ต้องสามารถซื้อ Trust ของทีมให้ได้ เพื่อให้ทีมกล้าพูดว่าตัวเองยังสนุกกับงานอยู่หรือเปล่า 6. ถ้าคนในทีมไม่สนุกแล้ว สำหรับ Lead แล้วก็ต้องหาวิธีแหละ ถ้ายังอยากให้คนในทีมสนุกอยู่ 7. ถ้างานมันสนุกแล้ว ชิ้นงานที่ออกมามันจะออกมาไม่แย่ อาจจะไม่ได้ดีเลิศ แต่ก็สามารถผ่านอุปสรรคที่เข้ามาได้ก่อน 8. พี่แชมป์ลองไปถามชาว ODDS| เรื่องของความสนุกของการทำ Software บางคนก็ตอบว่าการได้รับงานยาก ๆ และผ่านมันได้เป็นเรื่องสนุก บางคนก็ตอบว่าการได้ส่งของที่ดีให้ User เป็นเรื่องสนุก สรุปก็คือความสนุกของแต่ละคนไม่เหมือนกัน (เหมือนข้อ 2 นั่นเอง 5555) อย่าลืมสนุกกับการทำ Software นะครับ --- # สรุป Session จากงาน SCBX Unleashing CX: EP3 Figma Bangkok Meetup - URL: https://blog.ninprd.com/blog/summarize-figma-bangkok-meetup-2024/ - Published: 2024-11-01 - Tags: meetup-2024, meetup, scbx-next-tech, uxth, summary - Summary: สวัสดีครับ วันนี้นิลได้มีโอกาสไปงาน SCBX Unleashing CX: EP3 Figma Bangkok Meetup มาครับ ซึ่งในงานก็มี Session ในฟังถึง 3 เรื่องเลย หัวข้อแรกพี่แบงค์มาพูดถึงเทคนิคและวิธีการจัดระเบียบ Design System ในสำหรับงาน Scale เล็ก กลาง ใหญ่ครับ หัวข้อที่ 2 อ.วิชัยจากเพจ Qwerty is a DUCK วันนี้อาจารย์มาแบ่งปัน Tools เพื่อเพิ่ม Quality of Life ให้กับชาว Design ครับ และ Session สุดท้าย พี่แบงค์ อ.วิชัย และคุณเอกจากเพจ UncleAke มาเปิดวงคุยเกี่ยวกับ Figma UI3 ว่ามันต่างจาก UI เก่ายังไงและเขาสูญเสียอะไรไปบ้างเพื่ออะไรครับ แต่ละหัวข้อจะเป็นยังไง ไปดูกั๊น สวัสดีครับ วันนี้นิลได้มีโอกาสไปงาน SCBX Unleashing CX: EP3 Figma Bangkok Meetup มาครับ ซึ่งในงานก็มี Session ในฟังถึง 3 เรื่องเลย หัวข้อแรกพี่แบงค์มาพูดถึงเทคนิคและวิธีการจัดระเบียบ Design System ในสำหรับงาน Scale เล็ก กลาง ใหญ่ครับ หัวข้อที่ 2 อ.วิชัยจากเพจ Qwerty is a DUCK วันนี้อาจารย์มาแบ่งปัน Tools เพื่อเพิ่ม Quality of Life ให้กับชาว Design ครับ และ Session สุดท้าย พี่แบงค์ อ.วิชัย และคุณเอกจากเพจ UncleAke มาเปิดวงคุยเกี่ยวกับ Figma UI3 ว่ามันต่างจาก UI เก่ายังไงและเขาสูญเสียอะไรไปบ้างเพื่ออะไรครับ แต่ละหัวข้อจะเป็นยังไง ไปดูกั๊น ## Design System แบบพอดีคำ พี่แบงค์บอกว่าหลาย ๆ องค์กรชอบทำ Design System แบบคำใหญ่เกิน (ทำเยอะเกินที่ตัวเองใช้) ทำให้รสชาติไม่อร่อยครับ หลัก ๆ แล้วเราควรออกแบบ Design System ตาม Cognitive Load ของ Project ไป ซึ่งถ้างานขนาดเล็ก เราก็อาจจะไม่จำเป็นจะต้องมี Design System จริงจังก็ได้ แค่วางของในหน้าเดียวกันก่อนก็ได้ ถ้างานใหญ่หน่อยก็อาจจะต้องทำจริงจังขึ้นมา ซึ่งการจะวัดว่างานนั้นมีขนาดเท่าไหร่ พี่แบงค์บอกว่าเราจะใช้ปริมาณหน้ามาวัด ถ้าประมาณ 10 หน้าเราจะเรียกว่างานขนาดเล็ก ถ้าไม่เกิน 50 หน้า เราจะเรียกว่าขนาดกลาง และมากกว่า 100 หน้าก็จะเป็นขนาดใหญ่ครับ เราจะแบ่ง Design System ออกเป็น 3 แบบตามจำนวนหน้าครับ แบบแรกประมาณ 10 หน้า แบบที่ 2 คือประมาณ 50 หน้าและสุดท้ายคือประมาณ 100 หน้าครับ ซึ่งแต่ละแบบก็จะมีการทำ Desing System ที่ต่างกันออกไปครับ ซึ่งเดี๋ยวจะถูกพูดถึงในลำดับถัด ๆ ไป นอกเหนือจากเรื่องของการออกแบบตามขนาดแล้ว พี่แบงค์ยังให้ Component Guide เพิ่มเติมมาตามนี้ครับ 🌟 **วาง Component ใกล้กับที่ ๆ ใช้มันมากที่สุด** ถ้าใช้ Component นั้นแค่ 1 ที่ให้วาง Component นั้น ๆ ไว้ข้าง Frame ที่ออกแบบเลย ถ้าใช้ Component นั้นมากกว่า 1 ที่ให้วาง Component ใกล้ ๆ และครอบด้วย Frame เอาไว้ ถ้าใช้ Component นั้นมากกว่า 1 หน้าให้สร้าง Page: Component ใน Figma แล้วย้าย Component เราไปอยู่ในนั้น เราสามารถใส่ Emoji ❖ (ชื่อของมันคือ Black Diamond Minus White X) นำหน้า page ของ component เพื่อให้หา page นั้นง่าย ๆ ด้วยครับ ถ้าใช้ Component นั้นมากกว่า 1 Figma file: ให้แยกเป็น Figma component file และ import เข้ามา 🌟 **ใช้ชื่อให้สม่ำเสมอกันทั้ง Project**= หลัก ๆ แล้วการทำ naming ของนั้นมีด้วยกัน 3 ระดับ ระดับแรกสุดคือ Brand Color หรือใช้ชื่อของสี เช่น Slate 700, White 900 เป็นต้น ระดับที่สองคือ Semantic Color หรือการระบุหน้าที่ของสีนั้น ๆ เช่น Text-Primary, Background-Primary, Background เป็นต้น และระดับสุดท้ายคือ Component นั่นคือการเอาชื่อ Component มาระบุเข้าไป เช่น Card-Title, Card-Background เป็นต้น ![Chart showing color naming in Figma](assets/naming-figma-color.webp) ซึ่งหลัก ๆ จากข้อนี้คือให้เราเริ่มจากการค่อย ๆ กำหนด brand color ละไล่ไป semantic และค่อยไล่ไป component **อย่ารีบซับซ้อนโดยไม่จำเป็น** Tips อีกข้อที่พี่แบงค์บอกมาคือ อย่าใช้ Hex Code ในการใส่สีใน Frame เด็ดขาด เพราะทำให้เราต้องตามแก้เยอะ ให้กำหนดสีเป็น Local Styles หรือ Variables เอาไว้ พี่แบงค์ฝาก plugin Figma ไว้อีกตัวครับชื่อว่า [Design Lint](https://www.figma.com/community/plugin/801195587640428208/design-lint) เอาไว้ช่วย detect ว่าตรงไหน เรามีการ hard code พวก Hex Code ไว้ หรือว่ามีการใช้ของไม่ถูก system 🌟 **ให้แต่ละ group มี component หลัก 7 ตัว** ในข้อนี้พี่แบงค์บอกว่าเราสามารถใช้หลาย ๆ หลักการเพื่อเข้ามาช่วยเรื่องนี้ได้ เช่น Atomic Design เป็นต้น แต่มันก็อาจจะไม่ใช่วิธีที่ดีที่สุดสำหรับเราก็ได้ ลองนึกเวลาเรากอง component เอาไว้เยอะ ๆ แล้วเราต้องกลับมาหาของในกอง component นั้นอะ ยากอยู่นะ ดังนั้นวิธีที่พี่แบงค์ทำก็คือ ค่อย ๆ ปั้น component มาเรื่อย ๆ และเมื่อของที่ใกล้เคียงกันครบ 7 อันเมื่อไหร่ให้ group มันแล้วตั้งชื่อให้พวกมัน ทำแบบนี้ไปเรื่อย ๆ เราจะหาของง่ายมากขึ้นเพราะ group นึงเราจะมีของไม่เกิน 7 อันและจะเป็น 7 อันที่เรา group ของใกล้ ๆ กันไว้ อีก Tips นึงจากพี่แบงค์คือใน group นึงเนี่ย ควรวางของในแนวเดียวกัน (แนวตั้ง/แนวนอน) เพื่อให้สามารถ scan หาของจากบนลงล่างหรือซ้ายไปขวาทางใดทางหนึ่งเท่านั้น ## Awesome ~~Plugins~~ Tools ในหัวข้อนี้ อ.วิชัยบอกว่าตัวเองไม่ได้เป็น Designer เลยไม่ได้แนะนำ plugin Figma แหละ แต่มาแนะนำ tools ที่อาจจะทำให้คุณภาพชีวิตเหล่า Designer ดีขึ้นครับ จะมีตัวอะไรกันบ้าง ไปดูกันเลย **🌟 Design Sidekick** เพื่อน ๆ เคยเข้าไปหน้าเว็บไหนแล้วรู้สึกว่าถูกใจ อยากดูดสีมาใช้ไว ๆ ไหมครับ หรืออยากรู้ว่าเขาใช้้ Typography แบบไหน ถ้าเคยล่ะก็ ลองใช้่ Chrome Extension: Design Sidekick เป็นตัวช่วยดูสิครับ ตัว extension นี้จะสามารถทำให้เราเห็น palette หลักของเว็บไซต์ รวมถึงสามารถดู typography style ต่าง ๆ ของหน้าเว็บไซต์นี้ทั้งหมดครับ นอกเหนือจากนั้นแล้วยังสามารถดู SEO Checklist ของหน้านั้น ๆ ได้อีกด้วย ช่วยในเรื่องของ SEO ได้อีก และยังไม่หมด ๆๆ ยังสามารถใช้แทนการกด Inspect ด้วย ทำให้ชีวิต Designer ไม่จำเป็นตัองเข้าไป inspect panel แบบชาว Developer แหละ **🌟 SVG Globber** ตัวนี้เป็น Chrome Extension ที่ใช้งานในดึง SVG ที่อยู่ในหน้านั้น ๆ ออกมาและสามารถแก้ไข ดัดแปลง เปลี่ยนขนาด icon รวมทั้งสามารถ copy ออกไปและ export เป็น svg หรือเป็น React code ได้เลย นอกจากนี้ tool ตัวนี้ยังสามารถสร้าง icon ที่เราไปดูดมาเป็น collection ได้อีกด้วย บอกเลยว่าโหดสุด ๆ **🌟 Noise & Texture** Plugin ตัวนี้เอาไว้สร้าง Noise หรือใส่ Texture ลงใน frame ต่าง ๆ โดย texture จะมีทั้งแบบภาพนิ่งและ animation ด้วยแหละ และ ๆๆๆ เราสามารถ export frame นั้น ๆ ออกมาเป็น iframe, React code, หรือเป็นรูปแบบ json ได้อีกด้วย โคตรเมพ จบหัวข้อนี้พี่แบงค์มาเสริมว่า Figma ใช้ออกแบบ icon ได้ดี แต่อย่าใช้วาดรูป ## UI 3: What and Why? หลัก ๆ ที่ได้จาก Session นี้คือ pain point ของ Figma ใน UI เก่าคือความไม่สม่ำเสมอของข้อมูลใน toolbar ด้านบน ทำให้ Figma เลือกจะย้าย menu ที่เคยเข้าถึงง่ายจากด้านบน เช่น Layer intersection, Create a new component เข้าไปซ่อนอยู่ทางขวามือให้หมด เพื่อให้ไม่ว่าจะ click ที่ layer แบบไหน behavior ก็จะสม่ำเสมอทั้งหมด ซึ่งปัญหานี้เกิดจากสิ่งที่เรียกว่า Information Architecture แหละครับ เนื่องจากเขาอยากได้ความสม่ำเสมอ ก็จะต้องมีบางอย่างที่ต้องสูญเสียและแลกมาครับ กับอีกปัญหากวนใจของ toolbar ใน UI3 คือมันอยู่ด้านล่างครับ ซึ่งใน MacOS นั้น เวลาเราจะใช้ของใน toolbar เราจะต้องเอาเม้าส์ลากลงข้างล่าง ซึ่งสิ่งที่เกิดขึ้นคือเราจะไปโดน dock ขึ้นมาบังครับ ซึ่งคุณเอกกับพี่แบงค์ตั้งข้อสังเกตว่าที่เขาย้ายลงมาไว้ข้างล่าง เพราะน่าจะมาจาก FigJam ที่ไว้ toolbar ไว้ด้านล่างครับ ซึ่งข้อสรุปของทั้ง 2 คนคืออยากให้ย้าย toolbar ไปไว้ด้านบน (พี่แบงค์ฝากใครก็ได้ไปเปิดใน Figma Community หน่อยเดี๋ยวพี่แบงค์ไปตาม 555555) สุดท้ายคุณเอกกับพี่แบงค์ก็บอกว่าถ้าใครรู้สึกว่าข้อที่เขากล่าวมา วิธีแก้ปัญหาเบื้องต้นก็จะเป็นการกลับไปใช้ UI เก่าก่อน เพื่อลดความสับสนและรอทาง Figma พัฒนา UI ใหม่ที่ดีขึ้นออกมาครับ --- จบไปแล้วสำหรับ Blog สรุปงาน Figma Bangkok Meetup ครับ ขอบคุณงานดี ๆ จากพี่แบงค์ อ.เจมส์และก็คุณเอก รวมถึงทีมงานทุกคนเลยครับ สุดยอดมาก สุดท้ายถ้าใครอยากได้ slide สามารถไปโหลดได้ที่[โพสต์นี้ของเพจ Qwerty is a DUCK](https://www.facebook.com/share/p/BDvqtjyVfbL9NvFs/) เลยครับ นิลได้เจออ.เจมส์ละถ่ายรูปมาด้วย แค่นี้ก็คุ้มละครับ อิอิ วันนี้ลาไปก่อน สวัสดีครับ --- # สรุป Session - Why use JavaScript when CSS is possible? - URL: https://blog.ninprd.com/blog/summary-session-why-use-javascript-when-css-is-possible/ - Published: 2024-10-20 - Tags: software-engineer, conference, JavaScript-Bangkok, JSBKK2 - Summary: สวัสดีครับ วันนี้นิลได้ไปงาน JavaScript Bangkok 2.0.0 มาฮะ เลยลองสรุป Session - Why use JavaScript when CSS is possible? Session ของพี่จุ้นจาก MUI มาแหละ จะเป็นยังไง ลองไปดูกัน สวัสดีครับ วันนี้นิลได้ไปงาน [JavaScript Bangkok 2.0.0](https://javascriptbangkok.com/) มาฮะ เลยลองสรุป Session: Why use JavaScript when CSS is possible? Session ของพี่จุ้นจาก [MUI](https://mui.com/) มาแหละ ลองไปดูกัน พี่จุ้นมาพูดถึงการทำ Reusable Components ครับ ซึ่งการจะทำให้มันดีเนี่ย ต้องมีองค์ประกอบอะไรบ้างกับแต่ละ Stakeholder ซึ่งแต่ละ Stake มีเงื่อนไขแบบนี้ - End Users (ผู้ใช้งานหน้าเว็บ): UI ต้องน่าดึงดูดและโหลดไว - Business: Implement ไว และ Scale ได้ - Frontend Devs: ไม่ผูกมัดกับ Framework, ใช้ง่าย, Customize ง่าย, Developer Experience ดี แล้วจากเงื่อนไขเหล่านี้ CSS Method ไหนที่ตอบโจทย์ล่ะ พี่จุ้นมองว่า **CSS Modules + Inline Style** คือ Combo ที่ตอบโจทย์เหล่านี้มากที่สุด แล้วทำไมถึงเป็นคู่นี้ ต้องอธิบายถึง CSS Modules ก่อนว่า CSS Modules เป็นของที่ Built-in Support ในหลาย ๆ Framework เช่น Next, Nuxt, Solid ซึ่งการใช้งานนั้นก็เป็นเพียงแค่การ Import CSS File เป็น Module แล้วนำไปใช้งานใน File JS แบบนี้ครับ ```css title="button.module.css" .btn { background-color: red; padding: 12px 24px; } ``` ```js title="button.jsx" import * as styles from './button.module.css'; export default function Button() { return } ``` แต่การทำแบบนี้ก็จะมีปัญหาในเรื่องของการทำ Dynamic Styling ครับ เพราะว่าถ้าเราใช้ CSS Modules แล้ว เราต้องประกาศ CSS rules เป็น combination ของ style ปุ่ม ขนาดของปุ่ม และสีของปุ่ม แปลว่าถ้ามีปุ่ม 4 styles 3 ขนาด และ 4 สี ก็ต้องสร้าง CSS rules ตั้ง 48 rules แหนะ รวมทั้ง CSS นั้น ยังไม่มีความสามารถในการทำ Tree-Shaking ด้วย ถ้าเราประกาศ CSS rules เยอะ แต่ไม่มีการใช้ = หนักเว็บเล่น ๆ เว็บเราก็จะโหลดช้าอีก ดังนั้นพี่จุ้นเลยเสนอการเอา Inline Style มาใช้ร่วมกับ CSS Modules โดยมีขั้นตอนตามนี้ 1. Template CSS: สร้าง CSS Modules ที่มีแต่ CSS variables ผูกกับ Properties ต่าง ๆ ไว้ ```css title="button.module.css" .btn { padding: var(--padding); height: var(--height); } ``` 2. สร้าง Function ที่ return CSS variables ตาม style ที่กำหนด ```js title="button-styles.js" export function buttonSmall() { return { "--padding": "4px", "--height": "32px" }; } export function buttonNormal() { return { "--padding": "12px 16px", "--height": "40px" } } ``` 3. inject ใส่ Inline Style ```js title="button.js" import * as styles from './button.module.css'; export default function Button({style}) { return ( ); } ``` 4. Import ไปใช้งานแค่นี้ก็เสร็จละ ```js title="page/home.js" import { ButtonSmall } from "../components/button/button-styles.js"; import Button from "../components/button/button.js" export default function HomePage() { return (
); } ``` พี่จุ้นขิงด้วยว่าวิธีนี้ Bundle Size สูสีกับ [tailwindcss](https://tailwindcss.com/) แหละะ (อันนี้ว้าวมาก) นอกจากนี้พี่จุ้นก็ย้ำอีกครั้งว่าวิธีนี้ 1. ใช้ได้กับทุก Framework 2. Style ที่ไม่ได้ถูก import มาใช้ = ถูก Tree-Shaking 3. ง่ายต่อการ extend ทุกอย่างจัดการผ่าน style attribute 4. มี auto complete ให้ใช้กับ key ของ style 5. ใกล้เคียงกับ Native CSS และ JavaScript มาก สุดท้ายตอนนี้พี่จุ้นกำลังทดลองเพิ่มเติมอยู่ว่าวิธีนี้ใช้ได้ในระดับ production grade ไหมแหละครับ ต้องมาลุ้นกันครับ ถ้าใครพลาด Session นี้ในวันนี้ไปไม่ต้องห่วงนะครับ เดี๋ยวมี Live ย้อนหลังให้ชมกันครับ ติดตามกันได้ที่เพจ Facebook: [JavaScript Bangkok](https://www.facebook.com/javascriptbangkok) ได้เลยครับ วันนี้นิลหนีไปนอนก่อน สวัสดีครับ 😴💤 --- # สรุป Session - Designing Interfaces with ROI as the Primary Goal - URL: https://blog.ninprd.com/blog/summary-session-designing-interfaces-with-roi-as-the-primary-goal/ - Published: 2024-09-15 - Tags: meetup, meetup-2024, scbx-next-tech, uxth, summary - Summary: วันนี้นิลชวนมาอ่าน Content สรุปจาก Session Designing Interfaces with ROI as the Primary Goal ของคุณ Dave Malhotra ในงาน Designing for Maximum Impact and Scale กันครับ สรุป Session - Designing Interfaces with ROI as the Primary Goal ในงาน SCBX Unleashing CX: EP2 Designing for Maximum Impact and Scale ซึ่งเป็น Session ของคุณ Dave Malhotra, CEO & Lead Hustler ของ Shakesphere & Soldoutt ครับ คุณ Dave เปิด Session ด้วยคำพูดที่เขาชอบมากของ Steve Jobs ครับ นั่นคือ > You’ve got to start with the customer experience and work backward to the technology. You can’t start with the technology then try to figure out where to sell it. – Steve Jobs ซึ่งคุณ Dev บอกว่าในกรณีของเขาเขาออกแบบสำหรับ User ที่จ่ายตังให้เขาเท่านั้น (Design For Buyers) 🌟 **ปัญหาที่คนสมัยนี้ต้องเผชิญ** 1. **Information Overload:** ข้อมูลใน Internet มีเยอะเกินไป และคนเราได้รับข้อมูลมากกว่าที่จำเป็นต้องรู้ต่อวันไปเยอะเลย 2. **Over Supply:** ในยุคปัจจุบัน เราต้องเผชิญกับการมีสินค้าและบริการที่มีมากเกินความจำเป็น ความหลากหลายที่มากเกินไปนี้ทำให้ผู้คนรู้สึกสับสนและยากที่จะตัดสินใจเลือกสิ่งที่เหมาะสมกับตนเอง 3. **Attention Span ที่น้อยลงไปเรื่อย ๆ:** คุณ Dave กางข้อมูลมาว่า Attention Span เฉลี่ยของคนในปี 2015 นั้นมีเพียง 8 วินาทีซึ่งเมื่อเทียบกับปลาทองที่มี Attention Span เฉลี่ย 9 วินาทีนั้น ตอนนี้ปลาทองได้ชนะคนในเรื่อง Attention ไปเรียบร้อยแล้ว 🌟 **เทคนิคที่ใช้ช่วยในการออกแบบเพื่อ Drive การขาย** - **Prioritize information in the UI** เวลาลูกค้าจะซื้อ Product ครั้งนึง จะมีคำถามมากมายเต็มไปหมด แต่เราต้องกลับมาถามตัวเองว่า UI ของเราต้องตอบคำถามเหล่านี้จริง ๆ หรอ ซึ่งส่วนใหญ่แล้ว UI เราไม่ต้องตอบทุกคำถามในหัวของ User ทุกข้อก็ได้ เราแค่ต้องออกแบบ UI ให้ Connect The Dot ง่าย List ข้อมูลที่ช่วยให้ User ตัดสินใจซื้อของง่าย นำมาเรียงลำดับความสำคัญและเอาไปแปะที่ UI เลย Quick Tips ก็คือยิ่ง User เห็นข้อมูลน้อยบนหน้าจอ ยิ่งใช้เวลาน้อยในการตัดสินใจเท่านั้น ดังนั้นให้ดูว่า UI ไหนเกำลังขัดขวางการซื้อ ถ้าไม่สำคัญก็เอาออก - **Delay low priority or non-required actions** ปกติแล้วหน้า UI ที่ให้ User กรอกจะชอบมีช่องให้กรอกข้อมูลเยอะมาก ซึ่งปกติหลาย ๆ ที่จะชอบขอข้อมูลแบบ Just In Case หรือขอแบบเผื่อ ๆ ไว้ก่อน ซึ่งก็จะทำให้ User รำคาญมาก ๆ และอาจจะปิดหน้าเว็บไปเลยก็ได้ ดังนั้นหลัก ๆ เลยคือการ Chunking ให้ User กรอกข้อมูลน้อยที่สุดในแต่ละขั้นตอน เช่น แทนที่จะให้ User กรอก Form 20 ช่องทีเดียว ก็อาจจะเลือกแค่ Field ที่จำเป็นมาให้ User กรอกในขั้นแรกและให้กรอกของที่สำคัญน้อยกว่าในขั้นตอนถัด ๆ ไป คุณ Dave เลยโยนคำถามกับมาว่า เวลาสร้าง Form ขอข้อมูลเนี่ย อะไรที่สำคัญกับเรากันแน่? Branding, ข้อมูล หรือเงิน และก็โยนอีก 3 คำถามมาว่าเราต้องการข้อมูลเยอะขนาดนั้นไหม จะเอาข้อมูลไปใช้ยังไง และเป็นหน้าที่ของ User ไหมที่ต้องกรอก Data เหล่านั้น คุณ Dave ยกตัวอย่างเรื่องการกรอกข้อมูลของ Soldoutt ในกรณีที่มีคนซื้อตั๋วแบบกลุ่มเข้ามา โดย UI จะให้ User คนที่เป็นคนกรอกหลักกรอกแค่ข้อมูลตั๋วของตัวเองเท่านั้น และจะส่งอีเมลให้กับคนที่เหลือกรอกข้อมูลของตัวเองต่อไป ทำให้คนที่เป็นคนซื้อหลัก ไม่จำเป็นต้องกรอกข้อมูลของคนอื่น ๆ โดยไม่จำเป็น - **Take inspiration from others but make sure you design for your customer needs** หลาย ๆ ครั้งในฐานะ Designer เราอาจจะไปหยิบ Inspiration จากที่ต่าง ๆ แต่อย่าลืมว่าเราต้อง Design โดยดูว่า User อยากได้อะไร **🗂️ เคส Powerbuy** Powerbuy เข้าใจว่า User เมื่อซื้อเครื่องไฟฟ้าก็มีความอยากได้ของไว ๆ ทีมเลยตัดสินใจใส่ Visual Cue เพื่อบอกว่าของจะส่งในระยะเวลากี่ชั่วโมง กี่วันเพื่อช่วยให้ User ตัดสินใจง่ายขึ้น อีกอย่างที่ Powerbuy ทำคือการไม่ทำให้ User เคว้งคว้าง ไปต่อไม่ได้ โดยจะมีการ Track ว่า User หยุดที่ขั้นตอนไหนและหาปัญหาที่ Block การซื้อเพื่อทำให้ User ไปหน้า Checkout ให้ง่ายที่สุด **🗂️ เคส Soldoutt** Soldoutt มีการใช้เทคนิคของ FOMO, Social Proof และเขียน Visual Cue ที่บอกว่าทำไม User ควรซื้อตั๋วตอนนี้ไว้เพื่อ Drive ให้ User ทำ Action ที่เราต้องการมากที่สุด - **Use Visual Cues but not too much** อย่างในหัวข้อเมื่อกี้จะมีเรื่องของการเพิ่ม Visual Cues มาเพื่อ Drive การขาย แต่ทั้งนี้ทั้งนั้น เราต้องมั่นใจว่ามันไม่เยอะเกินไปจนทำให้ User รำคาญได้ - **No Exit Door** อันนี้แอบโหดร้ายนิดนึง แต่คุณ Dave บอกว่าอันนี้คือ 1 ในสิ่งที่เขาทำนั่นคือการไม่ให้มีปุ่ม Back to home หรือปุ่ม Go Back ในหน้า Checkout ซึ่งทำให้ User ต้อง Hard Exit นั่นคือปิดหน้าเว็บไปเท่านั้น - **Use Screen Recording Tool to watch what users are doing** ลองใช้ Tools ที่อัดหน้าจอเพื่อดูว่า User กำลังทำอะไร เช่น [Hotjar](https://www.hotjar.com/) เพื่อเก็บ Data และนำมาวิเคราะห์ว่าเราควรจะปรับปรุงจุดไหนของ Product เรา 🌟 **สรุป** UI ไหนไม่จำเป็นหรือขวางการซื้อของ User ให้เอาออกเพื่อ Drive User ไปทำ Action ที่เราต้องการมากที่สุดและให้เอา Data มาประกอบการตัดสินใจมากขึ้นเพื่อให้ได้ผลที่จับต้องได้มากขึ้น เมื่อเราออกแบบ UI ของเราอย่างระมัดระวังแล้ว เราก็มีโอกาสที่จะ Boost Conversion ได้มากยิ่งขึ้น --- # สรุป Session - Building a Community-First “Hotel” CX to Attract Digital Nomads to Chiang Mai - URL: https://blog.ninprd.com/blog/summary-session-building-a-community-first-hotel-cx-to-attract-digital-nomads-to-chiang-mai/ - Published: 2024-09-14 - Tags: meetup, meetup-2024, uxth, scbx-next-tech, summary - Summary: สรุป Session - Building a Community-First “Hotel” CX to Attract Digital Nomads to Chiang Mai ในงาน SCBX Unleashing CX: EP2 Designing for Maximum Impact and Scale ซึ่งเป็น Session ของคุณ John Ho, Founder and CEO ของ Alt_Coliving and Coworking Spaces สรุป Session - Building a Community-First “Hotel” CX to Attract Digital Nomads to Chiang Mai ในงาน SCBX Unleashing CX: EP2 Designing for Maximum Impact and Scale ซึ่งเป็น Session ของคุณ John Ho, Founder and CEO ของ Alt_Coliving and Coworking Spaces คุณ John Ho บอกไว้ก่อนเลยว่าเขาไม่ใช่ Designer เขาอาจจะไม่ได้ใช้คำศัพท์ของฝั่ง Designer มากนัก คุณ John Ho เปิดธุรกิจโรงแรมในเชียงใหม่ ชื่อว่า Alt_ChiangMai ซึ่งมี License โรงแรม แต่ไม่เรียกตัวเองว่าโรงแรม แต่เขาเรียกตัวเองว่า “Co-Living and Co-Working Spaces” เพราะว่าปกติเวลาเราไปโรงแรม เราจะไปเพลิดเพลินกับการอยู่กับตัวเองและการใช้ Facility ของโรงแรม แต่ที่ Alt_ChiangMai เขาจะมีการแปะชื่อหน้าห้องและให้ทุกคนสามารถมาทำกิจกรรมร่วมกัน โดยวิธีที่เขาเลือกใช้คือ “Community-First” ✨ **Community-First คืออะไร** Community-First คือการที่ออกแบบโดยใช้ Community เป็นแกนกลาง โดยไม่ว่าจะทำอะไร ก็จะถามกับ Community เพื่อนำมาปรับปรุง Service ได้ ยกตัวอย่างเช่น การมีจัดกิจกรรม Ice-Bathing มาให้ทุกคนทำร่วมกัน หรือมีการให้ทุกคนที่พักอยู่สามารถลงชื่อเสนอกิจกรรมและมาทำร่วมกันในช่วงสุดสัปดาห์ได้ ซึ่งคุณ John Ho ก็ได้เอา Social Proof มาให้ดูก็คือรีวิวผ่าน Google Reviews ซึ่งมีรีวิวยาว ๆ ด้วยความประทับใจเป็นจำนวนมาก คุณ John Ho ยังพูดถึง Activity ที่ชื่อ Family Meeting ซึ่งเป็นการรวมคนที่พักใน Alt_ChiangMai ในช่วงเวลานั้น ๆ เพื่อมาแนะนำตัวและคุยกันว่าในวีคนั้น ๆ จะทำอะไรเป็นระยะเวลา 30 นาที ซึ่งช่วงหลัง ๆ คนที่มาพักก็เป็นคนจัด Event เอง คุณ John Ho ไม่ต้องมาจัดการเรื่องนี้เลย ✨ **แล้ว Target Users ของ Alt_ChiangMai คือใคร** คุณ John Ho พูดถึง Digital Nomads ซึ่งคนเหล่านี้คือคนที่ทำงานหน้าคอมที่สามารถ Work From Anywhere ได้ ซึ่งเชียงใหม่ก็ถือเป็น Capital of Digital Nomads เลยก็ว่าได้ ซึ่งก็มีโอกาสที่น่าสนใจ เช่น ประเทศไทยก็ถือเป็นเป้าหมายอันดับต้น ๆ ใน Asia สำหรับ Digital Nomads รวมทั้งพวก Digital Nomads ก็ต้องการที่อยู่อาศัยด้วย ซึ่ง Pain Point ของคนเหล่านี้คือต้องการ Internet และรู้สึกเหงา คุณ John Ho บอกอีกว่าล่าสุดประเทศไทยเพิ่งมี Visa แบบ Destination Thailand Visa ซึ่งถูกออกแบบมาสำหรับ Digital Nomads โดยเฉพาะ โดย Visa นี้ทำให้สามารถอยู่ในไทยได้นานสุด 180 วันแหนะ ถือเป็นโอกาสที่ดีมาก ✨ **การออกแบบ Community-First เพื่อ Target Digital Nomads นั้นทำอะไรบ้าง** - **Spatial Design:** ออกแบบให้พื้นที่มี Share Space มากขึ้น เพราะ Alt_ChiangMai Focus ให้ทุกคนได้มาใช้พื้นที่ส่วนกลางร่วมกัน ซึ่งเขาได้ไปนั่งทำ Analysis และคิดก่อนว่า User จะเดินยังไง เพื่อแบ่งพื้นที่ให้ดีมากขึ้น - **Pricing Design:** ออกแบบให้เหมาะสำหรับ Target Users ที่เป็น Digital Nomads โดยออกแบบให้ยิ่งอยู่นาน จะลดเยอะขึ้น เพื่อตอบโจทย์คนที่มาอยู่ยาว ๆ ✨ **การใช้ Community-First กับการออกแบบ Location ใหม่** เมื่อปีก่อนคุณ John Ho มีแผนที่จะเปิด Alt สาขาใหม่ ซึ่งเขาก็บอกว่าเขาไม่มีตังขนาดนั้น เขาเลยมา Raise Funds ในหมู่คนที่มาพักใน Community ของ Alt_ChiangMai ซึ่งเขาได้เงินมาทำ Alt สาขาใหม่ 20 ล้านบาท (บ้าไปแล้ววว) ซึ่งระหว่างทางเขาก็เอาภาพ Render ไปถามใน Facebook Group ของ Digital Nomads ดูเพื่อไปลองถามดูแบบ เขาอยากได้อะไรบ้างสำหรับ Co-Working & Co-Living Space อันนึงที่ชอบเลยคือเขายกตัวอย่างว่า เขาไปถามว่าในกลุ่มว่าอยากได้สระว่ายน้ำกันไหม ในกลุ่มเลยตอบกลับมาว่าไม่อยากได้สระว่ายน้ำ อยากได้เก้าอี้ Ergonomics 555555 คุณ John Ho บอกว่า ถ้าอยากได้อะไร ให้ถาม Community แล้วเขาจะบอกเองว่าพวกเขาอยากได้อะไร ✨ **สรุป** อยากรู้อะไร ให้ใช้ Community-First Approach ให้ถาม Community ถามคนที่มาพักว่าเขาชอบ/ไม่ชอบ หรืออยากได้อะไร เพื่อสร้าง Feedback Loop และนำมาปรับปรุง Product/Service ได้ไวและตอบโจทย์มากขึ้น คุณ John Ho ฝากทิ้งท้ายเอาไว้ว่าปกติเวลาเขามากรุงเทพ เขาจะไป Hangout ที่ The Commons Thonglor เพื่อ Hang Out ครับ เผื่อใครไปเจอสามารถทักทายได้ --- # สรุป Session - Design for better Digital Government Services - URL: https://blog.ninprd.com/blog/summary-session-design-for-better-digital-government-services/ - Published: 2024-09-12 - Tags: meetup, meetup-2024, Y2024, uxth, scbx-next-tech, summary - Summary: สรุป Session: Design for better Digital Government Services ในงาน SCBX Unleashing CX: EP2 Designing for Maximum Impact and Scale ซึ่งเป็น Session ของพี่ณัฏฐ์ เพ็ญชาติ Community Founder ของ Thai Gov Design ครับ พี่ณัฏฐ์พูดถึงงานอดิเรกที่ชอบถ่ายรูปครับ ซึ่งเวลาถ่ายรูปเราจะมีเลนส์ระยะกว้าง ระยะกลาง ระยะไกล ซึ่งเมื่อเราใช้เลนส์คนละระยะ เราก็จะเห็นเรื่องราวที่ไม่เหมือนกัน ปกติเวลาเราดีลงานราชการเราก็จะเห็นแต่ Spec กับ TOR เหมือนได้เห็นภาพจากเลนส์มุมกว้างเลย แต่พี่ณัฏฐ์อยากมาชวนทุกคนดูภาพจากเลนส์ซูมบ้าง สรุป Session - Design for better Digital Government Services ในงาน SCBX Unleashing CX: EP2 Designing for Maximum Impact and Scale ซึ่งเป็น Session ของพี่ณัฏฐ์ เพ็ญชาติ Community Founder ของ Thai Gov Design ครับ พี่ณัฏฐ์พูดถึงงานอดิเรกที่ชอบถ่ายรูปครับ ซึ่งเวลาถ่ายรูปเราจะมีเลนส์ระยะกว้าง ระยะกลาง ระยะไกล ซึ่งเมื่อเราใช้เลนส์คนละระยะ เราก็จะเห็นเรื่องราวที่ไม่เหมือนกัน ปกติเวลาเราดีลงานราชการเราก็จะเห็นแต่ Spec กับ TOR เหมือนได้เห็นภาพจากเลนส์มุมกว้างเลย แต่พี่ณัฏฐ์อยากมาชวนทุกคนดูภาพจากเลนส์ซูมบ้าง **✨ Chatbot หมอพร้อม** ตอนช่วงโควิด Thai Gov Design ได้รับโจทย์เกี่ยวกับ Chatbot หมอพร้อมเพื่อคัดแยกผู้ป่วยฉุกเฉินที่ต้องกักตัว ซึ่งช่วงแรกที่ปล่อยไป Feedback ไม่เป็นไปตามที่คิด เพราะว่าผู้ป่วย 98% เป็นผู้ป่วยไม่ฉุกเฉิน ส่วนผู้ป่วยฉุกเฉินมีแค่ 2% เท่านั้น แต่ผู้ป่วยส่วนใหญ่ก็คิดว่าตัวเองไม่รู้ว่าตัวเองอยู่ในสถานะฉุกเฉินไหม ซึ่งถ้ามองแค่ภาพกว้าง เราก็จะมองไม่ออกว่าทำไมคนถึงรู้สึกกระวนกระวาย แต่ถ้าลองซูมลงภาพแคบ จะเห็น Message ของ Chatbot ที่บอกแค่สิ่งที่ต้องทำ แต่ไม่ได้บอกสถานะของตัวผู้ป่วยและไม่ได้บอกสถานะของส่วนรวมว่าตอนนี้เป็นยังไง ซึ่งแค่ปรับข้อความให้ตอบทุกอย่าง ตัว Chatbot นี้ก็สามารถตอบโจทย์ของการคัดแยกผู้ป่วยได้ **✨ DDC-Care** ตอนช่วงโควิด Thai Gov Design ก็ได้รับอีกโจทย์นึงก็คือการดูแลอีก Product นึงซึ่งชื่อว่า DDC-Care ซึ่งในตอนแรกก็ได้รับโจทย์แบบกว้าง ๆ มา ว่าเป็นแอปพลิเคชันที่ช่วยในเรื่องของการคัดกรองและทำ Isolation เพื่อที่จะเจาะลึกปัญหา ทีมน่าจะต้องซูมไปที่กลุ่ม ๆ นึงก่อน ซึ่งกลุ่มแรกที่เลือกจะซูมคือนักท่องเที่ยวที่เข้ามาในประเทศ ซึ่งเมื่อซูมไปก็พบว่ามีปัญหาว่าตอนที่ถามว่าจะกักตัวที่ไหน ระบบมีการขอ Location ซึ่งก็เลยกลายเป็นทุกคนเลือกสนามบินเป็นที่กักตัว พี่ณัฏฐ์จึงเริ่มทำ Service Design เพื่อปรับปรุง Process ของกระบวนการใช้แบบ DDC-Care ที่สนามบิน ปัญหาเกิดจากการที่เราพยายามยัดคนเยอะเกินไปใน 1 ภาพ ซึ่งถ้าเราซูมลงไป เราจะเห็นรายละเอียดมากขึ้น **✨ ระบบจ่ายภาษี** พี่ณัฏฐ์บอกว่าล่าสุดได้เข้าไปที่มูลนิธิคนตาบอดมาและค้นพบกับความจริงที่ว่าเขาสามารถเล่น Facebook, Twitter, Tiktok หรือที่น่าตกใจคือเขาสามารถเทรดหุ้นได้ (อันนี้นิลว้าวมาก) แต่สิ่งที่คนกลุ่มนี้ทำไม่ได้คือ เขาจ่ายภาษีไม่สำเร็จ ซึ่งก็ต้องลงไปซูมดูว่าทำไม พี่ณัฏฐ์บอกว่าคนตาบอดจะต่างจากคนตาปกติอย่างนึง คือถ้าเจออะไรที่ไม่ชัวร์ เขาจะไม่กดเพราะกลัวพลาด ซึ่งมันก็ดันมีปุ่มรูป Question Mark ปุ่มนึงที่เจ้า Screen Reader ของคนตาบอดไปอ่านโดนแล้ว เป็นคำว่า “ปุ่ม” ทำให้หลาย ๆ คนไม่กล้าจะไปต่อในขั้นตอนต่อไป อีกจุดนึงที่เป็นไปได้คือเส้นกันหน้าจอที่เป็นแค่จุดตกแต่ง ซึ่งสำหรับคนทั่วไป มันก็เป็นแค่เส้นแบ่งคั่น แต่สำหรับคนตาบอด ตัว Screen Reader จะอ่านเป็นคำว่า “เส้นแบ่งหน้าจอ” ทำให้หลาย ๆ คนไม่ได้ไปต่อเพราะคิดว่าตัว Form จบแล้ว **✨ Traffy Fondue** Traffy Fondue ก็เป็นอีกโจทย์นึงที่ได้รับมาว่า ทำยังไงถึงจะลดระยะห่างระหว่างประชาชนกับเจ้าหน้าที่กทม. โดยมี Time Frame สำหรับการ Research 1 เดือน ซึ่งระหว่าง Research ก็เจอกับหลายปัญหาเลยไม่ว่าจะเป็น 1. อ่านเมนูใน LINE ไม่เข้าใจ 2. Logo ใน LINE ของ Traffy Fondue ดูไม่น่าเชื่อถือ ดูไม่ Relate กับกทม. 3. คนไทยเป็นคนขี้เกรงใจ ส่วนใหญ่ขาด Motivation ในการ Report 4. แม่ค้าหาบเร่ไม่มีข้อมูลที่ถูกต้อง บางทีได้รับข้อมูลจากหลาย Source of Truth ไม่รู้ว่าข้อมูลไหนถูกผิด และไม่รู้ว่าตัวเองทำอะไรผิด ซึ่งจากปัญหาพวกนี้ก็ได้ผ่านกระบวนการ Design Thinking โดยมีการปรับปรุงไม่ว่าจะเป็นเมนูใน LINE ที่บอกอย่างชัดเจนมากขึ้นและเพิ่มขนาดเมนูที่ใช้บ่อย รวมทั้งมีการแจ้งกลับไปหาคนที่แจ้งปัญหาผ่าน Traffy Fondue มาเพื่อสื่อสารกลับไปหาประชาชนอีกครั้ง รวมทั้งมีการแจ้งแม่ค้าหาบเร่ว่าเขาทำอะไรผิด เขาจะได้สามารถทำมาหากินอย่างถูกต้องได้ **✨ สรุป** สรุปแล้วเวลาเราทำงาน โจทย์ที่เราได้รับมาจะมาแบบกว้างมาก ๆ อยากให้ลองเปลี่ยนการทำงานมุมกว้างเป็นการซูมปัญหาดู อย่างไรก็ดี ไม่ว่ายังไงก็ต้องมองภาพมุมกว้าง แต่บางทีต้องลองเปลี่ยนเลนส์เพื่อเจาะหาปัญหา **✨ แถม** พี่ณัฏฐ์มาแชร์ว่า Thai Gov Design กำลังจะมีการเปิดรับสมัคร Design Challenge ครั้งที่ 4 ในปลายปีนี้ครับ ซึ่งใครสนใจสามารถเข้ากลุ่ม [Thai Gov Design](https://www.facebook.com/groups/thaigovdesign/) เพื่อรอติดตามได้ครับ --- # สรุป Session - เกมมิฟิเคชัน: ศิลปะแห่งการสร้างแรงจูงใจผ่านกลไกเกม - URL: https://blog.ninprd.com/blog/gamification-conference-gamification-unviel-by-growth-game/ - Published: 2024-09-08 - Tags: conference, Y2024, ux, gamification, growth-game - Summary: สรุป Session เกมมิฟิเคชัน: ศิลปะแห่งการสร้างแรงจูงใจผ่านกลไกเกม ในงาน Game Changer ที่จัดโดย Gang Connector ซึ่งเป็น Session ของพี่ตรัง สุวรรณศิลป์ แห่ง Growth Game ครับ > เราสามารถจูงใจพฤติกรรมที่พึงประสงค์ด้วยกลไกเกม สรุป Session เกมมิฟิเคชัน: ศิลปะแห่งการสร้างแรงจูงใจผ่านกลไกเกม ในงาน Game Changer ที่จัดโดย [Gang Connector](https://www.facebook.com/Gangconnecter) ซึ่งเป็น Session ของพี่ตรัง สุวรรณศิลป์ แห่ง [Growth Game](https://www.facebook.com/GrowthGameIdea) ครับ ## 🌟 มนุษย์เป็นสัตว์ประเภทเดียวที่เล่นเกม เชื่อหรือไม่ว่ามนุษย์เป็นสัตว์ประเภทเดียวที่เล่นเกมและเกมไม่เคยบังคับให้ใครเล่น แต่จูงใจให้รู้สึกน่าทำต่อ ดังนั้นเราจึงสามารถ apply concept ของ Gamification ซึ่งคือการ**ใช้องค์ประกอบของเกม**และ**เทคนิคการออกแบบเกม**มาใช้ใน**บริบทที่ไม่ใช่เกม**เพื่อจูงใจให้เกิดพฤติกรรมที่เราอยากให้เกิดด้วยกลไกเกมกับมนุษย์ได้ อย่างไรก็ดี Gamification จะไม่ช่วยเลย ถ้า Content เรายังไม่ดีพอ ## 🌟 การสร้าง Engagement Loop Engagement Loop คือ Experience ที่จะทำ Motivate User ให้ทำ Action ต่อไปเรื่อย ๆ ได้ โดยองค์ประกอบของ Engagement Loop ประกอบไปด้วย Action, Feedback, และ Motivation ![engagement-loop-picture](assets/engagement-loop-picture.webp) ### 🏃 Action พี่ตรังบอกว่าคนมีหลาย Traits มาก ไม่ว่าจะเป็นคนที่ชอบสำรวจ ชอบการแข่งขัน ชอบสร้างสรรค์ หรือชอบร่วมมือ ซึ่งแต่ละ Traits ก็จะมี Action ที่แตกต่างกันออกไป #### 🎯 Gamification สำหรับ Action - Challenge, Quest & Missions - Boss Fight - Side Quest - Protector Quest - Special Event ### 📢 Feedback Feedback นี่เป็นตัวอย่างที่มีเยอะมาก เพราะ Key หลักของ Gamification คือการ Feedback (ตัวหลัก ๆ นิลจะติด ✨ ไว้นะครับ) #### 🎯 Gamification สำหรับ Feedback ##### แต้ม (Point) ✨ แต้มเป็นสิ่งที่เอาไว้ดู Progress และเป็น**การเปลี่ยนพฤติกรรมให้เป็นรูปแบบที่จับต้องได้** เช่น XP ในเกมหรือดาวใน Angry Bird อีกตัวอย่างนึงที่น่าสนใจคือฉลากประหยัดไฟเบอร์ 5 ซึ่งมี 5 ดาว ทำให้คนเลือกใช้เครื่องใช้ไฟฟ้าเบอร์ 5 และจูงใจให้ผู้ผลิตสร้างเครื่องใช้ไฟฟ้าแบบเบอร์ 5 ขึ้นมา ##### เหรียญตรา (Badge) ✨ เหรียญตราเป็นสิ่งที่**เปลี่ยน Achievement ให้เป็นสิ่งที่จับต้องได้** และช่วยให้คนรู้สึกดีเมื่อกลับมาเห็นได้ เช่น การให้ Badge เมื่อบริจาคเลือด การให้ Certificate เมื่อจบหลักสูตร หรือการทำกระดานความประพฤติ ##### ตารางอันดับ (Leaderboard) ✨ ใช้เพื่อบอกว่าตัวเองอยู่อันดับไหน เทีบกับคนอื่น ๆ ซึ่ง**เป้าหมายคือการสร้างการแข่งขัน** ##### Level ใช้บอกระดับความสามารถ และใช้ในกรณีที่มีการเลื่อนระดับหรือเลื่อนขั้น ##### Progress Bar ใช้บอกว่าตัวเราทำถึงตรงไหนของ Task นี้แล้ว เพราะคนจะชอบดูว่าเราทำอะไรยังไม่เสร็จ ##### Rewards - Fixed Rewards: คงที่ คาดเดาได้ เช่น เงินเดือน - Variable Rewards: ไม่คงที่ สร้างสีสัน เช่น มีเงินแปะอยู่ใต้โต๊ะ ให้ลองคลำใต้โต๊ะ - Proportional Rewards: ขึ้นกับคุณภาพหรือความคืบหน้า เพื่อสร้างประสิทธิภาพบางอย่าง เช่น การจ่ายโบนัส - Limited Rewards: เป็นรางวัลที่มีจำกัดเพื่อสร้างการเรียนรู้ เช่น Lottery, Collection, หรือ Easter Eggs ### 💪🏻 Motivation เป็นสิ่งที่หลาย ๆ คนลืมเวลาออกแบบเกมมิฟิเคชัน หลาย ๆ คนจะทำให้เกิดแค่ Action และ Feedback แต่ไม่มีการสร้าง Motivation ให้ ซึ่ง Motivation นั้นมี 2 แบบ นั่นคือ Extrinsic Motivation นั่นคือ Motivation ที่มาจากปัจจัยภายนอก ส่วน Intrinsic Motivation ซึ่งคือปัจจัยที่มาจากภายใน #### 🎯 Gamification สำหรับ Motivation - Story: สร้างเรื่องราวบางอย่างให้ User รู้สึกว่ามีเบื้องลึกเบื้องหลังอะไร - Surprise & Curiosity: สร้างเรื่อง Surprise บางอย่างเพื่อให้ User รู้สึกจดจำและรู้สึกว่าจะทำไปเรื่อย ๆ เพื่อเจอ Surprise - Torture Breaks: ทำให้ User ต้องหยุดอย่างทรมานเพื่อให้ User ทำบางอย่าง เช่น เกมที่มีหัวใจ 5 อันและเมื่อหัวใจหมดต้องเติมหัวใจ ## 🌟 หลักจิตวิทยาที่เกมมิฟิเคชันใช้ในการจูงใจ - **Scarcity:** คนจะอยากได้ของเพิ่ม เมื่อรู้สึกว่าของชิ้นนั้นหายากหรือมีจำกัด - **Loss Aversion:** คนจะมีแรงจูงใจเพิ่มขึ้นเพื่อหลีกเลี่ยงการสูญเสียมากกว่าการได้ผลประโยชน์ - **Zelgarnik Effect:** คนจะจำสิ่งที่ไม่เสร็จมากกว่างานที่เสร็จแล้ว ซึ่งสิ่งที่สามารถเอามาใช้กับ Zelgarnik Effect คือ Progress Bar และ Notification Count ## 🌟 หลักการคิดในการออกแบบ เวลาเราจะเริ่มในการคิดถึง Gamification ให้เริ่มที่ **Goal** ว่าอยากได้พฤติกรรมอะไร และให้ไปต่อที่ **Gap** ว่าเขายังไม่ทำพฤติกรรมนั้น ๆ เพราะอะไร แล้วจึงเอาไปออกแบบ **Gamification** เพื่อจูงใจพฤติกรรมนั้น ๆ ถ้าเวลาเราจะเอาไปนำเสนอกับทีมบริหารแล้ว เพื่อให้เขา Buy-in ให้นำเสนอในรูปแบบของ Goal และดูว่ามี KPI อะไรที่ตอบ Goal นั้น จากนั้นค่อยบอกว่าเราจะสร้างเสริม Behavior อะไรให้กับ User บ้าง ## 🌟 ปัจจัยที่ขัดขวางการ Action อย่าเพิ่งโทษ User เมื่อเขาไม่ทำอะไรบางอย่าง มันมีหลาย ๆ ปัจจัยที่ขัดขวางการทำ Action เช่น 1. ขาดแรงจูงใจ 2. ขาดความรู้/ความสามารถ 3. ขาดโอกาส ให้ Check ตลอดว่าเราต้องการ Gamification จริงไหม? Gamification เป็นแค่เครื่องมืออันนึงในการจูงใจพฤติกรรมเท่านั้น มีเส้นบาง ๆ ระหว่างการสร้างแรงจูงใจกับการชักใย เพื่อรักษาจริยธรรมของการใช้ Gamification ควรจะสร้างแรงจูงใจมากกว่าชักใยให้ใครทำอะไรบางอย่างให้เรา --- # สรุป UXTH Meetup: UX & Biometrics - URL: https://blog.ninprd.com/blog/uxth-meetup-ux-and-biometrics-summary/ - Published: 2024-08-24 - Tags: meetup, meetup-2024 - Summary: สวัสดีครับ วันนี้นิลได้มีโอกาสไปงาน UXTH Meetup ในหัวข้อ UX & Biometrics มาครับ ช่วงนี้นิลกำลังสนใจด้าน UX อยู่และเห็น Topic นี้ค่อนข้างฉีกจากหัวข้อ Traditional UX ไปพอสมควรเลย นิลเลยลองไปดูฮะ เนื้อหาจะเป็นยังไง ไปดูกันฮะ สวัสดีครับ วันนี้นิลได้มีโอกาสไปงาน UXTH Meetup ในหัวข้อ UX & Biometrics มาครับ ช่วงนี้นิลกำลังสนใจด้าน UX อยู่และเห็น Topic นี้ค่อนข้างฉีกจากหัวข้อ Traditional UX ไปพอสมควรเลย นิลเลยลองไปดูฮะ ซึ่งนิลมาเลทไปครึ่งชั่วโมงแหละ แหะ ๆ ช่วงแรก ๆ มันหายไปนิสนึง ขอโทษด้วยฮะ ตอนที่นิลมาก็เป็น Session ของพี่เปี๊ยก UX Research ที่ SCG ซะแล้ว ซึ่งจะเป็นยังไงเดี๋ยวไปดูกันเลยครับ ปกติแล้วในเชิง UX ปกติตาม Industry Standard เราจะสร้างของกันด้วยหลัก Lean UX ซึ่งก็คือ Build/Measure/Learn แต่กับที่ SCG แล้วจะเปลี่ยนเป็นแบบ Academic ซึ่งจะใช้เป็นหลัก No Measure/No Build ต้องมีการวัดค่าก่อน ถึงจะสร้างของออกมา ซึ่งปัจจัยที่ใช้วัดกันก็จะเป็น Satisfraction (ความพึงพอใจขอผู้ใช้งาน) Effectiveness (สร้างไปแล้วคนซื้อหรือไม่ซื้อ) Efficiency (User สามารถทำ Task ได้โดยที่ Cognitive Load น้อย ๆ ไหม) ซึ่งจากการวัดของเหล่านี้ เราจะทราบถึง Cognition (การรับรู้) Behavior (พฤติกรรม) และ Emotion (ความรู้สึก) ของผู้ใช้งาน ซึ่งตัว Behavior กับ Emotion จะทำให้เรารับรู้ Why ของ User ได้ เคสตัวอย่างแรกของการเอา Biometrics เข้ามาช่วยคือการออกแบบ Logo มา 6 อันและใช้ Software มาช่วย Analyze ว่า จาก Logo ทั้งหมดสามารถดึงดูดสายตาของผู้ใช้งานได้มากที่สุดเพื่อนำมาช่วยทีมตัดสินใจ นอกเหนือจากความชอบของปัจเจกบุุคคล เคสที่ 2 ก็จะเป็นการให้ User ลองทำ Task โดยที่เราเปิด Webcam และ Software ที่ใช้ในการตรวจจับการมองว่าแต่ละขั้นตอนของการ Test นั้น User มองไปที่จุดไหนบ้าง เคสที่ 3 จะเป็นการเอาแว่นตาที่ออกแบบมาสำหรับการทำ Eye Tracking มาใช้ร่วมกับเครื่องวัด EEG หรือเครื่องตรวจคลื่นไฟฟ้าในสมอง เพื่อมาดูว่าตาของ User ดูข้อมูลที่จุดไหนและ User มี Cognitive Load ในจุดไหนไหม เพื่อนำไปปรับปรุง UX ของ Product ซึ่งสมมติเราออกแบบมาให้แอปใช้งานง่าย ถ้า User จ้องจุดไหนเกิน 200 milliseconds และมี Cognitive Load สูงก็จะเข้าไปถาม User เพิ่มในจุดนั้น ๆ เคสที่ 4 คือการใช้ Web App ที่เป็น Machine Learning ในการจับการแสดงออกทางสีหน้า (Facial Expression) ดูว่าในช่วงที่ใช้งาน อารมณ์ของ User เป็นอย่างไร ซึ่งในการทำ Test ก็จะมีการส่ง Test ไป 2 ชุด ชุดแรกเป็นชุดที่ทำให้ User นิ่ง ๆ เพื่อเป็น Baseline สำหรับการดูว่า User คนนี้ Express อารมณ์อย่างไร พี่เปี๊ยกบอกว่ามีงานวิจัยที่ว่าคนจากตะวันตกจะแสดง Facial Expression ได้ดีกว่าคนเอเชียด้วยครับ พี่เปี๊ยกบอกว่าในการทำ Business Ideas Experiment เนี่ย มี Methodology มากมายเลย และมีการ Experiments อยู่ 2 แบบนั่นคือ **Discovery Experiments** ซึ่งเป็น Experiment ที่ใช้ในช่วงแรก ๆ ของ Process ทั้งหมด เพื่อใช้ตอบคำถามปลายเปิดครับ เช่นการทำ Card Storing, Paper Prototype หรือ การทำ User Interview กับอีกแบบนั่นคือการทำ **Validation Experiments** ซึ่งเป็นการทำ Experiment เพื่อตอบคำถามปลายปิดบางอย่าง เช่น ถ้าเปลี่ยนปุ่มเป็นสีฟ้าแล้ว User จะ Click เพิ่มขึ้น 10% ใช่ไหม (A/B Testing) หรือการทำ Clickable Prototype ให้ User ลองเล่น เพื่อ Validate ว่าสิ่งที่เราสัมภาษณ์ User และออกแบบตามสิ่งที่เราสัมภาษณ์มาแล้ว User มีประสบการณ์การใช้งานที่ดีขึ้นไหม ซึ่งการใช้ Biometrics นั้นสามารถนำมาใช้ได้ทั้ง 2 Experiments เลย ขึ้นกับว่าจะใช้ในเป้าหมายไหน หลังจากจบงานก็ได้มีโอกาสคุยกับพี่เปี๊ยกเพิ่มเรื่องของ Biometrics และ Business ครับ เพราะนิลแอบสนใจเรื่องนี้อยู่ พี่เปี๊ยกก็บอกว่าจริง ๆ ชาว Engineer เนี่ยจะมีความอยากสร้างของขึ้นมา แบบ อยากเอาโค้ดขึ้น Git ว่ะ แบบเท่ ๆ แต่ไม่สามารถตอบว่าสร้างของมาทำไมได้ 55555555 นอกจากนี้ทาง Business จะมีการทำ Business Model Canvas มาเป็นตัวช่วยและทำให้เราสามารถระบุความเสี่ยงทั้งหมดที่อาจจะเกิดขึ้นในเชิง User, Business, และ Technical Feasibility ซึ่งความเสี่ยงส่วนที่จะรีบไป Validate ก่อนคือความเสี่ยงฝั่ง Business และ User ก่อน เพราะถ้าเรายังลดความเสี่ยง 2 เรื่องนี้ไม่ได้ก็ไม่ต้องไป Implement ต่อหรอก ตามหลัก No Measure/No Build จากการ List ความเสี่ยงต่าง ๆ ที่เกิดขึ้น พี่เปี๊ยกและทีมก็จะไป Measure เพื่อลดความเสี่ยงที่จะสร้างของมาและไม่มีคนใช้ หรือสร้างของมาแล้ว User ใช้ไม่เป็นให้มากที่สุด แต่ทั้งนี้ทั้งนั้น ถ้าฝั่ง Management เคาะมาว่าเราจะสร้างสิ่งนี้แบบที่รู้ความเสี่ยงแล้ว = รับผิดชอบร่วมกัน 55555555 ก่อนจะแยกย้ายพี่เปี๊ยกก็โยน Keyword ให้ไปศึกษาต่อด้วยครับ ซึ่งถ้าใครสนใจ Deep Dive ต่อก็แนะนำ Keyword “Neuromarketing” กับ”Consumer Neuroscience” เลยครับ และถ้าอยากหา Pocket Book เกี่ยวกับเรื่องนี้อ่านไว ๆ สามารถไปดูกันได้ที่ [https://imotions.com/](https://imotions.com/) และถ้าสนใจในขาของ Business Experiments ก็แนะนำหนังสือ Testing Business Ideas ของ David Bland กับ Alexander Osterwalder ด้วยครับ จบไปแล้ว นิลคิดว่านิลจะสรุปรู้เรื่องนะ วันนี้ลองสรุปแบบพี่ ๆ ที่บ.บ้าง แต่นิลยังช้ากว่าพี่ ๆ มากเลย จะค่อย ๆ ปรับปรุง Skill การสรุปตัวเองไปเรื่อย ๆ ครับ ถ้าใครสนใจงาน Meetup แบบนี้สามารถติดตามได้ที่เพจ [UX Thailand](https://www.facebook.com/UXThailand) ได้เลยคร้าบบ --- # แชร์ประสบการณ์และรีวิว UX/UI Bootcamp (UXB) รุ่นที่ 7 ของ Skooldio - URL: https://blog.ninprd.com/blog/skooldio-ux-ui-bootcamp-7-review/ - Published: 2024-08-15 - Tags: UXB, uxb-by-skooldio - Summary: สวัสดีครับ วันนี้นิลมาเล่าสิ่งที่เรียกได้ว่าเป็นก้าวใหญ่อันนึงของนิลมาก คือช่วงพฤษภา – กรกฎาที่ผ่านมา นิลได้มีโอกาสไปเรียน UX/UI Bootcamp ของ Skooldio มาครับ ซึ่งถ้าคนที่อ่านมาซักพักก็จะเห็นอยู่แล้วว่านิลทำงานเป็น Software Engineer ที่ Skooldio Tech อยู่แล้วนะครับ อันนี้ก็เหมือนเป็นสวัสดิการอย่างนึงของพนักงานที่สามารถเรียน Bootcamp ได้ฟรีครับ (แอบขายบริษัทนิดนึงครับ 55555) ซึ่งนิลได้ตั้ง Expectation ของการเรียน UX/UI Bootcamp (ขออนุญาตเรียกสั้น ๆ ว่า UXB) ของนิลในครั้งนี้ไว้แบบนี้ครับ สวัสดีครับ วันนี้นิลมาเล่าสิ่งที่เรียกได้ว่าเป็นก้าวใหญ่อันนึงของนิลมาก คือช่วงพฤษภาถึงกรกฎาที่ผ่านมา นิลได้มีโอกาสไปเรียน [UX/UI Bootcamp ของ Skooldio](https://landing.skooldio.com/ux-ui-bootcamp?utm_source=ninprd&utm_medium=organic) มาครับ ซึ่งถ้าคนที่อ่านมาซักพักก็จะเห็นอยู่แล้วว่านิลทำงานเป็น Software Engineer ที่ Skooldio Tech อยู่แล้วนะครับ อันนี้ก็เหมือนเป็นสวัสดิการอย่างนึงของพนักงานที่สามารถเรียน Bootcamp ได้ฟรีครับ (แอบขายบริษัทนิดนึงครับ 55555) ซึ่งนิลได้ตั้ง Expectation ของการเรียน UX/UI Bootcamp (ขออนุญาตเรียกสั้น ๆ ว่า UXB) ของนิลในครั้งนี้ไว้แบบนี้ครับ - อยากเข้าใจ Design Process ทั้งหมด คือเรียนทฤษฎีแล้วไม่ได้ลงมือทำจริงมันแอบหลงทางนิดนึง - อยากเข้าใจว่าตอนที่ Dev ได้ Design มา มันแอบเอ้ะว่าแบบ ทำไมของชิ้นนี้ถึงมาแบบนี้นะ - อยากสามารถจบงาน (Design Process -> Dev Process -> Deliver งาน) ด้วยตัวคนเดียว หรือสามารถ Interchange Role ตัวเอง (Dev, Design) เพื่อส่งมอบงานได้ - อยากเรียนสดกับพี่แบงค์ (อันนี้สำคัญมาก 55555555) เอฟซีพี่แบงค์ครับ เอาล่ะ นิลเล่า Expectation ของตัวเองไปแล้ว ก่อนจะไปต่อขอปูพื้นฐานกันนิดนึงก่อนดีกว่าฮะ ## Bootcamp คืออะไรนะ? Bootcamp คือหลักสูตรการเรียนรู้แบบเข้มข้นและเน้นการปฏิบัติจริง ซึ่งจะมีจุดมุ่งหมายคือการพาทุกคนพัฒนา Skill เฉพาะด้านนั้น ๆ หรือสำหรับสายงานนั้น ๆ โดยส่วนใหญ่แล้วจะหลักสูตรแบบ 3-6 สัปดาห์แหละครับ ยกตัวอย่าง เช่น UX/UI Bootcamp เพื่อพาทุกคน Upskill UX/UI เพื่อย้ายสายงานเป็น UX/UI Designer หรือ Web Development Bootcamp ที่มีเพื่อพาทุกคน Upskill สู่สายงาน Web Developer ครับ ## รูปแบบการเรียนเป็นยังไงบ้าง? ในรุ่นที่นิลเรียนเป็นการเรียนแบบ Hybrid ครับ คือเรียน Offline วันเสาร์ 9:00 – 18:00 กับเรียน Online วันพุธช่วง 19:00 – 21:30 และก็เรียนประมาณ 6 อาทิตย์ครับ เรียกได้ว่าเรียนฉ่ำมาก นอกจากเรียนแล้วก็ยังมี Group Project ที่จะช่วยให้เราเข้าใจการทำงานเป็นทีมในฝั่ง UX มากขึ้น รวมทั้งมี Project เดี่ยวด้วย ซึ่งเดี๋ยวนิลจะแชร์ Key Takeaway แบบคลาสต่อคลาสเลยว่าแต่ละคลาสได้เรียนอะไรบ้าง ถ้าพร้อมแล้วก็ ไปลุยกันเล้ย ## Week 1: Empathize User & Business วีคนี้เราจะได้เรียนเกี่ยวกับการ Empathize ผู้ใช้งานและ Stakeholders ผ่าน Lecture และ In-Class Activity กับพี่คุปปี้ครับ โดย Key หลัก ๆ มีประมาณนี้ครับ - เวลาได้รับโจทย์มา อย่ารีบทำตามทันที ต้อง Fact Check ว่ามีปัญหานั้นอยู่จริงไหม - ถ้าปัญหานั้นมีอยู่จริง ก็เข้าไปสู่ Design Process ต่อ ถ้าไม่มีอยู่จริงก็ต้องไป User Research หาความจริงกันต่อ - อยากรู้ข้อมูลแบบไหน ค่อยเลือกเครื่องมือ Research เครื่องมือ Research มีหลายตัวมาก [สามารถไปอ่านสรุป Research Methods ทั้งหมดของ nngroup ได้ที่นี่ครับ](https://www.nngroup.com/articles/research-methods-glossary/?lm=ux-research-cheat-sheet&pt=article) - เวลาทำ User Interview พยายามทำถามคำถามปลายเปิด -> ได้ Insight -> Insight จะสะท้อนออกมาในงาน Design ไม่มากก็น้อย - วางแผน Interview ด้วยการตั้งเป้าหมายการเรียนรู้ คิดคำถามจากเป้าหมายนั้น ๆ และนำคำถามมาเรียงจากห่างจาก Product ที่สุด ไปใกล้ Product ที่สุด - จะ Interview ให้ดี ต้องฝึกฝน ทำบ่อย ๆ - เจอ Stakeholder ให้เช็คว่าเรายัง Align กันไหม Stakeholder ยังเชื่อเราไหม เขามี Personal Goal ยังไง - นอกจากจะเข้าใจ User แล้ว ยังต้องเข้าใจ Business ด้วย เพราะเขาเป็นคนที่กำเงินและมีความฝันอยากสร้าง Product - ควรใช้ [Stakeholder Mapping](https://www.nngroup.com/articles/stakeholder-analysis/) เป็น Tools เพื่อเข้าใจว่าเราต้องบริหารการเข้าหาคนแต่ละคนที่ทำงานด้วยอย่างไร Key หลักที่ได้จาก Week นี้คือ: > ทำ User Interview เพื่อลดความเสี่ยงให้กับ Business ![Classes of Week 1](assets/uxui-bootcamp-week-1-2.webp) ![Classes of Week 1](assets/uxui-bootcamp-week-1-3.jpg) ## Week 2: Problems to Solutions วีคนี้เราจะได้เรียนและทำเวิร์คช็อปแบบตะโกนกับพี่คามิน ซึ่งจะเป็นการเอา User Insights จาก Interview ที่เราทำมาเมื่อวีคที่แล้ว มา Define ปัญหาที่เราจะแก้ผ่าน Tools หรือ Frameworks ต่าง ๆ จนได้ Solution คร่าว ๆ แหละ โดย Key หลัก ๆ มีประมาณนี้ - การจะเข้าใจปัญหาให้มากขึ้น ต้องกลับไปดูให้ลึกขึ้นใน Research Notes ว่าพูดเรื่องนั้นซ้ำ ๆ มีหลักฐานบ่งชี้ หรือได้รับบริบทบางอย่างจากการสัมภาษณ์มาไหม - เราใช้ Affinity Mapping เพื่อจัดกลุ่ม Users และตีความคำพูดที่ Users แต่ละกลุ่มพูดออกมา เพื่อเข้าใจในภาพกว้างของกลุ่ม Users ของเรา - แตก Affinity Mapping เป็นข้อมูล Insights ผ่าน Framework/Tools อื่น ๆ เพื่อทำให้เราเห็นรายละเอียดของ Users มากยิ่งขึ้น - ใช้ Persona เพื่อ Represent กลุ่ม Users ที่เราไปทำการสัมภาษณ์มา - ใช้ A Day In Life หรือ User Journey เพื่อให้เห็นภาพในแกนเวลาว่า Users กลุ่มนั้น ๆ ใช้ชีวิตยังไง มี Opportunity ในช่วงเวลาไหนที่จะทำให้ชีวิตเขาง่ายขึ้นหรือแก้ปัญหาอะไรได้ในจุดนั้น ๆ หรือเปล่า - ใช้ How Might We (HMW) เพื่อสร้าง Problem Statements ที่มาจาก User Insight ของเรา เช่น ตั้งคำถามว่า _“ทำยังไงถึงจะช่วยให้คนตัวสูงสามารถนั่งเก้าอี้ออฟฟิศนาน ๆ แล้วไม่ปวดหลัง”_ - เอาข้อมูลจาก HMW มาเรียงด้วย Prioritization Matrix เพื่อให้เห็น Landscape ของปัญหาทั้งหมดว่าปัญหาไหนที่ควรสนใจ - การทำ UX Process ไม่ใช่ Waterfall Process เป็นสิ่งที่เราต้อง Iterate ไปเรื่อย ๆ และคอยย้ำกับตัวเองถึงสิ่งที่ตัวเองรู้และไม่รู้เกี่ยวกับ Users - เราควรทำ Presentation Script เพื่อนำเสนอข้อมูลที่เราได้มาจากการไปศึกษา Users ผ่านเครื่องมือต่าง ๆ เพื่อให้คนอื่น ๆ ในทีม ไม่ว่าจะเป็นฝั่งผู้บริหาร Business หรือ Team Dev เข้าใจภาพเดียวกัน Key หลักที่ได้จาก Week นี้คือ: > การทำ UX Process ไม่ใช่เส้นตรง เราต้องตระหนักรู้ว่าตอนนี้เราอยู่ตรงไหน และคอยย้ำกับตัวเองตลอดว่าเรารู้หรือไม่รู้อะไรเกี่ยวกับ Users ![Classes of Week 2](assets/uxui-bootcamp-week-2-1.webp) ## Week 3: UI Interaction Design เอาล่ะ วีคนี้โคตรมันส์ Instructor คือพี่แบงค์แห่ง UX Academy ครับ ซึ่งในวีคนี้พี่แบงค์ก็จะมาสอนหลักการต่าง ๆ ของการทำ UI และการทำ UI Interaction Design ครับ วีคนี้ In-Class Activity เยอะมากกก ได้ใช้ Figma ฉ่ำมาก Key หลัก ๆ ของ Week 3 มีประมาณนี้ครับ - การทำ Job to be done เพื่อช่วย User ก้าวผ่าน Struggle Moment - เวลาทำ Journey เริ่มทำเป็น Text และเริ่มทำที่ Start Stop แล้วค่อยมา Connect Flow ตรงกลาง ถ้าไม่พอใจ Flow ตรงไหนให้แก้ในรูปแบบของ Text เมื่อพึงพอใจแล้วค่อยวาด Wireframe ออกมา - ยิ่งเราขยับ Wireframe เร็วเท่าไหร่ ยิ่งราคาถูก - 4 Tips for Prototyping - General to Detail: ข้อมูลควรจะไล่จากกว้าง ๆ จนละเอียด เหมือนพวก Mailbox ที่ฝั่งซ้ายสุดเป็น Email Folder (General) ตรงกลางเป็นรายการ Email ใน Folder นั้น (เจาะจงเข้ามา) และฝั่งขวาก็จะเป็นเนื้อความและรายละเอียดของ Email นั้น ๆ (ละเอียดที่สุด) - Object not Action: เช่น หากเราต้องการออกแบบแอปช่วยเตือนกินยา ให้ออกแบบด้วยที่ในหน้าเป็นรายการยา ไม่ใช่ Action ต่าง ๆ เช่น กินยา แจ้งเตือนการกินยา - Basic Location: เวลาวางของใน UI ให้วางที่ที่มันควรจะอยู่ เช่น แถบเมนูหลักในแอปมือถือเป็นแถบอยู่ด้านล่าง อย่าเอาเมนูไปไว้ด้านซ้ายหรือด้านขวา - Real not Abstract: ข้อมูลที่มาใช้ Mock ใน Wireframe ไม่ควรเป็นแค่กล่องสี่เหลี่ยมและกากบาทหรือแค่แถบสีดำคาดตรงที่เป็นข้อความ แต่ควรเป็นรูปและข้อความที่ดูสมจริงขึ้นมา เพื่อให้คนมาดู Wireframe เห็นภาพมากขึ้น - เราสามารถเอา Gestalt’s Law มาช่วยในเรื่องการ Grouping ของเพื่อลดความซับซ้อนของ UI ได้ - การออกแบบ ไม่ใช่แค่คำนึงถึง User และ Business ยังต้องคำนึงถึง Platform ที่เราออกแบบ เช่น เรากำลังทำแอปบน iOS หรือ Android รวมถึงต้องคำนึงถึง Developer ด้วยว่าที่เราออกแบบไป ใช้เวลา Dev ทำยากแค่ไหน วีคนี้ได้ทำอะไรเยอะมากจริง ๆ พี่แบงค์สอนพวก Shortcut Figma ที่ใช้บ่อย ๆ ด้วย ดีมากเลยยย Key หลักที่ได้จากวีคนี้เยอะมาก แต่นิลชอบอันนึงมากคือ > เราเรียนหลักการต่าง ๆ เกี่ยวกับ UI เพื่อสร้างของที่ใช้งานง่ายและเอาไปคุยกับ Stakeholder ได้อย่างมีเหตุผล ![Classes of Week 3](assets/uxui-bootcamp-week-3-1.webp) ![Classes of Week 3](assets/uxui-bootcamp-week-3-2.webp) ## Week 4: Design Psychology วีคนี้ Instructor คือพี่ปุ้ม Head of UX Design ที่ Skooldio ครับ พี่ปุ้มจะมาเล่าเกี่ยวกับ UX/UI ในมุมของหลักการต่าง ๆ ทาง Psychology ครับ ซึ่งด้วยประสบการณ์และการยกตัวอย่าง Good และ Bad Examples ของพี่ปุ้มทำให้การเล่าเรื่อง Psychology นั้นฟังดูย่อยไม่ยากอย่างที่คิดไว้ครับ ในวีคนี้ Key หลัก ๆ มีประมาณนี้ครับ - การใช้หลักการทาง UX มาประกอบการออกแบบประสบการณ์การใช้งานนั้นจะไม่ได้สร้างการสวยแบบปัจเจกแต่จะสร้างความเอกภาพในเชิงความคิดเกี่ยวกับประสบการณ์การใช้งาน - เมื่อเวลาเราได้รับข้อมูลมาก ๆ ในแต่ละครั้ง เราจะเกิด Cognitive Load ซึ่ง Information ที่โดนยัด ๆ เข้ามา ส่วนใหญ่จะหายไป - Design Affordance คือการออกแบบของที่ทำให้ User ต้องคิดก่อนว่าจะใช้งานมันยังไง - การออกแบบ Digital Products ที่ดี นอกจากจะออกแบบให้ใช้งานง่ายแล้ว อีกแกนที่ควรคิดคือการลดการใช้ความคิดของ User - การใช้หลักการต่าง ๆ เพื่อออกแบบทั่วไป - Gestalt’s Law of Grouping + Closure/Continuity - Visual Hierarchy - 10 Usability Heuristics หรือ Mental Shortcuts - The Magic Number (7±2) - นอกจากหลักการที่พูดไปแล้ว หากเราไม่เข้าใจวิธีคิดของ User (Mental Model) เขาก็ยังจะไม่เข้าใจ Web/App ของเรา - วิธีที่ใช้เพื่อเข้าใจ Mental Model นั้น สามารถทำได้โดยการทำ Usability Testing, การทำ Information Architecture (IA) และการทำ Card Sorting - การวาด User Flow เพื่อให้เรารู้ว่าใน Web/App ของเรามี Flow อะไรบ้าง และให้เราเห็นจุดตัดสินใจใน Product ของเรา - ปกติ Flow แรกมักจะเป็น Flow ที่ User สามารถใช้งาน Product ของเราได้เลย แต่จริง ๆ มันจะมีพวก Unhappy Path, Empty State, Error State, Edge Cases ด้วยแหละ ต้องคิดเผื่อเรื่องพวกนี้ เพราะเป็นสิ่งที่ Developer จะมาถาม - สิ่งที่จะเป็น Indicator ว่า Hi-Fi ของคุณเรียบร้อยแล้ว คือเมื่อเอาไปให้ User ทดสอบแล้ว User พูดว่า “สิ่งนี้เหมือนของจริงมากเลยนะ มันยังกดไม่ได้อีกหรอ” วีคนี้เนื้อหาอัดแน่นมาก จบคลาส สมองไหล Cognitive Load TO THE MAX เลยยย นิลว่า Key หลักของวีคนี้คือ > นอกจากจะต้องออกแบบตามหลักการต่าง ๆ แล้ว เรายังต้องเข้าใจ Mental Model ของกลุ่มผู้ใช้งานของเรา เพื่อให้ Web/App ใช้งานง่ายและลดความต้องคิดของผู้ใช้งาน ![Classes of Week 4](assets/uxui-bootcamp-week-4-1.webp) ## Week 5: Design Systems ในวีคนี้ส่วนใหญ่จะเป็นงานปฏิบัติครับ วันนี้พี่แบงค์มาสอนในเรื่องต่าง ๆ ของการทำ Design System ตั้งแต่ Basic ยันไปถึงเรื่องของ Figma Variables ซึ่งเป็น Feature ใหม่ของ Figma เลยครับ ในวีคนี้ Key หลัก ๆ ที่ได้จะเป็นประมาณนี้ครับ - Auto Layout จริง ๆ แล้วหลักการจะเหมือนกับ Flex Box ที่ Developer ใช้เพื่อเขียนเว็บไซต์ - ถ้าเราลดความซับซ้อนของ Components แล้ว Dev จะไม่ต้องไปมโนวิธีการปั้น Components ใน Code เลย - การทำ Components ให้ไปในทิศทางเดียวกัน เช่น การใช้ Variant หรือการใช้ Swap Instance ควรจะใช้เหมือน ๆ กัน จะทำให้เราทำงานกับทีมง่ายขึ้น - ยังไม่ต้องรีบทำของให้เป็น Components มาก ให้ลองทำซัก 2-3 หน้าก่อน แล้วจะเริ่มเจอว่าของชิ้นนี้ซ้ำกันเยอะ ๆๆๆ และค่อยหยิบมาทำ Components - Design System มีหลักการในการขึ้นหลายแบบ สุดแท้แล้วแต่ละทีม แต่เราควรมี System เพราะเป้าหมายของการทำ System คือการทำให้ทีมหาของเจอง่าย - ช่วงแรก ๆ เวลาเราทำ Design ให้มาด้วยแนวคิดที่ว่า “เดี๋ยวของเราก็โดนรื้อ” - ควรใช้ Figma Shortcuts เยอะ ๆ เพื่อลดการขยับข้อมือ (เพื่อลดอาการปวดข้อมือ) - การทำสี พวก 100 200 มีหลายท่ามาก ๆ ไม่ว่าจะเป็นการปรับ Opacity, การใช้ HSL, หรือการใช้มาตรฐานใหม่อย่าง OKLCH - เราสามารถใช้ Figma Variables เพื่อจัดการข้อมูลได้ทั้งสี การทำ Light Mode, Dark Mode และการออกแบบหลายภาษา (Internationalization; i18n) Week นี้หลัก ๆ จะปฏิบัติเยอะมากกและเหนื่อยมากกกกกกกกก แต่ที่ชอบคือการมาด้วยแนวคิดที่ว่าเดี๋ยวของก็โดนรื้อครับ อย่ารีบใส่แรงในช่วงแรก ๆ ของการ Design ครับ ![Classes of Week 5](assets/uxui-bootcamp-week-5-1.webp) ## Week 6: Lean UX ในวีคนี้ได้เรียนกับพี่ชาญ Lead Design Consultant ที่ Thoughtworks ฮะ พี่ชาญมาเล่าว่าก่อนที่เราจะทำ Design Thinking ที่เป็น Double Diamond Space เนี่ย เราต้องเข้าใจเรื่องของ Vision ขององค์กรกับ Vision ของ Product และการวัดผลซึ่งเป็นขั้นตอนหลังจากทำ Design Thinking ฮะ ซึ่ง Key หลัก ๆ ของ Week นี้มีตามนี้ครับ - การตั้ง Vision Statement ที่ดี คือต้องสามารถสร้างเป้าหมายร่วมกัน ทำได้จริง และวัดผลได้ ซึ่งในทีมต้องเห็นเป้าหมายเดียวกัน และ Vision ต้องไม่ Lock เราจนเกินไปและต้องไม่ใส่ Requirement ของ Product เข้าไปใน Vision ด้วย - พอเราตั้ง Vision แล้ว เราก็จะมี Goal ที่ตอบรับ Vision นั้นและ Strategy ที่ตอบ Goal นั้น ๆ และจะลงไปถึง Initiatives ในการเริ่ม Strategy นั้น ๆ ขึ้นมา ซึ่ง Process ในการคิดของเหล่านี้ไม่ใช่เส้นตรง ค่อย ๆ Iterate ไปเรื่อย ๆ และเราควร Challenge Vision เราอยู่เสมอ ๆ - เมื่อเรามี Strategy แล้ว เราก็ต้องมีการวัดผลว่า Strategy นั้น ตอบ Goal แค่ไหน ซึ่งสามารถวัดด้วย Metric ต่าง ๆ - พี่ชาญแนะนำ Framework ตัวนึงที่ชื่อว่า Lean Value Tree ซึ่งช่วยจัดระเบียบความคิด แบ่งแยก Vision, Goal, Strategy และ Initiatives ออกจากกัน เพื่อให้เราเข้าใจและบรรลุจุดเป้าหมายต่าง ๆ ได้ ([สามารถอ่านเรื่อง LVT เพิ่มได้ที่นี่](https://www.thoughtworks.com/en-th/insights/blog/digital-transformation/how-to-brew-a-perfect-strategy-responsibly-part-one)) - Design Process ไม่ใช่ Perfect Double Diamond เราอาจจะต้องยืดบาง Part ออกซึ่งขึ้นกับโจทย์ที่เราได้รับว่าควรจะเน้นที่ Part ไหนของ Design Thinking (Empathy, Define, Ideate, Prototype & Test) - เราควรที่จะทำ UX แบบ Lean นั่นคือ ทำน้อย ล้มไว และพัฒนาอย่างมีจุดหมายและยั่งยืน - ใน Product Life Cycle นั้น เราอาจจะไม่ต้องทำ Product ก่อน แต่ให้เราไปเริ่มที่การ Discovery กับการทำ Proof Of Concept (POC) ก่อนว่ามีความสนใจในท้องตลาดแค่ไหน เมื่อ POC เสร็จและผลลัพธ์คือมีความสนใจเยอะ เราอาจจะลองทำ Minimum Viable Product (MVP) เพื่อนำไปลองตลาดจริงได้ - เวลาทีมเคลื่อนตัวไปนั้น ควรที่จะเคลื่อนตัวไปในทิศทางเดียวกันอย่างสมดุล ไม่งั้น Product จะไม่ขับเคลื่อนตาม - เมื่อ Product ถึงจุด Decline (อาจจะไม่มีผู้ใช้งาน หรือด้วยความที่ไม่มีเงินทุนมาทำต่อแล้ว) บริษัทอาจจะต้องหา New S-Curve หรือความเป็นไปได้ใหม่ ๆ เพื่อจะกลับมาแข่งขันในตลาดอีกครั้ง - การจะวัดผลของ Strategy ได้ เราต้องตั้งไม่ตั้ง Vanity Metrics (Metrics ที่ช่วยให้เรารู้สึกดี เช่น App มียอด Download 5 ล้านแต่จริง ๆ มี Monthly Active User แค่ 300) และต้องเป็น Actionable Metrics คือ Metrics ที่สามารถบอกได้ว่าเราจะพัฒนา Product เราต่อไปในทิศทางไหน จริง ๆ มีอีกเยอะมาก แต่นิลกลัวจะสปอยเยอะเกิน 555555 เอาเป็นว่าวีคนี้สิ่งที่นิลชอบคือนอกจากการเข้าใจศาสตร์ของการ Design แล้ว เรายังต้องเข้าใจในมุมขององค์กรและการวัดผลอีกด้วย เป็นสิ่งที่นิลรู้สึกว่าว้าวมากเลยเพราะว่าเป็นการสอนที่บอกเราว่า นอกจาก Stakeholder และ User แล้ว เรายังต้องดูแลทีมของเราและเราควรจะมาร่วมกันไปในทิศทางเดียวกันเพื่อพาทุก ๆ ฝ่ายไปถึงเป้าหมายเดียวกัน --- ## Group Project ระหว่าง 6 คลาสสุดตึงก็จะมีงานกลุ่มที่เราจะต้องไปทำในแต่ละอาทิตย์ครับ ซึ่งตอน Orientation เราจะได้โจทย์มาเพื่อไปทำ UX และ UI Process และนำมา Pitch กันในคลาสสุดท้ายครับ ซึ่งนิลสปอยโจทย์ไม่ได้แต่ว่ากลุ่มนิลได้โจทย์ที่หินมากฮะ ใครอยากรู้ว่านิลได้โจทย์อะไร [ดู Project “สุขี” ใน Landing Page ของ UXB ได้](https://landing.skooldio.com/ux-ui-bootcamp?utm_source=ninprd&utm_medium=organic) 5555555 ระหว่างทางเนี่ย เราก็ต้องไป Interview Stakeholder, Interview Users, ทำ UX Process ต่าง ๆ รวมทั้งได้ทำ UI Process ต่าง ๆ พวกการทำ Wireframe, High Fidelity Design, Design System, Prototyping เพื่อเอาไป Test กับ Users อีก รวมถึงได้ใช้ Figma Local Variables ในการลองทำแอปในรูปแบบ Dark Mode ด้วย (อันนี้เป็นโจทย์เสริมซึ่งทีมนิลก็สู้ด้วยไง ทำไปซะหมดเลย 555555) ซึ่งในระหว่างทางเราก็จะผ่านขั้นตอนเหล่านี้และผ่านการทำงานและตบตี (ถกกันเรื่องความคิดและไอเดีย) กับเพื่อนร่วมทีมจนสุดท้ายก็ผ่านพ้นไปด้วยดีครับ อย่างที่เขียนบอกไว้เลย ใน Project เราได้ทำอะไรเยอะมากและเราจะได้ทวนของเหล่านั้นในระหว่างการทำ Presentation ไปนำเสนอในคลาสสุดท้ายครับ นอกจากนั้น การได้ดูกลุ่มอื่น ๆ นำเสนอผลงานตัวเองก็ถือเป็นการได้ดูวิธีการทำงานและวิธีคิดของกลุ่มอื่น ๆ ด้วย เพื่อนร่วมรุ่นทุกกลุ่มคือสุดมากกก ถึงขนาดที่พี่แบงค์บอกว่ารุ่นนี้ใส่พลังกับ UXB เยอะมาก ปลาบปลื้มสุดด ภาพสรุปตอนจบนั้นคือการที่เราได้เข้าใจการทำงานในขาของ UX, UI และการทำงานเป็นทีมครับ ![Group project team winners with prizes](assets/uxui-bootcamp-ending-1.webp) ![Group project team winners with certificates](assets/uxui-bootcamp-ending-2.webp) หลังจากจบในส่วนที่เราไปนำเสนองานกลุ่มกันจบแล้ว ก็มี Session Wrap-Up Bootcamp ครับ พี่แบงค์ก็มาทวนให้อีกรอบว่าเราผ่านอะไรกันมาบ้างในระยะเวลา 3 เดือนที่ผ่านมา ซึ่งภาพคร่าว ๆ ก็เป็นประมาณนี้ครับ ![A slide to wrap up UXB 7 by Skooldio](assets/uxui-bootcamp-summary-1.webp) จากภาพนี้จะเห็นได้เลยว่า UXB นี่ค่อนข้างวางหลักสูตรมาให้เรียนไล่จากความเป็น UX มาทำ UI และเข้าใจการทำงานกับทีมมากขึ้นครับ หลังจากเรียนไปก็รับรู้ถึงความตั้งใจของ Program Director, Instructor, Facilitator และทีม Business Development ที่ร่วมกันสร้างบรรยากาศการเรียนรู้ให้กับคนเรียนทุกคนจริง ๆ (ขอบคุณทุกคนมา ณ ที่นี้คร้าบบ) จบงานก็มี Party Networking ครับ นั่งคุยกับ Instructor ทั้งพี่แบงค์ พี่ชาญ แล้วก็คุยกับเพื่อน ๆ ร่วมรุ่นครับ ทุกคนเหมือนรู้จักกันมานานมากกก นั่งคุยนั่งดริ้งค์กันแบบสุดมาก 555555 ตอนท้าย ๆ นิลก็ได้คุยกับหลาย ๆ คนที่นิลไม่เคยได้คุยใน Bootcamp เลยด้วย ละตอนจบนิลก็ได้ถ่ายรูปกับพี่แบงค์มาด้วย นี่ถือว่า Complete ชีวิตประมาณนึงละ 5555555555 ![ได้ถ่ายรูปกับพี่แบงค์ด้วย เย้ ๆ // นิลถือขวดน้ำทำไมนะ 555555](assets/uxui-bootcamp-nin-with-pbank.webp) เอาล่ะ เวลาเราตั้งเป้าอะไร เราต้องมา Review ว่าการที่เราทำสิ่งนั้นมันตอบเป้าที่เราตั้งไว้ไหม นิลจะเอา Expectation ของนิลต่อ UXB ลงมาไล่ดูนะครับว่าการเรียนในครั้งนี้มันตอบโจทย์นิลไหม ### อยากเข้าใจ Design Process ทั้งหมด คือเรียนทฤษฎีแล้วไม่ได้ลงมือทำจริงมันแอบหลงทางนิดนึง ✅ อันนี้ได้เข้าใจและลงมือทำจริงเลยครับ อาจจะไม่ได้เข้าใจแบบถ่องแท้ขนาดนั้น แต่นิลรู้สึกว่ามันดีมาก ๆ ที่เราได้เห็นภาพจริงทั้งหมดและเข้าใจว่าเราทำแต่ละ Process เพื่ออะไร รวมทั้งการที่ได้เข้าใจว่า Design Process ไม่ใช่เส้นตรงด้วย อันนี้ชอบมาก ในฐานะเด็ก IE คนนึงส่วนใหญ่จะชอบมองของให้เป็น Linear Process และทำต่อไปเรื่อย ๆ แต่พอมาเรียน UX ปุ๊ป รู้สึกฝืนธรรมชาติของตัวเองพอตัว แต่ก็ได้มุมมองใหม่ ๆ มาเยอะเลย ### อยากเข้าใจว่าตอนที่ Dev ได้ Design มา มันแอบเอ้ะว่าแบบ ทำไมของชิ้นนี้ถึงมาแบบนี้นะ ✅ นิลคิดว่าอันนี้นิลได้เข้าใจมากขึ้นครับว่าบางทีเวลาเราไป Interview User มาแล้ว หรือตอนที่ไป Interview Stakeholder ทำให้ Designers เห็น Insights บางอย่างที่ Dev ไม่เห็น และออกแบบของออกมาแบบนั้น ซึ่งสิ่งนี้ถ้า Designers สามารถอธิบาย Dev ได้นิลคิดว่าจะเป็นเรื่องที่ดีมาก ๆ ครับ ### อยากจบงานด้วยตัวคนเดียวได้ ✅ อันนี้นิลคิดว่าส่วนตัวนิลน่าจะทำไหวแล้วนะ 5555555 (ใครสนใจติดต่อจ้าง Design/Dev จ้างได้ครับ 🥺) แต่นิลมองอย่างงี้ครับ การที่เราจะพัฒนา Product อะไรแต่เราพัฒนาด้วยตัวคนเดียวเนี่ย สุดท้ายเราจะขาดมุมมองจากคนอื่น ๆ ซึ่งเวลาทำงานหลาย ๆ คนเราจะได้สิ่งนี้ครับ ทำให้นิลแอบคิดว่าสุดท้ายยังไงเราก็ควรจะทำงานเป็นทีมน่าจะเป็นตัวเลือกที่ดีกว่าครับ ### อยากเรียนสดกับพี่แบงค์ เอฟซีพี่แบงค์ครับ ✅✅ อันนี้ได้แบบเต็ม ๆ เลยครับ ได้ Wisdom จากพี่แบงค์มาตลอดเลย ขอบคุณพี่แบงค์ที่เป็นคนที่ทำให้นิลสนใจในเรื่องของ UX มากขึ้นครับ ก็ถือว่าการที่นิลใช้เวลามาเรียนประมาณเกือบ ๆ 3 เดือนในรอบนี้ตอบโจทย์ของนิลทุกข้อเลยครับ เหนื่อยแต่สนุกมากกกก ซึ่งนี่เป็นแค่ส่วนหนึ่งของคลาสทั้งหมดกับประสบการณ์ที่จะได้รับครับ ยังไงถ้าใครสนใจดูรายละเอียดเพิ่มเติม สามารถไปดู Course Syllabus รุ่นใหม่ ๆ ได้ที่ [หน้าเว็บของ UX/UI Bootcamp By Skooldio](https://landing.skooldio.com/ux-ui-bootcamp?utm_source=ninprd&utm_medium=organic) ได้เลยครับ ใครสนใจตัว Bootcamp นี้และอยากถามข้อมูลเพิ่มเติมจากนิลสามารถทักนิลมาทาง [LinkedIn: Peeranat Danaidusadeekul](https://www.linkedin.com/in/peeranatd/) ได้เลยนะครับ ขอให้ทุกคนสนุกกับการเรียนรู้และการ Upskill ครับ – นิล – --- # EventStorming ภาษากลางแห่งโลก Software - URL: https://blog.ninprd.com/blog/event-storming-ubiquitous-language/ - Published: 2024-08-11 - Tags: knowledge-sharing - Summary: วันนี้นิลมาใน Topic ที่นิลกลับมานั่งดู Session ต่าง ๆ อีกรอบ นั่นคือการทำ EventStorming ครับ ต้องเท้าความก่อนว่านิลได้ฟังพี่รูฟพูดถึงสิ่งนี้ที่ Session Ubiquitous Language ที่ UXTH Conference 2024 มาครับ และนิลก็รู้สึกว้าวมากและนิลก็ได้ฟังพี่รูฟพูดอีกครั้งจาก DevDay ของพี่ Siam Chamnankrit บน YouTube วันนี้นิลมาใน Topic ที่นิลกลับมานั่งดู Session ต่าง ๆ อีกรอบ นั่นคือการทำ EventStorming ครับ ต้องเท้าความก่อนว่านิลได้ฟังพี่รูฟพูดถึงสิ่งนี้ที่ [Session Ubiquitous Language ที่ UXTH Conference 2024](https://uxth.co/) มาครับ และนิลก็รู้สึกว้าวมากและนิลก็ได้ฟังพี่รูฟพูดอีกครั้งจาก [DevDay ของพี่ Siam Chamnankrit บน YouTube](https://www.youtube.com/watch?v=p7IqD83ljvc) (ฟังพี่รูฟแบบดับเบิ้ลเลย) วันนี้นิลเลยอยากเอามาเล่าในมุมที่นิลเข้าใจดูครับ มาลุยกัน ## ปัญหาของโลกการพัฒนา Software ปัจจุบันคืออะไร ในปัจจุบัน เวลาเรารับงาน Software มาอันนึง Product Manager ไปรับ Requirement จากลูกค้ามาก็จะแปลงเป็นภาษาของตัวเองเพื่อส่งต่อให้ Designer และ Designer ก็จะ Design สิ่งนี้ตามภาษาของตัวเองและส่งต่อไฟล์ Design ให้กับ Software Engineer (Dev) สุดท้าย Dev ก็จะแปล Design เป็นภาษาของตัวเองและออกแบบระบบรวมถึงเขียนโค้ดด้วยชื่อฟังก์ชันหรือตัวแปรที่ Dev ตั้งกันเอง ซึ่งหมายความว่าปัญหาที่เกิดขึ้นมันคือการที่แต่ละคนมีภาษาของตัวเองและต้องแปลภาษาของคนอื่นเป็นภาษาตัวเอง สมมติเวลา Dev คนเก่าลาออกไปแล้ว Dev คนใหม่มาดู มันก็อาจจะเกิดการสับสนในภาษาเพราะว่าภาษาที่ PM ใช้ ≠ ภาษาที่ Designer ใช้ และ ≠ ภาษาที่ Dev ใช้ หรือที่เราเรียกว่า Language Mismatch เวลา Dev คนใหม่ย้อนกลับไปดูไฟล์ Design เขาก็อาจจะงงเพราะว่าเขาหาไม่เจอว่า Feature ที่ชื่อนี้ใน Code มันคือ Flow ไหนในไฟล์ Design ส่งผลให้ยิ่งนานวันเข้าความสามารถในการ Maintain สิ่งนี้จะต่ำลงเรื่อย ๆ เพราะภาษาของแต่ละคนไม่ตรงกัน นอกจากนี้ โดยทั่วไป แต่ละตำแหน่งก็จะเป็น Domain Expert (คนที่มีความเข้าใจเชิงธุรกิจเชิงลึก) ในเรื่องต่าง ๆ ซึ่งพอแต่ละคนทำงานแยกกันเนี่ย ก็จะพบกับซวยเมื่อแต่ละคนก็จะ Concern แค่ในงานส่วนของตัวเองโดยที่ไม่ได้คุยกับฝ่ายอื่น ๆ ตั้งแต่เนิ่น ๆ ทำให้สุดท้ายเมื่อทำ Software ไปกลางทางก็อาจจะต้องรื้อเพราะแต่ละ Domain มีของที่ซ่อนอยู่ใต้ภูเขาน้ำแข็ง ## EventStorming คืออะไร EventStorming เป็น Workshop ที่เอา Stakeholder ที่เกี่ยวข้องกับระบบมาร่วมระดมความคิดกันเพื่อ Explore Business Domain โดยการนำ Post-it สีต่าง ๆ มาเชื่อมต่อกันให้เห็นภาพรวมของการทำงาน ซึ่งจะทำให้เราเห็นภาพรวมของระบบและเข้าใจตัวระบบมากขึ้นว่าเกิดอะไรขึ้นกับแต่ละ Domain รวมทั้งสามารถตั้งคำถามกับการทำงานในระบบเพื่อช่วยกันชี้จุดที่ยังคลุมเครือได้อีกด้วย ซึ่ง EventStorming สามารถนำมาใช้ได้ในหลาย ๆ สถานการณ์ เช่น 1. **การ Improve องค์กร:** การทำ EventStorming จะทำให้เห็นถึง Flow ต่าง ๆ ของ Business และได้เห็นความคิดของฝ่ายต่าง ๆ ในองค์กร ทำให้เราสามารถเห็นภาพรวมและ Next Step ที่เราจะพัฒนาองค์กรไปได้ 2. **การแสดงให้เห็นถึง Ecosystem ขององค์กร:** การทำ EventStorming จะทำให้ Stakeholder ทุกคนเข้าใจว่าเรามีทรัพยากรอะไรบ้างและเรากำลังจะสร้างอะไรบ้าง เพื่อให้ทุกคนไปในทิศทางเดียวกัน 3. **การคิด Service ใหม่ ๆ:** การทำ EventStorming จะสร้างความร่วมมือกันในทีมและทำให้แต่ละคนสามารถเสนอไอเดียและมาเข้าใจหลักการทำงานของ Service ใหม่ ๆ และมาเข้าใจว่าเราจะ Deliver Value ได้อย่างไร 4. **การออกแบบ Software ที่ซับซ้อน:** การทำ EventStorming จะทำให้เห็นความต้องการของแต่ละ Stakeholder และสามารถออกแบบ Software ด้วยหลักการ Domain Driven Design (DDD) ได้ ซึ่งวันนี้นิลจะขอ Focus ที่การทำ EventStorming สำหรับการออกแบบ Software นะครับ ## สีของ Post-it ที่ใช้ทำ EventStorming ### Post-it สีส้ม (Event) เราจะใช้ Post-it สีส้มในการเขียน Event หลัก ๆ ของ Domain นั้น ๆ โดยเราจะต้องเขียนเป็น Past Tense เพื่อระบุว่าเป็นเหตุการณ์ที่เกิดขึ้นไปแล้ว ### Post-it สีฟ้า/น้ำเงิน (Command) เราจะใช้ Post-it สีนี้เพื่อระบุถึง Command หรือ Action ของ User ที่ทำให้เกิด Event นี้ขึ้นมา ### Post-it สีเหลือง (External System) เราจะใช้ Post-it สีนี้เพื่อระบุจุดที่เชื่อมต่อ Service ภายนอก ### Post-it สีชมพู (Question) เราจะใช้ Post-it สีนี้เพื่อตั้งคำถามที่จุดต่าง ๆ ที่เราสงสัย ### Post-it สีม่วง (User) เราจะใช้ Post-it สีนี้เพื่อบอกว่าผู้ใช้งานใน Flow นั้น ๆ คือใคร อันนี้เป็นตัวอย่างของชุด Post-it ที่ใช้นะครับ ![post-it-example-for-event-storming](assets/event-storming-post-it.webp) สีส้มกับสีฟ้าเป็นสีที่ใน EventStorming ทุกคนใช้กัน แต่สีอื่นก็แล้วแต่กำหนดกันเลยฮะ ## ข้อตกลงก่อนทำ EventStorming อันนี้ก็จะเป็นข้อตกลงของแต่ละที่ที่ทำอีกแหละ แต่คร่าว ๆ ใน Context ทั่วไปน่าจะประมาณนี้ครับ 1. ทุกคนต้องให้ความร่วมมือ เนื่องจากเป็น Collaborative Workshop 2. ทุก Path ต้องจบด้วย Event หมายความว่า User จะ Command อะไรมาก็ตาม สุดท้าย Path นั้น ๆ ควรจบด้วย Event 3. Event ต้องเขียนเป็น Past Tense 4. ถ้าเขียนภาษาอังกฤษไม่ได้ ไม่เป็นไร ให้เขียนภาษาไทยไว้ก่อนและค่อยหา Facilitator มาแปลเป็นอังกฤษให้ 5. ถ้าระหว่างทำ EventStorming รู้สึกสงสัยหรือคาใจที่จุดไหน ให้แปะคำถามหรือข้อสงสัยที่ Post-it สีชมพู (Post-it คำถาม) ทันที อย่าเก็บความสงสัยไว้ ## ขั้นตอนของ EventStorming 1. Facilitator เล่าภาพรวมของระบบให้ฟัง 2. ผู้เข้าร่วมคนอื่น ๆ ช่วยกัน List Event ทั้งหมดที่เกิดขึ้นได้ และนำมาเรียงกันด้วย Timeline โดย Event ที่เขียนบน Post-it จะเป็นศัพท์ที่ทีมตกลงร่วมกันว่าจะใช้คำนี้ 3. เติมข้อมูลของ Command, User, และ External System ที่เกี่ยวข้องทั้งหมดเข้าไป และแน่นอนว่าชื่อ Command, User, และ External System ที่มีการใช้ในนี้ก็ต้องผ่านการตกลงร่วมกับทีมอีก 4. ถ้ามีจุดไหนที่สงสัยหรือคาใจ ติด Post-it คำถามทิ้งไว้ 5. เมื่อทำเสร็จแล้วก็จะมา Review กันและเช็คความเข้าใจร่วมกันอีกทีนึง ![post-it-colors-for-event-storming](assets/event-storming-post-it-example.webp) การทำ EventStorming เป็นสิ่งที่เราสามารถ Iterate ไปเรื่อย ๆ ได้เพื่อทำให้ภาพมันชัดมากขึ้น สุดท้ายก็ขึ้นกับการ Weight ระหว่างความชัดเจนกับเวลาที่ต้องเสียไปในการทำ EventStorming ว่าคุ้มค่าหรือเปล่า ## เราจะ Benefit อะไรจากการทำ EventStorming แน่นอน อย่างแรกเลยคือเราจะเข้าใจภาพรวมและการทำงานของระบบมากขึ้น รู้ว่า User เป็นใคร มาใช้งานระบบเราในจุดไหน ระบบเราเชื่อมต่อกับอะไร ซึ่งจะทำให้ทีมมีความเข้าใจร่วมกันและทำให้ทีมไปใน Direction เดียวกัน ถ้าในฝั่ง Technical แล้ว การที่เรามาตกลงชื่อ Event, Command, และ Users ร่วมกัน นั่นคือการที่ฝั่ง Business, PM, Designer, และ Dev จะใช้ชื่อเดียวกันในการสื่อถึงสิ่งหนึ่ง ๆ ก็จะทำให้ทีมสามารถสื่อสารกันอย่างเข้าใจมากขึ้น เมื่อการสื่อสารสามารถ Sync กันได้แล้ว แน่นอนว่าเราจะสามารถ Maintain Software ได้ง่ายขึ้นเพราะว่าของที่เขียนใน Requirement, ชื่อ Flow ใน Design, และชื่อตัวแปรกับฟังก์ชันใน Code ก็จะเหมือนกันหมด ทำให้ถ้าเราต้องการแก้อะไรในฝั่ง Business ฝั่ง Code ก็จะสามารถหาได้อย่างง่ายดาย ## Next Step เราจะศึกษาอะไรต่อดี นอกจาก Event Storming แล้ว ยังมี Tools อื่น ๆ เพื่อช่วยเราในเรื่องต่าง ๆ ได้ [Domain Storytelling](https://domainstorytelling.org/) – เป็น Tools ที่ใช้ในการ Capture Requirement ในระดับที่สูงขึ้นมาจาก EventStorming อีก ทำให้เราสามารถเห็นภาพกว้างขึ้นมาได้อีกระดับ [User Story Mapping](https://www.nngroup.com/articles/user-story-mapping/) – เป็น Tools ที่ใช้ในการคุยกันของทีมโดยคำนึงถึงการใช้งานของ User เพื่อให้สามารถแตก Task ย่อยและตัดตอนส่วนที่ไม่จำเป็น จนสามารถพัฒนา Product ในระยะเวลาที่กำหนดได้ ## สรุป - EventStorming เป็นแค่ Tools เฉย ๆ ไม่ได้แก้ได้ทุกปัญหา - แต่ถ้าทีมกำลังมีปัญหาเรื่องการสื่อสารและการ Maintain Software สิ่งนี้อาจจะช่วยได้ - EventStorming เปรียบเสมือนภาษากลาง (Ubiquitous Language) ในการพัฒนา Software ทำให้ทุกฝ่ายสามารถเข้าใจกัน และเพิ่ม Maintainablilty ให้กับ Software > ภาษาไม่ควรถูก Limit ที่ทีมฝั่งใดฝั่งหนึ่ง แต่ควรใช้ภาษาเดียวกันสื่อสารทั้งหมดเพื่อ Improve Maintainability และคุยกันรู้เรื่องมากขึ้น --- เย้ ๆๆ จบไปแล้วกับ Blog ที่นิลเล่าเกี่ยวกับ EventStorming ฮะ จริง ๆ ที่เพิ่งย้อนกลับมาดูคลิปอีกรอบเพราะว่าเดี๋ยวนิลต้องไปเข้า Workshop กับที่ออฟฟิศอะ 5555555 นิลเลยมานั่งย้อนดูฮะ และก็อยากลองเอามาเล่าในความเข้าใจของนิลฮะ แอบขายของนิดนึง (แต่เขาไม่ได้จ่ายนะ) ตอนนี้ UXTH ร่วมกับ Skooldio กลับมาเปิดขาย Online Rerun ของงาน UXTH Conference 2024 ที่ผ่านมาด้วยแหละ มี Session ที่น่าฟังเพียบบบ ยังไงใครสนใจสามารถเข้าไปดูได้[ที่ลิงก์นี้](https://www.skooldio.com/courses/uxth-con-2024)ได้เลยครับ และก็สามารถไปดู [Session DevDay ที่พี่รูฟพูดที่ช่องพี่ Siam Chamnankit ได้ที่ลิงก์นี้](https://youtu.be/p7IqD83ljvc?si=NkIwNNTvlZkMPICZ)ครับ ขอให้สนุกกับการสร้างภาษากลางในการทำงาน – นิล – --- # สรุปจาก WP Bangkok Meetup: ความปลอดภัยของ WordPress - URL: https://blog.ninprd.com/blog/wordpress-meetup-wordpress-security/ - Published: 2024-08-04 - Tags: WordPress, wordpress-meetup, meetup, meetup-2024, wordpress-bangkok - Summary: สรุปสาระสำคัญจากงาน WP Bangkok Meetup เรื่องความปลอดภัยของ WordPress เมื่อวันศุกร์ที่ผ่านมา ทาง WordPress Bangkok ได้จัด Meetup เรื่องความปลอดภัยของ WordPress นะครับ ซึ่งเป็น Group Discussion ที่ทุกคนมาแชร์กันเรื่อง Concern ของความปลอดภัยของ WordPress นะครับ ทั้งหมดนี้นิลสรุปออกมาเป็น Checklist ไว้แล้วครับ จะมีอะไรบ้าง ไปดูกันเลยครับ การแก้ไข functions.php ที่นิลพูดถึงในบทความนี้ทั้งหมด ขอให้ทุกคนทำที่ [Child Themes](https://developer.wordpress.org/themes/advanced-topics/child-themes/) นะครับ ใครไม่ยังไม่เข้าใจ Concept นิลแนะนำว่าอย่าเพิ่งแก้ไขอะไร functions.php นะครับ ถ้าทำที่ Theme หลักแล้ว เวลาที่เราอัปเดท Theme ไป ตัว Code Snippet ที่เราแก้ไขไปมันจะหายไปหมดเลยนะครับ ## ย้าย URL ของ Login และ Admin อันนี้อาจจะเป็น Basic ที่หลาย ๆ คนใช้นะครับ คือการที่ย้าย URL ของหน้า Login เพื่อให้คนที่จะเข้ามาโจมตีต้องนั่ง Scan นั่งแงะเว็บไซต์เพื่อพยายามหาหน้า Login นะครับ ซึ่งในขั้นตอนนี้เราสามารถใช้ Plugin ชื่อว่า [WPS Hide Login](https://wordpress.org/plugins/wps-hide-login/) ในการทำได้เลยครับ ## Limit จำนวนครั้งที่ Login ได้ อีกจุดนึงที่เราสามารถทำได้คือการ Limit จำนวนครั้งที่ User สามารถ Login ได้ครับ เพื่อป้องกันการ Brute Force หรือการสุ่มรหัสผ่านเข้ามาเรื่อย ๆ ครับ ซึ่งเราสามารถป้องกันได้โดยการติดตั้ง Plugin [WPS Limit Login](https://wordpress.org/plugins/wps-limit-login/) นะครับ ## คอยอัปเดท Version ของ WordPress, Plugins และ Themes อยู่ตลอด บางทีแล้วใน Version เก่า ๆ ของ WordPress, Plugins หรือ Themes อาจจะมีช่องโหว่อยู่ ซึ่งเขาก็จะออก Version ใหม่มาเพื่อปิดช่องโหว่เหล่านี้ ถ้าเราไม่อัปเดทแล้ว แน่นอนครับ เว็บไซต์ของเราโดนเจาะแน่นอน ## Authenticate REST API อันนี้เผื่อใครไม่รู้นะครับ WordPress เนี่ยจะเปิด REST API เป็นปกติอยู่แล้ว ถ้าเราเข้าเว็บไซต์ของเราแล้วเข้า /wp-json/wp/v2/users เนี่ย เราจะสามารถเห็น Users 10 คนล่าสุดในระบบเราได้นะครับ ซึ่งเราสามารถเห็น slug ซึ่งมันอาจจะตรงกับ Username ได้และทำให้คนที่พยายามจะโจมตีสามารถสุ่มรหัสผ่านจาก Username ที่ได้ไป ดังนั้นถ้าเป็นไปได้ เราควรจะทำการ Authenticate หรือว่าบังคับให้ต้องส่งพวก Token ในการยืนยันตัวตนมาให้ WordPress ก่อนเพื่อให้ใช้ REST API ได้ครับ อันนี้เราสามารถทำได้โดยแปะ Snippet นี้ไปที่ `functions.php` ครับ ```php // Require authentication for all REST API requests add_filter('rest_authentication_errors', 'require_authentication_for_rest_api'); function require_authentication_for_rest_api($result) { if (!is_user_logged_in()) { return new WP_Error('rest_not_logged_in', 'You are not currently logged in.', array('status' => 401)); } return $result; } ``` ## บังคับให้ใช้ Username เป็น Email ในการเข้าสู่ระบบ อันนี้เป็นสิ่งหนึ่งที่เราสามารถทำได้ หากเราต้องการเปิดตัว REST API Route เอาไว้นะครับ เราสามารถบังคับให้ User ใช้ Email แทน Username ได้โดยการใส่ Snippet นี้ไว้ที่ functions.php ครับ ```php // Authenticate user only if the username is an email function email_only_login_authenticate($user, $username, $password) { // Check if the username is an email address if (!is_email($username)) { return new WP_Error('invalid_username', __('Invalid username. Please use your email address to log in.')); } $user = get_user_by('email', $username); if ($user) { $username = $user->user_login; } else { return new WP_Error('invalid_email', __('No user found with this email address.')); } return wp_authenticate_username_password(null, $username, $password); } add_filter('authenticate', 'email_only_login_authenticate', 20, 3); ``` ## ปิด Function การ Forgot Password ถ้าไม่จำเป็นต้องใช้ อันนี้เป็นเรื่องที่มีคนถูก Pentest (Penetration Testing) แล้วเจอมานะครับ ช่องทางนี้ก็เป็น 1 ในช่องทางที่สามารถถูกเจาะได้ครับ ดังนั้นเราควรที่จะปิดการใช้ Forgot Password ถ้าไม่จำเป็นครับ เราสามารถใช้ Snippet นี้แปะที่ functions.php ได้เลยครับ ```php // Redirect Lost Password page to homepage or a custom page function disable_lost_password_page() { if (isset($_GET['action']) && $_GET['action'] === 'lostpassword') { wp_redirect(home_url()); exit(); } } add_action('login_init', 'disable_lost_password_page'); // Hide "Forgot Password?" link with CSS function custom_login_css() { echo ''; } add_action('login_enqueue_scripts', 'custom_login_css'); // Disable password reset functionality function disable_password_reset() { return false; } add_filter('allow_password_reset', 'disable_password_reset'); function disable_password_reset_message($message, $key) { return 'Password reset is disabled.'; } add_filter('retrieve_password_message', 'disable_password_reset_message', 10, 2); ``` ## ปิดเลข Version ของ WordPress และ Plugins อันนี้ก็เป็นอีก 1 ช่องโหว่นะครับ เมื่อคนที่มาโจมตีเว็บเราเห็นว่าเว็บเราใช้ WordPress หรือ Plugin Version เก่า ซึ่งอาจจะเป็น Version ที่มีช่องโหว่ก็จะอาศัยช่องโหว่นั้นในการโจมตีเว็บเราได้นะครับ ดังนั้นในจุดนี้เราควรปิดไม่ให้คนอื่นเห็นครับ เราสามารถปิดได้โดยเอาการเอา Snippet นี้ไปแปะที่ functions.php ครับ ```php // Remove version numbers from plugin styles and scripts function remove_plugin_version_numbers($src) { if (strpos($src, 'ver=') !== false) { $src = remove_query_arg('ver', $src); } return $src; } add_filter('style_loader_src', 'remove_plugin_version_numbers', 9999); add_filter('script_loader_src', 'remove_plugin_version_numbers', 9999); // Remove WordPress version number remove_action('wp_head', 'wp_generator'); // Remove WordPress version from RSS feeds function remove_wp_version_rss() { return ''; } add_filter('the_generator', 'remove_wp_version_rss'); ``` ทีนี้ถ้าเราใช้ Yoast SEO อยู่ ตัว Yoast จะมีวิธีการแปะ Version ที่ไม่เหมือน Plugin อื่น เราสามารถเอา Snippet นี้ไปแปะที่ functions.php ได้เลยครับ ```php // Remove Yoast SEO version number add_filter('wpseo_debug_markers', '__return_false'); add_filter('wpseo_analytics_intro', '__return_false'); add_filter('wpseo_frontend_output', 'remove_wpseo_version', 10, 2); function remove_wpseo_version($output, $version) { return preg_replace('//', '', $output); } // Remove Yoast SEO meta tags add_action('get_header', 'remove_wpseo_meta'); function remove_wpseo_meta() { remove_action('wp_head', array( 'WPSEO_Frontend', 'debug_mark' ), 2); remove_action('wp_head', array( 'WPSEO_Frontend', 'head' ), 1); } // Remove Yoast SEO comment add_filter('wpseo_debug_markers', '__return_false'); ``` ## การเลือก Hosting และ Domain Registrar เราก็ควรจะเลือก Hosting ที่มีชื่อเสียงและสามารถติดต่อ Support ได้อย่างทันท่วงทีและก็อาจจะใช้ Domain Registrar ที่สามารถช่วยเรากัน Spam เช่น [Cloudflare](https://www.cloudflare.com/) เป็นต้น ## หาก Setup ตัว Hosting เองระวังเรื่อง File Permissions หากเราต้องตั้ง File Permissions เอง ระวังการตั้ง File Permissions ที่ทำให้คนเข้าถึงและแก้ไข File ของเราได้ง่าย เช่น อย่าตั้ง File Permissions เป็น 777 เป็นต้น ## อื่น ๆ - ถ้าทำงานกับเว็บไซต์ภาครัฐ ต้อง Logout User ถ้า User คนนั้น ๆ Inactive เกิน 15 นาที สามารถใช้ Plugin [Inactive Logout](https://wordpress.org/plugins/inactive-logout/) - อีกอย่างนึงคือการต้องกังวลเกี่ยวกับตัว User เองมากกว่า แบบ ไม่ตั้งรหัสผ่านที่เดาง่ายจนเกินไป หรือ ไม่แปะรหัสผ่านไว้ตาม Post-it หน้าคอมหรือใต้โต๊ะ เท่านี้ก็น่าจะทำให้เว็บไซต์ WordPress ของทุกคนปลอดภัยแล้วครับ ^^ ใครสนใจ Meetup ดี ๆ แบบนี้สามารถติดตามได้ที่ [Meetup.com](https://www.meetup.com/bangkok-wordpress/) ได้เลยครับ ทีม WP Bangkok เขาจัดงานกันทุกเดือนครับ (ขอบคุณสำหรับงานดี ๆ แบบนี้ด้วยครับ) ขอให้สนุกกับการใช้ WordPress – นิล – --- # พูดไม่รู้เรื่อง จริงหรือเปล่าน้า (ฉบับ DevDev) - URL: https://blog.ninprd.com/blog/do-we-talk-incoherent/ - Published: 2024-05-18 - Tags: experience-sharing - Summary: สวัสดีครับ วันนี้มาใน Topic ที่นิลรู้สึกว่านิลมีปัญหาเรื่องนี้ครับ คือการพูดไม่รู้เรื่องครับ ตลอดเกือบ ๆ 2 ปีที่นิลทำงานมา นิลรู้สึกว่าตัวเองเป็นคนพูดไม่รู้เรื่องและปัจจุบันก็ยังรู้สึกแบบนั้นอยู่ครับ 55555 นิลเห็น Dev หลาย ๆ คนจะโดน Sterotype ว่าต้องพูดไม่รู้เรื่องเลย วันนี้นิลเลยจะมาพูดหัวข้อนี้ในมุมฝั่ง Dev แล้วกันว่าจริง ๆ แล้ว Dev พูดไม่รู้เรื่องจริงหรือเปล่านะ เอ… แล้วที่นิลเขียน Intro มาเนี่ย รู้เรื่องกันหรือเปล่านะ ถ้ารู้เรื่องก็ไปลุยกันเลยครับ สวัสดีครับ วันนี้มาใน Topic ที่นิลรู้สึกว่านิลมีปัญหาเรื่องนี้ครับ คือการพูดไม่รู้เรื่องครับ ตลอดเกือบ ๆ 2 ปีที่นิลทำงานมา นิลรู้สึกว่าตัวเองเป็นคนพูดไม่รู้เรื่องและปัจจุบันก็ยังรู้สึกแบบนั้นอยู่ครับ 55555 นิลเห็น Dev หลาย ๆ คนจะโดน Sterotype ว่าต้องพูดไม่รู้เรื่องเลย วันนี้นิลเลยจะมาพูดหัวข้อนี้ในมุมฝั่ง Dev แล้วกันว่าจริง ๆ แล้ว Dev พูดไม่รู้เรื่องจริงหรือเปล่านะ เอ้ะ ว่าแต่ที่นิลเขียน Intro มาเนี่ย รู้เรื่องกันหรือเปล่านะ ถ้ารู้เรื่องก็ไปลุยกันเลยครับ ## ความยากในการคุยของชาว Dev ในฐานะ Dev ท่านหนึ่งแล้ว นิลจะรู้สึกว่าหลาย ๆ ครั้งนิลจะหลุดพูดคำที่ศัพท์ที่เป็นเชิง Technical ของ Dev หรือ Jargon ของ Dev ออกไป ขอลองยกตัวอย่างดู เช่น API, CI/CD, Container, DDD (คนไม่ใช่สาย Tech งงคำพวกนี้ไหมครับ –‘) ซึ่งมันจะไม่เป็นอะไรเลยถ้าในวงสนทนานั้นทุกคนล้วนเป็น Dev แต่ถ้าในการสนทนานั้นเป็นการคุยระหว่าง Dev กับ Business แล้วนิลพูดศัพท์ Technical ไปล่ะครับ ตู้มมม ถ้า Business เขาไม่มีความรู้ Tech เลยนี่ เขาไม่มีทางรู้เรื่องกับสิ่งที่ Dev พูดเลยนะครับ (และเอาตรง ๆ ก็ไม่อยากคุยกับ Dev ที่คุยแบบนี้ด้วย 5555555) นอกจากการที่ Dev จะชอบพูด Jargon แล้ว อีกอย่างนึงที่ชาว Dev จะเจอคือการที่เราไม่ได้ Organize เรื่องที่เราจะเล่าให้ดีก่อน บางทีเล่าไปถึงประเด็นนึงซึ่งใกล้จะจบแล้ว ก็อาจจะเพิ่งนึกอะไรที่เป็นข้อมูลที่ต้องเล่าตอนแรก ๆ ออกและพูดแทรกหัวข้อที่ตัวเองกำลังพูดอยู่ ซึ่งพอผนวกความ Disorganize ในการเล่ากับการพูดศัพท์เทคนิคหรือ Jargon รัว ๆ แล้ว คนจะฟังจะไม่ค่อยเข้าใจและเกิดอาการอี๋ชาว Dev ฮะ อีกปัญหานึงที่เจอมาคือแม้แต่ใน Dev กันเอง ก็อาจจะเกิดปัญหาเมื่อ Dev คุยกันและระดับความรู้หรือ Context ของเรื่องเล่าที่มีในหัวไม่เท่ากัน (ขอเรียกสิ่งนี้ว่า Knowledge Gap ฮะ) เช่น Senior อธิบายของบางอย่างให้น้อง ๆ Junior ฟัง ก็อาจจะเกิดปัญหาที่น้อง ๆ Junior ไม่เข้าใจสิ่งที่ Senior จะสื่อออกมา ทั้ง ๆ ที่จริง ๆ Senior ที่เป็นคนเล่าคนนั้นอาจจะมองว่ามันง่ายมาก แบบ So easy แต่ด้วย Context ที่ต่างกัน น้อง ๆ ก็ไม่ได้เข้าใจ Project หรือไม่มีความรู้ในเรื่องนั้น ๆ มาก่อน สิ่งนี้ก็อาจจะทำให้แต่ละฝ่ายต่างไม่เข้าใจกัน ## ถ้าคุยไม่รู้เรื่อง จะเกิดอะไรขึ้นบ้าง เอาล่ะ ในมุมการทำงานเป็นทีม การคุยไม่รู้เรื่องก็ส่งผลกระทบต่อการทำงานโดยตรงเลยล่ะ เพราะถ้าคุยไม่รู้เรื่อง กว่าจะเข้าใจ Brief งาน หรือกว่าจะอธิบายงานให้คนอื่นเข้าใจก็อาจจะต้องเสียเวลาไปมากแล้วครับ ซึ่งจะกระทบต่อการเติบโตในสายงานอีก เพราะการที่ถ้าสมมติวันนึงเราจะเติบโตเป็น Senior หรือระดับ Leadership ได้ Skill การสื่อสารเราก็ต้องดีเหมือนกัน นอกจากนี้ถ้าเราต้องทำงานตรงกับลูกค้าและเราพูดไม่รู้เรื่อง มันก็จะส่งผลต่อภาพลักษณ์ของเรา ทำให้ลูกค้าไม่เชื่อถือบ้างหรืออาจจะทำให้ลูกค้าไม่พอใจก็ได้ครับ ## ในฐานะ Dev คนนึง เราจะสามารถทำอะไรได้บ้าง สิ่งแรกที่เราสามารถทำได้คือการลดคำศัพท์ Technical ที่ไม่จำเป็นลงและใช้คำพูดที่เข้าใจง่ายมากขึ้น ก่อนหน้านี้นิลมีเขียน Blog เรื่อง WordPress ที่เป็น Basic ไป (ซึ่งตอนนี้ก็ยังไม่ได้ปล่อย) แล้วนิลก็เขียนอธิบาย Pages ว่า > Page ใช้สำหรับข้อมูลที่ Static หรืออยู่ยงคงกระพัน ซึ่งนิลก็เขียนมาด้วยความที่แบบ Static ก็ Static Page ไง ศัพท์ง่าย ๆ แล้วนิลก็ส่งเพื่อนนิลที่ไม่ใช่สาย Tech อ่าน Preview ก่อน เพื่อนก็ทักมาถามนิลว่า _“สรุปว่าข้อมูล Static หรืออยู่คงกระพันคือไรวะ มันฆ่าไม่ตายหรอ5555”_ นิลแบบ เออ กลับไปนั่งคิดกับตัวเองเลยว่าถ้าไม่ได้อยู่สาย Tech แล้ว คำนี้ก็แอบยากเหมือนกันแฮะ สุดท้ายนิลก็พยายามเค้นความคิดของนิลออกมาเพื่อจะอธิบาย Pages ใหม่แบบนี้ครับ > Page จะใช้สร้างเนื้อหาในเว็บไซต์ที่ข้อมูลไม่ค่อยเปลี่ยน หรือบางอันก็อยู่ยงคงกระพันเลย ยกตัวอย่าง เช่น หน้าแรก หน้าเกี่ยวกับเรา หน้าติดต่อเรา ซึ่งเราก็จะไม่ได้แก้ไขหน้าพวกนี้บ่อย ซึ่งพอนิลปรับข้อความเป็นแบบนี้เพื่อนนิลก็เข้าใจมากขึ้นถึง Page ใน WordPress ขึ้นครับ จะเห็นได้ว่าแค่เราลด Jargon และเพิ่มคำอธิบายที่ทำให้เห็นภาพมากขึ้นเข้าไป เราก็จะสามารถสื่อสารให้คนอื่น ๆ เข้าใจได้ นอกจากนี้อีกอย่างที่สามารถทำได้คือการ Organize/Structure ความคิดก่อนที่จะพูดหรือจะเล่าออกไป ถ้าเอาแบบง่ายสุด ๆ ก็คือการเล่า Overview ก่อนแล้วเราค่อยเจาะลงไปในประเด็น คนที่ฟังเราจะได้เห็นภาพรวมเรื่องราวทั้งหมดและสามารถตามในแต่ละรายละเอียดที่เล่าออกไปได้ อีกสิ่งนึงที่ควรทำเป็นอย่างยิ่งคือการดูก่อนว่า ผู้ฟังคือใคร ซึ่งเมื่อเรารู้ว่าคนฟังของเราคือใคร เขามีความเข้าใจ Tech ประมาณไหน เราก็จะสามารถสื่อสารออกไปในภาษาที่เขาน่าจะเข้าใจได้ ยกตัวอย่างว่า นิลที่เป็น Dev กำลังคุยกับเพื่อน ๆ หรือพี่ ๆ Dev ที่ทำงานมาซักพักนึงแล้ว นิลก็อาจจะสามารถซัดศัพท์เทคนิคแบบเบิ้ม ๆ ได้ แต่ถ้านิลกำลังคุยกับพี่ ๆ Business หรือ Marketing แล้วนิลไปซัดศัพท์เทคนิคใส่ล่ะครับ ไม่รู้เรื่องแน่นอนเลย Tips นึงที่นิลชอบใช้เวลาที่จะคุยกับใครก็คือเรารู้ก่อนว่าเขาเป็นใครและก่อนที่นิลจะอธิบายไป นิลจะถามคำศัพท์ที่เกี่ยวข้องกับหัวข้อนั้น ๆ ก่อน เพื่อที่จะได้รู้ว่าเขารู้เรื่องอะไรบ้างและใช้คำศัพท์ในระดับที่เขารู้ เช่น ถ้านิลต้องอธิบายเรื่องระบบขายของที่ทำด้วยระบบอื่น ๆ มา ซึ่งในระบบก็จะมีสินค้าและหมวดหมู่ของสินค้าให้กับเพื่อนของนิลที่นิลรู้ว่าเขาเคยใช้ WordPress มาก่อน นิลก็จะถามว่าจำเรื่อง Posts กับ Categories ของ WordPress ได้ไหม ซึ่งให้มองสินค้าเป็น Posts ของ WordPress และหมวดหมู่ของสินค้าคือ Categories เลย แค่นี้ก็สามารถทำให้เพื่อนนิลเข้าใจในเรื่องระบบซื้อขายของอันใหม่ในเวลาอันรวดเร็วได้แล้วครับ --- จบไปแล้วกับ Blog ที่เล่าเรื่องของการพูดไม่รู้เรื่องผ่านเลนส์ของ Dev ท่านหนึ่งนะครับ นิลคิดว่านิลอาจจะทำ Blog อะไรแบบนี้ออกมาอีกแหละ เพราะนิลคิดว่ามีหลาย ๆ อย่างที่คนทั่ว ๆ ไปไม่เข้าใจชาว Dev และนิลก็อยากจะหยิบยกเรื่องราวเหล่านั้นมาเล่าให้ทุก ๆ คนฟังแหละ เย้ ๆ นิลแวะมาขายของนิดนึง (ที่เขาไม่ได้จ่าย) ช่วงนี้ Google Cloud เขาจัด Self-Study Program อยู่ชื่อว่า ChaiyoGCP ฮะ ปีนี้เป็นเกี่ยวกับ AI/ML ใครอยาก Upskill เกี่ยวกับ AI/ML หรือ Cybersecurity [สามารถเข้าไปดูรายละเอียดได้ที่นี่เลยฮะ](https://rsvp.withgoogle.com/events/chaiyogcp-s4) ที่เขียนมาคือถ้านิลเขียน Blog ไม่ทันนิลจะบอกว่าไปเรียน ChaiyoGCP แหละทุกคน 55555555 วันนี้ลาไปก่อนครัช ขอให้สนุกกับการสื่อสารกับผู้คน (ในยุคที่ต้องสื่อสารกับ AI 5555) – นิล – --- # ต่อให้ไม่มีเรา บริษัทก็อยู่ได้ - URL: https://blog.ninprd.com/blog/even-though-im-not-here-company-still-running-properly/ - Published: 2024-05-11 - Tags: experience-sharing - Summary: สวัสดีครับ เอาตรง ๆ คำว่าไม่มีเราเนี่ย มันสื่อออกมาได้ 2 ทางนะครับ คือ ไม่มีเราเพราะว่าลาป่วย ลากิจ ลาพักร้อน หรือไม่มีเราเพราะลาออกจากบริษัทไปครับ วันนี้นิลอาจจะเล่าหลัก ๆ ในทางแรกเพราะยังไม่เคยลาออกน่ะครับ สิ่งที่นิลเล่าเป็นมุมมองของ Junior Software Engineer คนนึงที่เพิ่งทำงานกำลังจะครบ 2 ปีนะครับ จะเป็นยังไงไปดูกันครับ สวัสดีครับ เอาตรง ๆ คำว่าไม่มีเราเนี่ย มันสื่อออกมาได้ 2 ทางนะครับ คือ ไม่มีเราเพราะว่าลาป่วย ลากิจ ลาพักร้อน หรือไม่มีเราเพราะลาออกจากบริษัทไปครับ วันนี้นิลอาจจะเล่าหลัก ๆ ในทางแรกเพราะยังไม่เคยลาออกน่ะครับ สิ่งที่นิลเล่าเป็นมุมมองของ Junior Software Engineer คนนึงที่เพิ่งทำงานกำลังจะครบ 2 ปีนะครับ จะเป็นยังไงไปดูกันครับ ## เมื่อบริษัทไม่มีเราแบบ ลาป่วย ลาพักผ่อน เอาล่ะ อันนี้ก็แน่นอน เมื่อวันที่เราป่วย วันที่เราอยากจะลาพักมันก็มีอยู่แล้วแหละครับ แต่บางทีเราจะรู้สึกว่าเรามีบ่วงแบบ ถ้าชั้นลาไปแล้ว เพื่อนร่วมงานชั้นจะเป็นยังไงนะ งานจะดำเนินต่อไปได้อย่างราบรื่นหรือเปล่าน้า ในมุมนิลแล้วเมื่อก่อนนิลก็มีคิดแบบนี้บ้างครับ แบบชั้นเป็น Dev คนเดียวใน Project ถ้าชั้นลาทีมจะชิบหายกันไหมนะ ถ้าชั้นลาแล้วจะกระทบ Timeline ของ Project หรือเปล่านะ คิดแบบนั้นเสร็จแล้วก็ก้มหน้าก้มตาทำงานต่อไปครับ สุดท้ายงานเสร็จ แต่ร่างกายนิลก็พังมากเช่นกันครับ ในความเป็นจริงแล้ว เมื่อเราสื่อสารกับทีมว่าเราจะลาวันไหนบ้าง ตอนนี้งานในมือเรามีอะไรอยู่บ้างและเราทำค้างไว้ที่ Step ไหน สิ่งที่เกิดขึ้นระหว่างการลามีได้หลายทางมาก ไม่ว่าจะเป็นการส่ง Task ที่เรากำลังทำอยู่ให้กับคนอื่น ๆ ในบริษัทที่มี Skillset ใกล้เคียงกับเรา หรือแม้แต่การจ้าง Outsource เพื่อรับผิดชอบงานในส่วนนั้นเพื่อให้ส่งมอบงานให้ทัน Timeline ครับ เมื่อเรากลับมาก็แค่กลับมารับงานต่อจากส่วนที่มีคนมาทำต่อไว้ แค่นั้นเลยครับ อันนี้นิลไม่ได้บอกให้ทุกคนแบบทิ้งความรับผิดชอบในหน้าที่นะครับ แบบขี้เกียจจังเลยน้า พรุ่งนี้ลาดีกว่าแล้วก็ Yolo ใส่ทีม แบบนี้ไม่เอานะครับ นิลแค่อยากให้ทุกคนสื่อสารเรื่องความเหนื่อย ความอยากพักผ่อน และอาการป่วยของตัวเองออกมาให้ภายในทีมรู้ หรืออาจจะ Reflect กับ Manager ตอน One-on-One เพื่อว่าถ้าสมมติเราอยากจะพักผ่อนจริง ๆ ทีมจะได้ช่วยกันหาทางออกเพื่อจะให้เราได้พักอย่างเต็มที่ครับ ซึ่งในทางปฏิบัติจริงเมื่อเกิดเหตุการณ์แบบนี้บ่อย ๆ ทีมก็อาจจะต้องเริ่มคิดมาตรการต่าง ๆ สมมติเช่นว่าตอนแรก Project มี Dev คนเดียวและ Dev คนนั้นเริ่มรู้สึกเหนื่อยกับการทำงานและอยากพักหลาย ๆ ครั้ง หรืองานโถมที่ Dev คนนี้มากจนเขาป่วยบ่อยมาก ทีมก็อาจจะต้องหา Dev มาเพิ่มเพื่อช่วยแบ่งเบาภาระ Dev คนนั้นและลดความเสี่ยงในการส่งมอบงานไม่ทัน Timeline หรืออาจจะมีการวางตัวสำรองแบบคร่าว ๆ ไว้ เช่น ถ้าคนนี้ลา คนนั้นจะสามารถมาทำแทนได้ เพื่อให้สุดท้ายแล้ว ทีมก็ยังสามารถ Deliver งานออกไปได้ แม้เราจะไม่อยู่ครับ นิลลองยกตัวอย่าง เคสนิลอันนึง ช่วงต้นปีนิลติดโควิดไปครับ ซึ่งเป็นช่วงที่ทีมกำลังต้องไป Train ลูกค้าและจริง ๆ นิลต้องเป็นคนไปสอน แต่พอนิลติดโควิดและมีไข้ ไอ และอาการมึนหัวมาก พอแจ้งทีมไป ทีมก็เริ่มคิดว่าจะทำยังไงดี ซึ่งก็ยังโชคดีที่ในทีมมีน้อง Dev อีกหนึ่งคนที่รู้ Context ของ Project ค่อนข้างเยอะครับ สุดท้ายนิลแค่ลุกจากเตียงมาเล่าว่านิลทำ Slide ในส่วนไหนไปแล้วบ้าง และอยากเน้นย้ำส่วนไหน พอนิลเล่าเสร็จนิลก็โดดขึ้นเตียงนอนเพื่อพักละฮะะ ส่วนทีมที่เหลือก็ต้องรีบเตรียม Training กันต่อแหละ สิ่งที่นิลจะสื่อคือบางทีพอเราป่วยในจังหวะที่ชิบหายแบบนี้ อาจจะมีคนเลือกที่จะไม่สื่อสารอาการป่วยออกไปและฝืนมาทำงานต่อครับ สุดท้ายเราก็ทำงานไม่เต็มที่ ทีม Productivity ก็ตก บางทีเราป่วยและต้องการพักช่วงที่ทีมรีบตามงาน เราก็ไม่ตื่นมาตอบเขาอีก สู้ลาไปเลยแล้วส่งต่องานให้คนที่ยังอยู่ดีกว่า นิลว่ามันอาจจะตอบโจทย์ในมุมการทำงานเป็นทีมมากกว่านะครับ ## เมื่อบริษัทไม่มีเรา แบบเราลาออกไป ถ้าเราไม่อยู่แล้ว อย่างที่นิลจั่วหัวไปครับ บริษัทก็อยู่ได้ แต่มีอะไรบ้างที่บริษัทจะเสียไป นิลว่าอันนี้อาจจะน่าสนใจกว่าครับ นิลคิดว่าแน่ ๆ แหละ ถ้าสมมติคน ๆ นึงหายไปและเขารับ Workload เยอะ วันนึงที่เขาลาออกไป ก็ต้องมานั่งบริหารจัดการ Workload ให้คนในทีมใหม่อีก กับถ้าคนนั้น ๆ ถือ Domain Knowledge อะไรบางอย่างอยู่และเขาออกโดยที่ไม่ได้ทำ Documentation เอาไว้ บริษัทก็จะเสีย Domain Knowledge บางอย่างที่ไม่ได้แชร์ไปครับ และที่คิดได้อีกอันคือเรื่องของค่ารับคนใหม่เข้ามาแทนกับค่า Training เพราะกว่าที่เราจะหาคนที่ Skillset ใกล้เคียงคนที่ออกไป หรือ Train ให้มี Skillset ที่ใกล้เคียงกัน อาจจะต้องใช้เงินและเวลาเยอะมาก ซึ่งนิลคิดว่าเนี่ยแหละคือสิ่งที่บริษัทเสียไป ในอีกมุมนึงนิลมองว่าก่อนที่เราจะลาออกไป เราควรจะทำ Documents, Knowledge Sharing หรือถ้าเราตำแหน่งใหญ่หน่อยก็ควรจะวาง Successor หรือผู้สืบทอดไว้มาแทนเรา เพื่อให้บริษัทสามารถดำเนินการต่อไปได้ครับ ถ้าเราบอกว่าเราจะลาออกไปแล้วบริษัทมาบอกว่า ถ้าเราออกไปแล้ว บริษัทนั้นจะล่มจมเลย ในมุมนิลรู้สึกว่าคำพูดนี้เป็นแค่เหมือนการรั้งกันไว้เฉย ๆ นะครับ ลองคิดภาพตามว่า ถ้าออกปุ๊ป องค์กรล่มปั๊ป องค์กรนี้บอบบางยิ่งกว่ากระดาษ A4 อีกนะครับ 55555 --- จบไปแล้วนะครับกับ Blog สุดดราม่า Blog นี้นิลมีตัวช่วยนิลคิดหัวข้อคือเจ้า Perplexity แหละ ปกติแล้วนิลจะใช้ ChatGPT เป็นเพื่อนที่เหมือนช่วยตรวจ Bullet Point ที่นิลเล่าครับ แต่วันนี้นิลลองอีกแบบนึง คือลองให้มันสร้าง Bullet Point ต่าง ๆ จากหัวข้อของ Blog ที่นิลใส่ไป และให้ Context มันไปเพิ่มนิดหน่อย ละนิลลองแบบไม่คิดอะไรเพิ่มและเล่าจาก Bullet Point ที่มัน Gen มา ส่วนตัววันนี้นิลคิดว่ามันทำได้ดีนะ แล้วก็ใช่ครับ รูปปกที่เป็น Style ไปเพราะตอนนี้นิล Cancel Subscription ChatGPT แล้ว แงงๆๆ หลัง ๆ นิลใช้แค่ Gen รูปกับตรวจบทความอะ เลยรู้สึกว่าไม่คุ้มแล้ว กับอยากหา Gen AI ตัวอื่นด้วย หวยก็เลยไปตกที่ Perplexity ที่มี Code ลดละเดือนแรกเหลือ 10 ดอลฮะ แหะ ๆ แต่ยังแอบไม่ชอบ Style รูปเท่าไหร่เลย ช่วงแรก ๆ อาจจะต้อง Tune การใช้งานกันไปก่อนแหละ แล้วก็ตัว Blog ยังสามารถ Feedback กันเข้ามาได้ที่เพจเหมือนเดิมนะครับ เปิดรับ Feedback เสมอครับ – นิล – --- # พร้อมแค่ไหนถึงจะยื่นสมัครงาน? - URL: https://blog.ninprd.com/blog/how-ready-you-have-to-be-before-applying-for-jobs/ - Published: 2024-04-20 - Tags: experience-sharing - Summary: พอดีนิลได้มีโอกาสไปเป็น TA ให้กับ Web Development Bootcamp ของ Skooldio และนี่เป็นคำถามที่นิลได้จากคนเรียน Bootcamp ที่นิลรู้สึกว่าตอบง่ายมากครับ เพราะในตอนที่นิลเริ่มสมัครงานครั้งแรก นิลก็เป็นแค่เด็กที่จบวิศวะ อุตสาหการคนนึง ที่เพิ่งผ่านการฝึกงานในตำแหน่ง Full Stack Developer มา 6 เดือนและทำ Project ส่วนตัวมานิดหน่อยและย้ายสายไปฝั่ง Software ทันทีหลังเรียนจบเลย งั้นต้องพร้อมแค่ไหน ไปค้นหาความพร้อมกันเลยครับ > ตอนที่ยื่นสมัครงานครั้งแรก รู้สึกต้องพร้อมแค่ไหน ถึงยื่นสมัครงาน > > คนเรียน Bootcamp ท่านหนึ่ง พอดีนิลได้มีโอกาสไปเป็น TA ให้กับ [Web Development Bootcamp](https://landing.skooldio.com/web-development-bootcamp) ของ Skooldio และนี่เป็นคำถามที่นิลได้จากคนเรียน Bootcamp ที่นิลในตอนนี้รู้สึกว่าตอบง่ายมากครับ เพราะในตอนที่นิลเริ่มสมัครงานครั้งแรก นิลก็เป็นแค่เด็กที่จบวิศวะ อุตสาหการคนนึง ที่เพิ่งผ่านการฝึกงานในตำแหน่ง Full Stack Developer มา 6 เดือนและทำ Project ส่วนตัวมานิดหน่อยและย้ายสายไปฝั่ง Software ทันทีหลังเรียนจบเลย งั้นต้องพร้อมแค่ไหน ไปค้นหาความพร้อมกันเลยครับ ## ย้อนไปสมัยหนุ่ม ๆ ของนิล ในตอนที่นิลยื่นสมัครงานครั้งแรก นิลก็เจอแนวคิดแบบนี้เหมือนกันครับ ตอนนั้นนิลมีประสบการณ์ฝึกงานในตำแหน่ง Full Stack Developer มา 6 เดือนทำให้นิลรู้สึกว่ามีแต้มต่อกว่าคนอื่น แต่นิลก็ติดกับแนวคิดความพร้อมเหมือนกับสมัยสอบมหาลัยฯ ว่าเราต้องพร้อมที่สุดเพื่อที่จะทำได้ เพื่อจะเก่งเจ๋ง ผนวกกับตอนนั้นที่นิลทำมา นิลเขียนเว็บด้วย VueJS ครับ แต่ส่วนใหญ่บริษัทในไทยจะรับสมัครแต่คนที่ใช้ ReactJS นิลเลยรู้สึกไม่พร้อมเท่าไหร่ นิลเลยไปนั่งเรียน React เพิ่ม ทำ Project เพิ่ม ทำไม่ได้ตรงไหนก็ทำเพิ่มเรียนเพิ่ม วนลูปอยู่นั่นแหละครับ และก็เกิดวุฒิปัญญาขึ้นมาได้ที่จุดนึงครับว่าการรอให้พร้อม 100% อาจจะไม่มีอยู่จริงก็ได้ พอนิลคิดได้แบบนั้น นิลที่พอมีพื้นฐานจุดนึงแล้ว นิลก็เริ่มสมัครงานเลยซึ่งในแต่ละที่ที่นิลสมัครไป พอผ่าน Process ของเขาเสร็จ นิลจะเห็นจุดที่นิลยังไม่โอเค ยังปรับปรุงได้อยู่ นิลก็นำมาปรับปรุงและนำไปพัฒนาเรื่อย ๆ จนสุดท้ายนิลก็แก้ไขมันมาเรื่อย ๆ และผ่านการสัมภาษณ์รวมถึงได้เข้าทำงานที่ Skooldio Tech ครับ ## มุมมองของนิลต่อคำถามนี้ ในมุมของนิลแล้ว การที่จะบอกว่าเก่งแค่ไหน พร้อมแค่ไหนถึงจะพอ นิลว่ามันยากมากเลยที่จะตอบ Exact Point ของความพร้อม กว่าที่เราจะรู้สึกว่าพร้อมที่สุด อาจจะเป็นวันที่ไม่เหลือโอกาสอะไรแล้วหรือมันอาจจะไม่เคยมาถึงก็ได้ รวมถึงจากที่ผ่าน ๆ มา นิลจะเห็นหลาย ๆ คน Self Doubt ในตัวเอง คิดว่าตัวเองไม่เก่ง ไม่เจ๋ง แล้วก็จะงมมันอยู่อย่างงั้นแหละ ซึ่งในมุมนิลก็คิดว่าอาจจะเป็นการดีที่รู้ว่าตัวเองยังไม่เก่งเจ๋ง แต่อาจจะเป็นการใช้เวลางมกับความคิดของตัวเองนานเกินไปจนทำให้พลาดโอกาสดี ๆ ไปได้ ดังนั้นในมุมของนิล ถ้าเรารู้สึกมั่นใจประมาณนึง เราก็อาจจะยื่นสมัครงานไปก่อนได้เลย แล้วพอเราไปเจอสถานการณ์จริงแล้ว เราจะรู้เองว่าเราไม่พร้อมตรงไหน และค่อย ๆ ปรับเพื่อเป็น Better Version ในครั้งถัด ๆ ไป หรือว่าถ้ามีเพื่อนที่อยู่ในตำแหน่งงานนั้น ๆ อาจจะลองถามว่าในตำแหน่งงานนั้น ๆ มีเรื่องอะไรที่เราต้องรู้เพื่อทำมันได้ไหม ถ้าเราคิดว่าเรารู้และเข้าใจสิ่งเหล่านั้นประมาณนึงแล้ว อาจจะไปลองเลยก็ได้ครับ ให้เรื่องปวดหัวเป็นเรื่องของ HR ครับ ตัวเราอย่าไปคิดมากในจุดนี้เลย เราแค่ทำหน้าที่ของเราในฐานะผู้สมัครคนนึงให้ดีที่สุดพอครับ แต่อย่ากลัวที่จะยื่นพอครับ ## ถ้าจะสมัครงานแล้ว มีอะไรที่ต้องดูอีก อีกอย่างนึงที่เราควรทำคือดูว่าเราอยากเข้าบริษัทไหนและบริษัทนั้น ๆ เขามี Expectation ต่อคนที่มาสมัครยังไง และเรามี Expectation ต่อการทำงานยังไง เช่น เรา Expect ว่าเราจะทำงานชิว ๆ แอค ๆ แต่ว่าบริษัทที่เราสมัครไปเขามี Expectation ว่าอยากได้คนเทพ ๆ ทำงานเดือด ๆ เราก็อาจจะไม่ตรงกับ Expectation ของเขาครับ ซึ่งอย่างที่นิลเคยเขียนไปใน Blog [“การ Set Expectation ในการทำงาน”](clear-expectation-at-work.md) แหละครับ ทั้ง 2 ฝั่งก็ควรจะมี Expectation ที่ตรงกัน ถึงจะ Happy ทั้ง 2 ฝั่งครับแหละ ## บางทีเราอาจจะลองตั้งคำถามอีกแบบนึงล่ะ ถ้าสมมติเราตั้งคำถามว่าเราต้องพร้อมหรือต้องเก่งแค่ไหน อาจจะทำให้เราเกิดความ Self Doubt ในตัวเองประมาณนึงครับ ถ้าลองเปลี่ยนเป็นคำถามว่า _“บริษัทไหนอยากจะรับเรา”_ อาจจะเป็นการกลับมานั่ง Reflect กลับตัวเองก็ได้ครับว่าทำไมบริษัทนั้น ๆ ถึงอยากรับหรือไม่อยากรับเราเข้าไปทำงาน อันนี้น่าจะเป็นจุดที่เราสามารถจัดการกับจุดที่เรามองว่าเรายังไม่ดีพอสำหรับแต่ละบริษัทและก็ลับคมให้ดีสำหรับจุดที่เรามองว่าเราเก่งเจ๋งอยู่แล้ว คำถามที่เปลี่ยนไปอาจจะช่วยเปลี่ยนมุมมองจากการตั้งคำถามในตัวเองเป็นคำถามเพื่อการพัฒนาตัวเองได้เลยครับ --- จบไปแล้วนะครับ Blog นี้เป็น Blog ที่มีคนมาช่วยนิลคิดเยอะมาก คือบอกตรง ๆ ว่าถึงกลางคันของการเขียนแล้ว นิลคิดไม่ออกว่าจะเล่าสิ่งนี้ยังไงต่อ แต่จนแล้วจนรอดเมื่อวานก็มีพี่ที่ออฟฟิศนิลมาช่วยนิล Unlock ความคิดกับแนะนำหัวข้อเพิ่มเติมมาจนนิลเขียนจบได้ครับ กราบไหว้สุด ๆ มีคอนเทนต์ในหัวเยอะแต่ว่าคิดไม่ออกว่าแต่ละหัวข้อจะเล่ายังไงดี เดี๋ยวจะค่อย ๆ ปรับเรื่อย ๆ ครับ ยังไงก็ขอบคุณทุก ๆ คนที่อ่านกันมาถึงจุดนี้มากครับ มี Feedback กันยังไงก็บอกกันได้ครับ จะพยายามเอาไปปรับปรุงครับ 🙂 – นิล – --- # เที่ยวคนเดียวครั้งแรกที่ไต้หวัน - URL: https://blog.ninprd.com/blog/alone-in-taipei-2024/ - Published: 2024-03-30 - Tags: experience-sharing, Y2024, travel, taipei - Summary: สวัสดีครับ ปีนี้เป็นครั้งแรกที่นิลเดินทางออกนอกประเทศคนเดียวและประเทศที่นิลไปคือไต้หวันครับ โดยเป้าหมายหลักของการไปในครั้งนี้ของนิลคือการไป WordCamp Asia 2024 และไปคลายเครียดครับ ซึ่งช่วงก่อนหน้าที่นิลจะไปนั้น งานทับตัวมากครับ นิลไม่ได้มีเวลาทำแผนยาว ๆ เลย นิลเลยเลือกการใช้ผู้ช่วยส่วนตัวของนิลในการวางแผนนั่นคือ “ChatGPT” นั่นเอง ทริปนี้จะชิบหายแค่ไหน ไปดูกันครับ สวัสดีครับ ปีนี้เป็นครั้งแรกที่นิลเดินทางออกนอกประเทศคนเดียวและประเทศที่นิลไปคือไต้หวันครับ โดยเป้าหมายหลักของการไปในครั้งนี้ของนิลคือการไป WordCamp Asia 2024 และไปคลายเครียดครับ ซึ่งช่วงก่อนหน้าที่นิลจะไปนั้น งานทับตัวมากครับ นิลไม่ได้มีเวลาทำแผนยาว ๆ เลย นิลเลยเลือกการใช้ผู้ช่วยส่วนตัวของนิลในการวางแผนนั่นคือ “ChatGPT” นั่นเอง ทริปนี้จะชิบหายแค่ไหน ไปดูกันครับ ## การตัดสินใจไปไต้หวัน ต้องเท้าความกลับไปตอนที่นิลตัดสินใจจะไปนะครับ จริง ๆ มันเริ่มจากงาน WordCamp ก่อน คือนิลตัดสินใจไปงาน WordCamp Asia แล้วก็กดซื้อตั๋วเข้างานไปเลยแบบงง ๆ อยู่ดี ๆ ตังก็ปลิวไปเลย ทีนี้พอกดตั๋วเข้างานแล้ว นิลก็เลยคิดแบบ ชิบหายแล้ว ทำอะไรลงไปวะ แต่มันก็ทำให้นิลเลือกที่จะเริ่มจองโรงแรมและตั๋วเครื่องบินครับ ในส่วนของตั๋วเครื่องบินนิลก็หาจาก Google Flight เลย ส่วนโรงแรมนิลให้เพื่อนที่เคยไปไต้หวันช่วยเลือกครับ ซึ่งนิลก็จองผ่านเพื่อนนิลคนนึงครับที่ทำงานอยู่ที่ Agoda ซึ่งก็จะได้ส่วนลดมาประมาณนึงเลยครับ พอจองอะไรเสร็จ นิลก็ Download เอกสารทุกอันไว้ ส่วนโรงแรมที่เพื่อนจองนิลก็ให้ส่งมาใน LINE (แต่ไม่ได้โหลด) ตัวเอกสารที่ได้มานั้น นิลไม่ได้อ่านเลย ด้วยความที่งานทับตัวอยู่ในช่วงนั้น ## วางแผนการเดินทางแบบโคตรเท่…(ล่ะมั้ง) อย่างที่นิลได้เขียนไปข้างบนครับ ตอนแรกนิลเลือกคุยกับ ChatGPT เพื่อที่จะวางแผนเที่ยวให้โดยนิลใช้เวลาคุยเกือบ ๆ จะชั่วโมงครับ เอาไอนู่นเข้า เอาไอนี่ออก ไม่กินข้าวร้านนี้ ไม่แวะที่ร้านนู่น ไปมา ๆ กับ ChatGPT นานมาก จนสุดท้ายนิลก็ได้ Final Plan By ChatGPT มาครับ นิลก็เอาลง Story IG แบบ โคตรเท่ แผนเที่ยว By ChatGPT ว่ะเพื่อน ๆ แต่ว่านิลก็ต้องมาสะดุดครั้งที่ 1 คือ “Chat แม่งมั่ว” Chat ให้สถานที่ที่ไม่มีอยู่จริงเยอะมาก แบบเกือบ ๆ 50% ของแผนได้ ซึ่งนิลก็ได้เพื่อนนิลอีกคนครับ ที่เห็นนิลลงแผนแบบที่มั่ว ๆ ไปใน Story มาช่วยนิลวางแผนให้ ซึ่งสุดท้ายนิลก็เอาแผนเพื่อนมาผสมกับแผนจาก ChatGPT ที่ตรวจสอบแล้วว่ามีอยู่จริงเอาไปลงเว็บแอปที่มีชื่อว่า Wanderlog ครับ เป็นเว็บแอปที่ใช้วางแผนการเที่ยว สามารถสร้าง Trip และใส่พวกรายละเอียดการเที่ยว เช่น Flight ที่นอน Budget รวมถึงว่าวันต่าง ๆ จะไปที่ไหนด้วยครับ นอกจากนี้ถ้ามีคนไปด้วยก็สามารถ Invite เพื่อนมาใน Trip และเอามาหารค่าใช้จ่ายได้ด้วย จนสุดท้ายนิลก็ได้แผน Version 1 มาได้อย่างยากลำบาก ## ไปถึงไต้หวัน ตอนนิลถึงไต้หวันเนี่ย นิลก็ไม่รู้อะไรเลยครับ นิลมีแค่ Easy Card ที่เพื่อนที่ออฟฟิศให้มา แต่นิลไม่ได้ศึกษาเลยว่ามันทำอะไรได้บ้าง นิลก็ไปงึก ๆ งัก ๆ หน้าตู้จ่ายตั๋วรถไฟฟ้าครับ ก็มีคนไต้หวันคนนึงเดินมาสอนวิธีการใช้งานเจ้าบัตรตัวนี้และสอนการดูเส้นทางการนั่งรถไฟครับ พอนิลเติมเงินได้ เขาก็ยิ้มและพูดกับนิลว่า “Happy Traveling in Taiwan” รู้สึกใจฟูมาก จากนั้นนิลก็นั่งรถไฟไปเรื่อย ๆ เพื่อจะไปที่พัก จนผ่านมาซักพักนิลก็อยากจะเปิดรายละเอียดเกี่ยวกับโรงแรมที่จองไป ไฟล์ใน LINE มันหมดอายุ นิลเลยโทรไปให้เพื่อนส่งมาให้อีกรอบ พอนิลเปิดดูปุ๊ป ร้อง “เxี้ย” อย่างดังครับ เพื่อนจองโรงแรมเป็น Female Only ไป นิลแบบชิบหายละ และก็โทรไปให้เพื่อนยกเลิกและจองโรงแรมใหม่ให้ สุดท้ายนิลก็ได้ที่พักอีกที่นึง (แล้วต้องจ่ายตังเพิ่มด้วยนะ ที่พักแพงขึ้น) เป็น Hostel ชื่อว่า Cavemen Hostel ครับ ก็พอใช้ได้ แต่บรรยากาศทึบไปนิดนึงครับ + บรรยากาศให้ความรู้สึกไม่ Secure เลย ฮืออ แบบนิลเอาคอมไปด้วยไง เลยแอบกลัวนิด ๆ นอกจากนี้โรงแรมก็ไม่มีผ้าขนหนูให้อีก นิลก็ออกไปซื้อตามห้างซึ่งด้วยความไม่รู้เนี่ย นิลก็ไปซื้อที่ MUJI ครับ โคตรแพงเลย คอมโบต่อมาที่ข้าวเย็น ด้วยความที่ไม่ได้ศึกษาอะไรก่อนมาเลย แน่นอนครับ โดน Food Court ห้างไปตามระเบียบ ไม่ตามระเบียบอย่างเดียวคือราคา ทำไม Food Court มันจานละเกือบ ๆ 200 ได้วะ 555555 แต่โดยรวมวันนี้ก็ไม่ได้ทำอะไรมากครับ แค่นี้ก็หมดวันแล้ว ## Day 2-4: WordCamp Asia 2024 เนื้อคอนเทนต์มันไปอยู่ใน Blog อีกอันแล้วอ่า ไปตามอ่านได้ที่  [wordcamp-asia-2024-with-nin](wordcamp-asia-2024-with-nin.md) ## ก่อนกลับวันนึง ตอนแรกนิลว่าจะไปแช่น้ำพุร้อนที่ Beitou Hotspring กับแก๊งค์ชาวไทยที่นิลเจอที่งาน WordCamp Asia แต่ว่าไม่สะดวกกัน นิลเลยเปลี่ยนแผนนิดหน่อย เลยย้าย Hotspring ไปพรุ่งนี้และเปิดวันด้วยการไปกินร้านชานม 50 Lan มา ส่วนตัวนิลชอบมากก แนะนำเลย เสร็จแล้วนิลก็ไปหากินข้าวเที่ยงแล้วก็ไปที่ตึก Taipei 101 เพราะตอนแรกจะไปลองร้านกาแฟ Simple Kaffa (เพื่อนแนะนำมา) แต่แบบไปถึงแล้วมันต้อง Reserve + ค่ากาแฟแพงมาก นิลเลยเปลี่ยนไปกินอีกร้านนึงชื่อว่า Cafe Acme ครับ ได้ไปซิบกาแฟชมวิวจากตึก Taipei 101 ชั้น 35 แล้วก็นั่งเขียน Blog ไปด้วย โคตรดีเลยครับ จากนั้นนิลก็จะไปกินข้าวเย็นที่ร้าน Din Tai Fung แต่ดูจากปริมาณคิวแล้ว นิลน่าจะได้กินอีกทีชาติหน้า นิลเลยลงไปหากินที่ Food Court (อีกแล้ว) และตามระเบียบที่นี่ครับ Food Court ก็เกือบ 200 อีกแล้ว (คิดถึง Food Court ไทยก็ทีนี้แหละ TT) พอกินเสร็จ นิลก็จะกลับที่พักแล้วครับ แต่ท้องไส้ปั่นป่วนหนักมากเลย ไม่รู้ว่าโดนอะไรมา แต่มันก็ทำให้นิลพลาดที่จะลองร้าน Chun Shui Tang ที่อยู่ใน Bucket List นิลได้แหละ 5555 พอกลับถึงที่พักก็ดีขึ้นฮะและก็กลายเป็นมานั่งปั่นงานต่อถึงเที่ยงคืนเลย 55555 ![Curry in Food Court in Taipei](assets/alone-in-taipei-foot-court.webp) ## วันสุดท้ายแล้ว วันนี้นิลตั้งเป้าเอาไว้ว่าอยากเก็บชานมให้ครบตาม Bucket List ของตัวเองครับ และก็มีนัดกับแก๊งค์ชาวไทยไป Beitou Hotspring กันตอนบ่ายด้วย แต่เปิดวันด้วย Checkout + ฝากกระเป๋าไว้ที่โรงแรมและไปที่ MOCA Taipei ครับ ซึ่งนิลก็ช็อคมากเพราะว่า MOCA ปิดวันจันทร์ และวันที่นิลไปก็คือวันจันทร์ ฮืออออ ฮืออออ ฮืออออ เศร้ามากก นิลก็เลยเปลี่ยนแผนด้วยการไปที่ตึก Syntrends ครับ เป็นตึกที่รวมพวก Technology หรือ Gadget ต่าง ๆ อยู่ในนี้ซึ่งบอกเลยว่าตอนแรกไม่อยู่ในแพลนเลย แต่นึกขึ้นได้ว่ามีคนเรียน Bootcamp แนะนำมา นิลเลยไปครับ ไปเจอพวก Gadget ต่าง ๆ ก็สนุกดีครับ เดินเพลินมาก เดินไปชั่วโมงกว่า เสร็จแล้วนิลก็ลงมาหาข้าวกินครับ
![Coco Ichibanya in Taipei](assets/alone-in-taipei-2024-coco.webp) ![Syntrend Building in Taipei](assets/alone-in-taipei-2024-syntrends.webp) ![Moca in Taipei](assets/alone-in-taipei-2024-moca.webp)
พอกินข้าวเสร็จนิลก็ไปรวมตัวกับแก๊งค์ที่จะไป Beitou Hotspring ด้วยกันแล้วก็นั่งรถไฟไปกันครับ พอไปถึงก็มีคอนเทนต์อีกก็คือที่ Hotspring ที่จะไปแช่เนี่ย พอเราจะเข้าไปกัน เขาก็แนะนำว่าไปอีกที่ดีกว่าไหม อะไรแบบนี้ พวกนิลก็แบบ ห้ะ อะไรวะนั่น แต่จริง ๆ คือถ้าจะแช่ที่นี่มันต้องมีกางเกงว่ายน้ำครับและก็ตัวบ่อน้ำพุมันปิด 4 โมง ซึ่งกว่าเราจะไปถึงกันก็บ่าย 3 แล้ว เขาเลยบอกว่าถ้าซื้อกางเกงว่ายน้ำ + ตั๋วค่าเข้าแล้ว พวกเราจะไม่คุ้มเพราะใช้เวลาแช่กันได้ไม่นาน แต่ตกลงไปตกลงมา สุดท้ายก็แช่กันที่นี่แหละครับ บ่อที่นี่จะเป็น บ่อ 3 ระดับความร้อน บ่อ Easy (ประมาณ 39 องศา) บ่อ Medium (ประมาณ 42 องศา) แล้วก็บ่อ Hard (ประมาณ 45 องศา) แน่นอนครับว่าด้วยความที่นิลไม่เคยแช่เลยเนี่ย นิลก็วิ่งไปบ่อ Easy ก่อน 555555 แต่แค่บ่อ Easy ก็ร้อนมากแล้วอ่า แช่ไปซักพักพอย้ายไป Medium ก็แบบลงทั้งตัวไม่ไหวเลย 55555 ประสบการณ์แช่น้ำร้อนครั้งแรก รู้สึกร้อนมาก ไม่เคยรู้สึกเหมือนโดนลวกแบบนี้ 55555 แต่ก็ดีครับ เหมือนได้ไปเปิดโลกเลย กลับไทยก็อยากจะลองพวกออนเซนอยู่ฮะะ พอแช่น้ำพุร้อนเสร็จก็นั่งรถไฟกลับกัน คนอื่น ๆ ก็กลับที่พัก ส่วนนิลก็อยากไปดูรองเท้า On Cloud เลยไปที่ร้าน Marathon’s World แถว ๆ CKS Memorial Hall ครับ แต่พอลองใส่จริงกลับรู้สึกแปลก ๆ อาจจะเพราะปกตินิลใส่ Skechers จนชินแล้วมั้ง แต่สรุปก็กลับออกจากร้านแบบมือเปล่าเลย แซด TT เสร็จแล้วนิลก็ไปกินชานมกับข้าวเย็นที่ Chun Shui Tang แถว ๆ ที่พักครับ แต่แอบผิดหวังนิดนึง จืดมากแต่คุณภาพชากับไข่มุกดีเลยครับ เสร็จจากร้านชานม นิลก็วิ่งกลับไปที่โรงแรมเพื่อเอากระเป๋าแล้วพุ่งตัวไปที่สนามบินครับ เย่ะ จบทริปด้วยสวัสดิภาพ ## สรุป ค่าเสียหาย Trip นี้ทั้งหมดประมาณ 22,000 บาทครับ แพงสุดคือค่าตั๋วเครื่องบิน ถูกสุดคือค่าน้ำเปล่า นิลไม่เสียเลยซักบาท นิลกรอกฟรีตั้งแต่สนามบิน ที่พัก ยันงาน Conference ก่อนออกมาเที่ยวก็กรอกตุนเต็มที่ตลอด ถือว่าสุดมากกับค่าน้ำเปล่า 55555 อีกอย่างที่ถูกกว่าที่ไทยคือค่ารถไฟฟ้าครับ นั่งไป 10 กว่าสถานียังประมาณ 40 บาทเอง สุดมาก คิดว่าทริปครั้งนี้เหมือนมาเปิดประสบการณ์ด้วยความที่มาเที่ยวเองครั้งแรกก็แอบมีความเหงา ความเหวงอยู่แหละ แต่โดยรวมก็ดีครับ อากาศดีด้วย 14 องศาเอง เดินเล่นสนุกมาก เดินวันละ 20,000 ก้าวแหนะ แอบเสียดายที่ไม่ได้ Plan มาดี ๆ และก็เสียดายเวลาที่นั่งทำงานระหว่างเที่ยวด้วย 55555 แต่ก็นั่นแหละ ทุกครั้งเราก็จะมีอะไรที่เสียดายไป แต่ก็ต้องปล่อยวางไปและเดินหน้าต่อไปแหละครับ คิดว่าอยากไปไต้หวันอีกครับ อาจจะแบบปีหน้า อยากกลับไปอีกรอบนึง เป็นประเทศที่ค่อนข้างดีครับ --- # สรุป Session - Positioning the Value of Human Understanding in Design - URL: https://blog.ninprd.com/blog/uxth2024-summary-positioning-the-value-of-human/ - Published: 2024-03-23 - Tags: conference, uxth, ux, Y2024 - Summary: สรุป Session: Positioning the Value of Human Understanding in Design ของคุณ Meena ในงาน UX Conference 2024 `Speaker: Meena Kothandaraman` ใน Session นี้ Meena พูดถึงการเข้าใจคน โดยเวลาทำ Product ใด ๆ ก็จะมีฝั่ง 2 ฝั่งนั่นคือ - **Consumers** (ผู้ใช้งาน) ซึ่งต้องการความเร็ว ความง่าย และความ Efficient ในการใช้งาน - **Producers** (ผู้สร้าง) ซึ่งต้องการ Context, Confidence, ความชัดเจน (ว่าผู้ใช้งานจะใช้งาน Product ของเรายังไง) และ Connection ซึ่งส่วนใหญ่เราจะไป Focus ที่การเข้าใจ Consumers แต่ว่าใน Session นี้จะ Focus ที่การคุยเกี่ยวกับฝั่ง Producers เป็นหลัก หลัก ๆ ที่ Meena พูดคือเรื่องการ Connect Consumers กับ Producers โดยส่วนใหญ่แล้ว เวลามีการทำ Product อะไร คน initiate ไอเดีย/เจ้าของ Product มักจะให้ทีม UX/UI ไปทำ Research เพื่อหา Insight/ข้อมูลเพิ่มเติม แต่ว่าตัวคนที่ Initiate/เจ้าของ Product มักจะไม่ได้ไปทำ Qualitative Research ด้วย ซึ่งจริง ๆ จะทำให้ระยะห่างระหว่าง Consumers กับ Producers ยิ่งห่างเข้าไปอีก นอกจากนี้ Producers หลาย ๆ คนก็จะชอบจบด้วยความคิดที่ว่าของ ๆ เรา**ดีพอแล้ว** ซึ่งแนวคิดแบบนี้จะทำให้ฝั่ง Producers รู้สึกสบายใจ แต่ไม่ได้ทำให้เรามั่นใจมากขึ้น และยิ่งทำให้ตัว Producers ยิ่งห่างจาก Consumers เข้าไปอีก Meena เล่าให้ฟังว่าเมื่อคนฝั่ง Producers รู้สึกว่าไม่ Connect กับ Consumers แล้ว ส่วนใหญ่คนก็จะลาออกจากองค์กร ซึ่งจะสร้าง Cost ให้องค์กรเพิ่ม (จาก Research ของ twig + fish ในปี 2018 การหาคนมาแทนจะใช้เงินประมาณ $70K-$100K) ซึ่งถือเป็นจำนวนเงินที่เยอะมาก Meena แนะนำ Process ของ twig + fish ที่เธอเรียกว่า “twig + fish 5-Phase Learning Process” โดยมีขั้นตอนดังนี้ 1. **Align**: Organize questions and study intent 2. **Plan**: Recruit and create protocol 3. **Gather**: Capture and debrief data/stories 4. **Analyze**: Synthesize and deconstruct insights 5. **Apply**: Develop final findings deliverable ซึ่งแต่ละ Process มีขั้นตอนดังนี้ ## 1. Align ออกแบบคำถามและประสบการณ์การถามซึ่งในฐานะของผู้ถึงสัมภาษณ์และเราแล้ว ไม่มีใครอยากมาสัมภาษณ์ด้วยคำถามปลายปิด เช่น พวก Yes-no Question แต่คำถามควรจะกระตุกจิตกระชากใจให้คิดหรือให้ได้ Insight เพิ่มเติม ให้เขาเล่า **Story** ออกมา สุดท้ายในขั้นตอนนี้เราควรจะได้ Intent และ Objective ของการทำ Research ครั้งนี้ ## 2. Plan ออกแบบประสบการณ์การสัมภาษณ์ อาจจะวางเป็น Ideal Process ก่อนและค่อยปรับมาเป็น Actual Process ที่เราจะไปทำเพราะถ้าไม่เริ่มเลย เราจะไม่ได้ทำมันซักที โดยเป้าหมายคือการออกแบบประสบการณ์การสัมภาษณ์ที่สนุกสำหรับเราและผู้สัมภาษณ์ ## 3. Gather ออกไปสัมภาษณ์ Users ซึ่งอย่าลืมที่จะพาฝั่ง Producers ออกมาทำการสัมภาษณ์ด้วย เพื่อรับฟังปัญหาหรือประสบการณ์การใช้งาน Product ที่ผู้ใช้งานกำลังเผชิญอยู่ โดยจะได้ฟัง Story จาก Users ในระดับที่เราออกแบบไว้ นั่นคือการฟัง Story หนึ่ง ๆ Story เกี่ยวกับ Product ของเรา และ Story ระดับ Ideal ที่คิดว่า Product เราจะไปถึง ## 4. Analyze นำข้อมูลที่เราได้จากขั้นตอน 3 มาวิเคราะห์และ Extract Information ให้ได้เพื่อเข้าใจเป้าประสงค์ของคำตอบมากที่สุด ## 5. Apply นำข้อมูลที่เราได้จากขั้นตอน 4 มา Finalize และส่งมอบสิ่งที่เราได้รับจากการไปทำ Research . ซึ่งเวลาเราได้ Insights, เรารู้สึกว่าได้ข้อมูลหรือเข้าใจผู้ใช้งานมากขึ้น เราจะรู้สึกตื่นเต้นและเริ่มคิดถึง Solutions ซึ่งก็จะทำให้เราสามารถพัฒนา Product ที่ฝั่ง Consumers รู้สึก Connect และใช้งาน Product ของเรามากขึ้น สุดท้าย Meena ฝาก Quote นึงไว้ว่า > Let us minimize the **“good enough”** mindset that distances producers from people. > > Meena Kothandaraman --- # ตะลุย WordCamp Asia 2024 กับนิลนิล - URL: https://blog.ninprd.com/blog/wordcamp-asia-2024-with-nin/ - Published: 2024-03-23 - Tags: conference, WordPress, wordcamp, Y2024 - Summary: สวัสดีครับ เมื่อวีคก่อนนิลมีได้ไปงาน Conference อันนึงมีชื่อว่า WordCamp Asia 2024 ครับ เป็นงาน Conference เกี่ยวกับตัว WordPress ซึ่งนิลตัดสินใจไปด้วยปัจจัย 2 อย่าง อย่างแรกคือตัวนิลเริ่มมีการใช้ WordPress มาซักระยะ นิลเลยมองว่าอันนี้เป็นเหมือนการหาความรู้ + โอกาสและ Connection ในโลก WordPress และอย่างที่สองคือนิลเครียดกับงานโปรเจคปัจจุบันมาก ทำให้นิลอยากพักครับ โดยตัวงานถูกจัดที่ประเทศไต้หวันครับ เป็น Conference ที่ระยะเวลา 3 วันถ้วน และที่สำคัญครับ นิลไปแบบ Solo เลย ไม่ได้ชวนใครไปเลยครับ 55555 แต่ละวันนิลเจออะไรบ้าง มาดูกันดีกว่าครับ สวัสดีครับ เมื่อวีคก่อนนิลมีได้ไปงาน Conference อันนึงมีชื่อว่า WordCamp Asia 2024 ครับ เป็นงาน Conference เกี่ยวกับตัว WordPress ซึ่งนิลตัดสินใจไปด้วยปัจจัย 2 อย่าง อย่างแรกคือตัวนิลเริ่มมีการใช้ WordPress มาซักระยะ นิลเลยมองว่าอันนี้เป็นเหมือนการหาความรู้ + โอกาสและ Connection ในโลก WordPress และอย่างที่สองคือนิลเครียดกับงานโปรเจคปัจจุบันมาก ทำให้นิลอยากพักครับ โดยตัวงานถูกจัดที่ Taipei International Convention Center (TICC) ประเทศไต้หวันครับ เป็น Conference ที่ระยะเวลา 3 วันถ้วน และที่สำคัญครับ นิลไปแบบ Solo เลย ไม่ได้ชวนใครไปเลยครับ 55555 แต่ละวันนิลเจออะไรบ้าง มาดูกันดีกว่าครับ ## Day 1: Contributor Day วันแรกของงานนะครับ จะเป็นวันที่เรียกว่า Contributor Day วันนี้จะต้องลงทะเบียนแยกจากตัว Conference ครับ ซึ่งจะเป็นวันที่ให้คนที่อยากสร้างประโยชน์/ทำอะไรซักอย่างให้กับ WordPress Team ได้มาลองลงมือทำจริงร่วมกับทีมงาน WordPress ครับ ซึ่งทำให้นิลรู้ว่า WordPress มีทั้งหมดอยู่ 14 ทีม ซึ่งประกอบไปด้วย - Accessibility: ดูแลเรื่อง Accessibility ของ WordPress Core - Community: ดูแลการจัด Meetup WordPress/สร้าง Community WordPress ตามที่ต่าง ๆ - Core / Core Performance: ดูแลเรื่องของ Feature หลักและ Performance ของ WordPress - Design: ดูแล UI ของ WordPress - Documentation: ดูแล Documentation ทั้งในฝั่งผู้ใช้งานและผู้พัฒนา - Marketing: ดู Marketing พวก Social Media, Digital Marketing, Analytics - Meta: ดู Software ของ WordPress.org, APIs และเครื่องมือต่าง ๆ เช่น Theme and Plugin Directories - Patterns: สร้าง Patterns ของ Block เพื่อให้ผู้ใช้งานสามารถ Copy/Paste ไปใช้ได้ง่าย ๆ - Photos: ดูแลรูปที่อยู่ใน Photo Directory ของ WordPress - Plugins: ดู Plugins ที่มีคน Submit มาว่ามีฝ่าฝืนกฎอะไรหรือเปล่า - Polyglots: ดูแลเรื่องการแปลภาษาของ WordPress - Support: ช่วยตอบคนที่ WordPress Support Forum - Themes: ดู Themes ที่มีคน Submit มาว่ามีฝ่าฝืนกฎอะไรหรือเปล่า - Training: ช่วยกันสร้าง Training Materials สำหรับงาน Event, ช่วยทำ Workshops ในวันนั้นเขาก็ให้แต่ละทีมมาอธิบายว่าทีมตัวเองมีช่วยพัฒนา WordPress ในส่วนไหนอยู่ครับ โดยคนที่มาพูดในแต่ละทีมจะเป็น Table Leads หรือว่าคนที่ประจำโต๊ะของทีมนั้น ๆ อยู่ ซึ่งพอฟังทุกทีมขึ้นมาพูดแล้ว นิลรู้สึกว่านิลอยากไปทำทีม Documentation ครับ ซึ่งทีมนี้จะเป็นทีมที่ช่วยกันเขียน Documentation หรือ User Manual ของ WordPress นั่นเอง โดยปัจจัยตัดสินใจของนิลคือนิลชอบการ Document ของอยู่แล้วกับอยากรู้ว่าทำไม Document ของ WordPress ถึงไม่ค่อยถูกอัปเดทเท่าที่ควร ![WordCamp Asia image, taken by Nin](assets/wordcamp-asia-with-nin-image-1.webp)

Image Taken By me

พอได้เข้าทีม นิลก็ได้เจอกับ Leo ซึ่งเป็นหนึ่งใน Table Leads ของทีม Documentation ครับ Leo ก็ได้พานิลเริ่มตั้งแต่สร้าง Account ที่หน้าเว็บ WordPress.org ซึ่งนั่นเป็นปัญหาแรกที่เจอในงานครับ หน้าเว็บส่วน Login โหลดโคตรช้า ตอนแรกนิลก็คิดว่าที่ Internet แต่ว่าพอเข้าหน้าเว็บอื่น ๆ มันก็เข้าได้ปกติ แต่หน้า Login ของ WordPress นั้นช้ามาก ทำให้เสียเวลาไปเกือบ ๆ ครึ่งชั่วโมงเลย ซึ่งพอสร้าง Account และ Login สำเร็จ Leo ก็ได้สอนวิธีที่จะ Contribute ให้กับทีม Doc ของ WordPress ครับ ซึ่งนิลก็ได้เรียนรู้วิธีและได้เริ่มสร้างประโยชน์แก่ WordPress เป็นครั้งแรก 5555 ยังไม่ทันไรก็ถึงเวลาข้าวเที่ยงแล้ว ด้วยความที่นิลมาแบบ Solo เลย นิลไม่รู้จักใครเลย Leo เลยพานิลไปนั่งด้วย บอกเลยว่าอาหารในงานโคตรอร่อย โซ้ยหมดด้วยความรวดเร็วและลืมถ่ายรูปมา 55555 ซึ่งในโต๊ะกินข้าวนั้น นิลก็เจอ Akira และ Milana ซึ่งเป็น Table Leads ของทีม Doc อีก 2 คน นิลก็ได้คุยกับ Akira เรื่องประเทศไทยเพราะปีที่แล้ว Akira มา WordCamp Asia 2023 ที่จัดที่ประเทศไทย เขาก็เล่าเกี่ยวกับการผจญภัยในกรุงเทพของเขา และเราก็เผาประเทศให้เขาฟัง 555555 อย่างมันส์ ส่วน Milana นั้นก็คอยแจกจ่ายขนมที่ตัวเองซื้อมาให้กับคนในโต๊ะกิน พอคนในโต๊ะไม่กินด้วย เขาก็เอาไปแจกโต๊ะอื่น ๆ ต่อ 555555 ซื้อมาเยอะเกิ๊นนน หลังจากที่อิ่มจนพุงกางนิลก็ได้ขอตัวออกมาเดินเล่นซักพักและกลับไป Join งานของทีม Doc ต่อซึ่งในตอนบ่ายนิลก็ได้เจอ Michael ซึ่งเป็นคนที่เพิ่งมาจอยโต๊ะนี้ตอนบ่ายมานั่งข้าง ๆ Michael เจอปัญหาเรื่อง Internet แต่อันนี้เป็นที่ Internet จริง ๆ Michael เลยชวนนิลคุยเรื่องว่าทำไมถึงมา WordCamp Asia รอบนี้ ทำไมถึงอยากมาจอยทีม Doc อะไรแบบนี้ นิลก็ตอบเหตุผลของนิลไป หลังจากนิลเล่าเหตุผลของตัวเอง นิลก็ได้ถามกลับไปว่าทำไมเขาถึงสนใจทีม Doc ซึ่งเหตุผลของเขาก็คือเขาอยากมาเรียนรู้การทำ Doc เพราะหลังจากจบงาน WordCamp เขาต้องกลับไปช่วยทำ Doc ให้กับบริษัท ความสนุกเริ่มต้นขึ้นเพราะว่าในโต๊ะนิลมีคนที่มาจาก GoDaddy และ Hostinger มาอยู่ซึ่งเขาเป็นคู่แข่งทางธุรกิจกัน ในระหว่างนั่งทำ Doc ก็ได้มีการเล่นมุขแบบ แซ่บ ๆ จิก ๆ กัด ๆ กันหลาย ๆ ครั้ง 55555 แต่พอตอนเล่นกันไปซักพัก Michael ก็พูดขึ้นมาและเป็นคำพูดที่นิลชอบมาก เขาพูดว่า > I really like this kind of event. Even though we are business rivals, during these 3 days of event, we’re friends. > > Michael ซึ่งทุกคนก็เห็นด้วยกับคำพูดนี้มาก ในวันนั้นนิลถึงกับรีบเข้าแอพโน๊ตไปจดคำพูดนี้เลยนะ 5555555 หลังจากนิลเสร็จงานส่วนแรกนิลก็ได้ไปคุยเพิ่มกับ Leo ถึงการทำงานของทีม Doc ของ WordPress นิลถึงได้รู้ว่าจริง ๆ แล้วทีม Doc ของ WordPress ไม่ได้เป็นทีมงาน WordPress แบบ Full Time แต่เป็นทีมงานจากบริษัทต่าง ๆ มาจอยกัน (ซึ่ง Leo ก็มาจาก Hostinger) และช่วย ๆ กันทำ Doc แหละ ซึ่งทีมงานก็มีประมาณ 20 คนและมีเวลากันขั้นต่ำคนละ 2 ชั่วโมงต่ออาทิตย์มาทำกันและด้วยความที่ WordPress มีการปล่อย Minor Release ปีละ 3 ครั้งและ Feature ที่มีการเปลี่ยนแปลงเยอะมาก ทำให้เขาทำไม่ทันกัน บางทีก็จะต้องเพิ่มในส่วน Feature ที่มาใหม่ก่อน ของเก่า ๆ ถึงไม่ได้ถูก Update เลย ซึ่งถ้าใครอยากเข้าไปช่วยเนี่ยก็สามารถเข้าไปตามในนี้ได้เลยครับ คิดว่าเป็น Starting Point ที่ดีในการเริ่มช่วยทีม Doc ครับ ใน Session นี้นิลได้ช่วย Proof Screenshots และ Content ของตัว Documentation เรื่อง Query Loop กับ Tag Cloud ครับ โดยหน้าเหล่านี้ถูกแก้ไขล่าสุดเมื่อมีนาปีที่แล้ว 😱😱 ซึ่งแค่ตรวจ 2 หน้าและ Capture รูปที่เป็นของใหม่ทั้งหมดก็หมดเวลาทำมาหากินอย่างไม่น่าเชื่อแล้วครับ จริง ๆ มีอีก Session ที่เขาจัดขึ้นใน Contributor Day ครับแต่นิลไม่ได้เข้าร่วมด้วยเพราะแค่ทำงาน Team Doc ก็หมดเวลาแล้ว ซึ่ง Session นั้นมีชื่อว่า “Human Library” ครับ Session นี้เป็น Session ที่จะมีคนที่ทำหน้าที่เป็น Librarian ที่สามารถตอบคำถามของที่เข้ามาถามได้ ตัวนิลคิดว่าเป็นไอเดียที่สุดยอดมากเลย ถ้านิลทำอะไรเร็วกว่านี้อีกนิดนึงนะ นิลอาจจะได้ไปลอง Session นี้เพิ่มเติมก็ได้ แต่ไม่ทันซะก่อน งานทับตัว 555555 จบวันไปนิลก็มีคุยกับ Leo เพิ่มขอ Connect เขาไว้ใน LinkedIn ด้วย Leo บอกว่าพรุ่งนี้เขาจะมาเป็นตากล้องให้กับงานนี้ เขาบอกว่าจริง ๆ ใครที่มีกล้องก็สามารถมาช่วยเป็น Staff ได้เลย แอบเสียดายที่ไม่ได้เอากล้องมาเลย 5555 และนิลก็ขอไป Contact Akira ด้วย ได้นามบัตรเขามาด้วยแหละ ส่วนนิลทัก Milana ไม่ทัน Milana ขยับตัวออกไปไวมากและก็นิลก็ไม่ได้คุยกับเขาเยอะด้วย เลยอดคุย อดขอ Contact เลย สิ่งที่นิลได้จาก Contributor Day คือนิลได้รู้จักคนเพิ่มเยอะมาก ซึ่งก็คือคนที่มาร่วม Contribute ในทีม Documentation แหละ ซึ่งมาจากหลาย ๆ บริษัทที่นิลเคยเห็นผ่านตา ไม่ว่าจะเป็น GoDaddy, Hostinger, Yoast, และ WPML รวมถึงได้รู้ว่า Process ในการจะ Contribute ให้กับ WordPress จริง ๆ แล้วไม่ยากเลย แค่เข้ามา Join ทางทีมก็พร้อมต้อนรับ นอกจากนี้ยังได้เข้าใจ Process การทำงานของทีมทีมนึงใน WordPress Team และเข้าใจว่าทำไม Doc มันถึงไม่ค่อยอัพเดท (ไม่ได้รู้สึกว่าโลกสวยนะ แต่เข้าใจเขามากขึ้นละกัน) – จบ WordCamp Day 1 – --- ## Day 2: Conference Day 1 วันนี้เป็นวัน Conference วันแรก ด้วยความที่นิลได้บัตรเข้างานตั้งแต่เมื่อวานแล้ว ทำให้วันนี้นิลไม่ต้องไปต่อคิวลงทะเบียนแบบคนอื่นเขาด้วย นิลเลยดิ่งไปซิบกาแฟในยามเช้าที่ร้าน Louisa Coffee ในตึกจัดงานครับ ในนั้นนิลก็นั่งทำงานอย่างอื่นไปเรื่อย ๆ และพบกับแก๊งค์ชาวไทยในร้าน ซึ่งหนึ่งในนั้นคือพี่จาบอนซึ่งเคยเป็น Consult ให้กับบริษัทนิลใน Project นึง นิลเลยได้คุยกับพี่จาบอนและพี่เขาเลยชวนนิลไปเข้ากลุ่ม Facebook ของชาวไทยและไปกินข้าวกับแก๊งค์ชาวไทยหลังจากจบงานวันนี้ นิลก็ตอบตกลงไปแบบไม่ได้คิดอะไรเพราะตัวนิลก็อยากมาหา Connection อยู่แล้วด้วย อันนี้ก็อาจจะเป็นโอกาสอันดีที่จะได้รู้จักคนเพิ่มแหละ หลังจากแยกกับชาวไทยที่ร้านกาแฟมา นิลก็ได้เข้า Hall เพื่อฟัง Opening Keynotes ตามตารางเลยครับ โดยนิลสรุปมาได้เป็นประเด็นประมาณนี้ครับ - ตอนนี้ WordPress เป็น 43% ของ Website ทั่วโลก - ยอดการใช้งาน WordPress เพิ่มทุกปี - คน Supply เพิ่ม แต่ Demand ไม่โตตาม แปลว่าตอนนี้ Supply (WordPress Developer) ในท้องตลาดกำลังแย่งงานกันอยู่ - WordPress เมื่อก่อนเคยโดนตราหน้าว่าเป็น Monolith CMS แต่ก็สามารถสร้าง S-Curve และเติบโตมาได้จนถึงทุกวันนี้ และตอนนี้ WordPress กำลังเปลี่ยนตัวเป็น Composable CMS และกำลังหา S-Curve ใหม่ - ตอนนี้ตลาดยังไม่รู้ Capabilities ทั้งหมดของ WordPress ในฐานะของ WordPress Developer ควรจะทำให้ท้องตลาดเข้าใจและอยากใช้ Solution ที่เป็น WordPress มากขึ้น - Guideline ตัวอื่น ๆ ในท้องตลาดดูง่ายกว่า Doc ของ WordPress - อยากทำ Integration Directory สำหรับ WordPress เพื่อให้สามารถเริ่ม Project ได้ง่าย ๆ เหมือนพวก Frontend Framework สมัยใหม่ - ใน Service ยุคใหม่ ๆ อาจจะต้องเอา WordPress ไป Plug กับ Service อื่น ๆ เพื่อทำให้ WordPress กลับมาเป็นผู้นำตลาดอีกครั้ง ![Noel Tock on the stage in WordCamp Asia 2024, taken by Nin](assets/wordcamp-asia-noel-tock.webp) พอจบ Session Keynote ทุกคนก็ปรบมือกันลั่น Hall เลย ส่วนตัวนิลก็แบบ อะไรวะเนี่ย ข้อมูลเป็นล้าน 5555555 พอฟัง Keynotes เสร็จนิลก็ได้เข้าไปฟัง Session ต่าง ๆ (ส่วนสรุป Session ต่าง ๆ นิลขอเอาไว้เขียนแยกเป็นอีก Blog นะไม่งั้นเยอะเกิน) พอถึงพักเที่ยงนิลก็ได้เจอกับพี่ไทแห่ง BKK.JS หลังจากนั้นนิลก็ทำเสมือนเล่นเกมและเปิด Bot เลย นิลก็เป็น Bot เดินตามพี่ไทเลยเพราะนิลไม่รู้เลยว่าถ้ามางาน Networking แบบนี้ นิลจะต้องทำตัวยังไง พี่ไทก็พานิลไปนู่นนี่นั่น พาไปกินข้าว เปิดบทสนทนาในโต๊ะกินข้าว จนสุดท้ายนิลก็ผ่านมื้อเที่ยงที่ต้องคุยกับคนแปลกหน้าหลายคนได้ (p.s. ข้าวเที่ยงวันนี้ไม่ค่อยอร่อยอะ ฮืออออ) นอกจากนั้นพี่ไทยังพานิลไปเจอกับชุนซึ่งชุนเป็นคนที่ร่วมทำ Commu ฝั่ง JavaScript กับพี่ไทมา พี่ไทบอกว่าชุนเป็น Indie Hacker และกำลังทำโปรเจค [https://learnalgorithm.com/](https://learnalgorithm.com/) นิลก็ตกใจมากแบบ เชี่ยย นี่แม่งบุคคลที่แบบโคตรตึง โคตรโหด โคตรอันตราย ก็ได้ทำความรู้จักกับชุนที่ตรงนั้นครับ แต่ก็ได้คุยแปปเดียวเพราะว่า Session บ่ายกำลังจะเริ่มแล้ว หลังจากนั้นนิลก็เข้า Session บ่ายปกติไป ซักพักนึงพี่ไทก็เดินมาบอกว่าเดี๋ยวบ่าย 3 คนไทยมีรวมตัวกันถ่ายรูปรวม ตอนแรกนิลก็สองจิตสองใจเพราะว่าในตอนแรกนิลก็ไม่อยากพลาดซัก Session เลย แต่ยังไงก็ตาม นิลก็เลือกที่จะมารวมตัวกับคนไทยคนอื่น ๆ เพราะอยากรู้ว่าคนไทยมากันเยอะไหม พอรวมตัวกันครบ ก็ได้รู้ว่าคนไทยมากันเยอะมาก เกือบ 30 คนแหนะ แต่แค่ทีมงาน Seed Webs ก็ล่อไป 10 คนแล้ว ยังมีทีมงานจากมหาวิทยาลัยเชียงใหม่อีก รู้สึกว่าเปิดโลกมากเลย ได้คุยกับพี่เม่นกับทีมงาน Seed Webs ด้วย ทุกคน Friendly มากเลยแหละ ปลาบปลื้มใจมาก ตอนแรกคิดว่าจะ Connect กับคนอื่น ๆ ยากกว่านี้ ![A photo of P'Menn from SeedWebs and Nin, taken by Junior from SeedWebs](assets/pmen-and-nin.webp)

Image of Nin and P'Men by Junior from Seed Webs Team

![A photo of Thai people at WordCamp Asia 2024, taken by WordPress Staff](assets/wordcamp-asia-2024-thai-people.webp)

Image of Thai people at WordCamp Asia 2024, taken by WordPress Staff

พอถ่ายรูปรวมชาวไทยที่ WordCamp Asia กับเม้ามอยเสร็จ นิลก็จะกลับไปฟัง Session อื่น ๆ พี่ไทยก็มาบอกนิลว่า Session พวกนี้มีปล่อยฟรีบน YouTube ถ้ามาแค่ฟังอย่างเดียว โดยไม่ได้มีคำถามไปถามคนพูดหรืออยากไป Connect คนพูดแล้ว ก็เหมือนเสียค่าบัตรฟรี เอาเวลาไปคุยกับคนในงานหรือ Sponsor Booth ที่ตั้งอยู่ในงานดีกว่า นิลก็มานั่งคิดไปคิดมาละเห็นด้วย แต่ด้วยความที่นิลเข้าหาคนไม่เก่ง นิลจึงเลือกที่จะไปลองคุยกับ Booth Sponsor และ Booth แรกที่นิลเข้าไปคุยคือ Booth ของ Elementor ซึ่งเป็น Page Builder Plugin ที่นิลใช้กับ Project ล่าสุด นิลได้คุยกับ Rami ซึ่งเป็นหนึ่งในทีมพัฒนา Elementor เขาก็ให้คำแนะนำเกี่ยวกับการใช้มาและเขาก็พูดปัญหาที่ตอนนี้ Elementor กำลังเจอ นั่นคือการ Backward Compatability ของต่าง ๆ ไม่ว่าจะเป็น Icon Pack หรือ php version เพื่อ Support ผู้ใช้งาน 16 ล้านคนทั่วโลก (เยอะมากกกก) นอกจากนี้นิลยังถามเรื่องการพัฒนา Feature ว่าเขามี Strategy ยังไง Rami เลยตอบนิลว่า 1 ใน Strategy คือดูใน Github Issues ว่ามีคน Feature Request อะไรและมีคนเข้าไป Like หรือ +1 กันเยอะไหม ซึ่งก็แอบตกใจเหมือนกันว่าทำไมถึงไม่ได้เป็นการ Drive Feature จากทีมมาด้วย แต่นิลก็ไม่ได้ถามเหตุผลเพิ่มเติมไป จบ Booth นี้นิลก็ได้หมวก Elementor มาใบนึง 555555 จริง ๆ หลังจากจบ Booth Elementor นิลมีแวะ Booth ของ Woo, Google, ละก็ GoDaddy แต่ก็ไม่ได้มีอะไรเยอะมากจนนิลจะเขียนได้ 555555 หลังจากจบงานนิลก็มีไปรวมกับพี่ไทอีกครั้งเพื่อรอกินข้าวชาวไทย แต่ว่าพอรู้ว่าจะไปรวมตัวแบบคนเยอะนิลแอบกลัวนิดนึง (ไม่ค่อย Comfort กับการอยู่ในวงสนทนาที่มีคนเยอะ รู้สึกทำตัวไม่ถูก) พี่ไทก็มาถามนิลว่าสนใจไปกินแยกอีกกลุ่มนึงไหม นิลก็ตอบตกลงไปและไปกับพี่ไทกับชุนไปเดินตลาดกลางคืนแห่งหนึ่ง เดินไปกินไป เงินอย่างไหลเลย ละนิลก็เดินไปเจอชานม 50 Lan ที่อยู่ใน List ชานม นิลก็รีบโดดไปสั่งไปกินทันที แต่กลับเศร้ามากเพราะสั่งชานมไข่มุก Size M แต่ได้ชานม Size L ที่ไม่มีไข่มุก 🥺 พอเดินกันเสร็จก็มีไปเดินคุยกันในสวน ZhongShan ต่อฮะ รู้สึกวงสนทนาใกล้ชิดดีครับ เสร็จแล้วก็แยกย้ายกันไปพักผ่อน – จบ WordCamp Day 2 – --- ## Day 3: Conference Day 2 วันนี้นิลตื่นสายย แต่ตื่นก็ 9 โมงแล้วไอบ้าเอ้ย สุดท้ายนิลก็มาถึงงานประมาณ 9 โมงครึ่งและพุ่งตรงไปที่ Session ที่นิลสนใจ นั่นคือ “Fighting the JavaScript Fatigue: Picking the right framework for Headless WordPress” ซึ่งเป็น Session ของภูมิ ซึ่งเป็นชาวไทยที่นิลติดตามเพจเขามาซักพักใหญ่ละ พอนิลไปถึงที่ห้องจัด Session นิลก็ได้เจอกับภูมิที่ยืนอยู่หน้าห้อง นิลก็เข้าไปคุยกับภูมิ ซึ่งภูมิ Friendly มากกก พอคุยกันซักพักก็ถึง Session ของภูมิ ภูมิขึ้นไปพูด นิลไปนั่งฟัง ฟังแล้วแบบ โอ้โหหห โคตรเก่ง พูดโคตรดี ภาษาอังกฤษอย่าง Flow เลย พอจบ Session ภูมิ นิลก็ได้คุยกับคณะอาจารย์จากมหาวิทยาลัยเชียงใหม่ เขาเหมือนสนใจเกี่ยวกับการ Training/Course Online ของ Skooldio เลยมาขอ Contact นิลไว้ แอบทำตัวไม่ถูกนิดนึง 55555 พอจบ Session ของภูมิก็ได้ไปฟัง Session ของพี่เพิร์ธต่อ เป็นหัวข้อเรื่อง “Multiply your income streams with WordPress development skills” ซึ่งบอกเลยว่าดีมากก เป็น 10 นาทีที่มีประโยชน์กับชีวิตมากเลย ซึ่งพอจบ Session พี่เพิร์ธนิลก็ออกไปเดินเล่น Sponsor Booth ต่อ พอเดิน Sponsor Booth ตอนเช้าเสร็จก็ถึงเวลาข้าวเที่ยงแล้ว วันนี้นิลกับพี่ไทยแยกตัวกันไป ทำให้นิลต้องฝึกการเข้าสังคมเอง 55555 แต่นิลก็กลับไปนั่งโต๊ะเดียวกับเมื่อวานและเจอคนเดิมที่นั่งอยู่ รอบนี้นิลก็ได้คุยกับเขามากขึ้น ซึ่งด้วยเขาเป็นคนไต้หวัน ตอนแรกก็ได้คุยเกี่ยวกับการทำ Personal Blog, งานประจำของแต่ละคน แต่พอซักพักนึงนิลก็คุยเรื่องที่พัก เขาก็คุยเรื่องเกี่ยวกับไต้หวันมากขึ้น เขาแชร์ว่าตอนนี้ค่าที่พักในไต้หวันสูงขึ้นมาก ตัวเขาเลยไปอยู่แถวชานเมืองและเดินทางเข้ามาเพราะค่าเดินทางนั้นรวม ๆ แล้วถูกกว่าค่าที่พัก นิลก็ช็อค ๆ ไปแปปนึง หลังจากนั้นเขาก็แนะนำนิลไปกินร้าน Din Tai Fung เขาบอกนิลว่ามันเป็น Foreigner’s Must Eat เลย (แต่สรุปแล้วนิลไม่ได้กิน คนแม่งเยอะไม่ไหวว) พอแยกย้ายหลังข้าวเที่ยง นิลก็เดินสาย Sponsor Booth ต่อ นิลไปเดิน Booth ของ Hostinger ซึ่งมี Leo ที่เป็น Table Leads ที่ทีม Doc อยู่ นิลก็เข้าไปคุยกับคนใน Booth และคุยเรื่อง Hosting ของ Hostinger ด้วยหลัก ๆ คือนิลอยากรู้ว่า Hosting ของ Hostinger มันดีกว่าเจ้าอื่นยังไง โดยสรุปแล้วคือนิลมองว่าตัว Infra ก็อาจจะคือ ๆ กับเจ้าอื่นแต่ Hostinger นั้นมีการทำ UI ของ Backoffice ที่ใช้ Manage การ Hosting สวยมากและมีการพัฒนา AI มาช่วยเขียน Blog ซึ่งแค่ใส่หัวข้อมันก็จะ Generate เนื้อหามาให้ ฟังละแบบ โคตรโกงเลย 55555 ตัวนิลซึ่งกำลังมองหา Hosting WordPress อยู่ก็ได้ถามซอกแซกเขาไปเรื่อยจนเขาให้ Hosting Free มาปีนึง ให้เมล็ดกาแฟมาถุงนึง ให้ผ้าเช็ดจอคอมแล้วก็ให้ถุงผ้ามาอีก พูดเลยว่าให้มาอย่างคุ้มเลยครับ นิลก็น้อมรับด้วยความยินดีมาทุกอย่างเลย อิอิ และแล้วก็มาถึง Session Q&A with Matt, Co-Founder ของ WordPress ซึ่งนิลรู้สึกชอบ Session อะไรแบบนี้มาก จริงใจสุด ก็มีคนมีคำถามจะถาม Matt เยอะมาก และ Matt ก็ตอบอย่างดีทุกอันด้วย ตัวนิลก็เสียดายนิดนึงเพราะจริง ๆ ก็มีคำถามที่อยากถามเหมือนกัน แต่คนถามเยอะเกิน แย่งไม่ไหว TT นอกจากนี้ Matt ยังประกาศอีกว่าจะมีงาน State of The Word ซึ่งจะเป็นงานที่เกี่ยวกับการอัพเดท WordPress ที่กรุงโตเกียว ประเทศญี่ปุ่นแหละ 🤩 พอ Matt พูดเสร็จก็มีประมวลภาพจบ WordCamp Asia 2024 และก็ประกาศว่าปีหน้า [WordCamp Asia 2025](https://asia.wordcamp.org/2025/) จะจัดที่ประเทศฟิลิปปินส์ 🥳🎉 นอกจากนี้ก่อนจบงานเขาก็ประกาศว่าจะมี After Party ที่ MAJI Square ด้วยซึ่ง Party จะเริ่มตอนทุ่มนึงครับ โดยมีอาหารฟรี เครื่องดื่มฟรี (หูผึ่งตรงนี้ 5555) ![Image of Matt on stage, taken by Nin](assets/wordcam-asia-2024-matt.webp)

Image of Matt on stage, taken by me

![Image of Nin, taken by Chun Rapeepat](assets/wordcamp-asia-2024-me.webp)

Image of me by Chun Rapeepat

หลังจากจบ Session ก็จะเหลือเวลาประมาณ 2 ชั่วโมงก่อนจะเริ่ม Party ครับ นิลก็เลยไปเดินเล่นกับชุน เดินจากงาน WordCamp ไปที่ National Theatre and Concert Hall (ระยะทาง 4.6 กิโล) ระยะทางแบบบ้าบอมาก ระหว่างทางก็ได้คุยสัพเพเหระไปเรื่อย เดินไปประมาณชั่วโมงกว่าก็ถึงที่หมาย นิลก็แยกกับชุนและเดินไปที่พักนิลต่อ (อีก 2 โล) เดินให้ขาพังไปเลย 5555555 พอถึงที่พักนิลก็ทุ่มกว่าแล้ว นิลเลยเข้าไปอ่านข้อความชาวไทยที่ถึงที่งานแล้วว่าบรรยากาศงานเป็นไงบ้าง ก็เห็น Feedback เหมือนงานค่อนข้างเสียงดัง + คนเยอะ + เน้นแอลกอฮอล์ซึ่งตัวนิลไม่ค่อยชอบปัจจัยเหล่านี้ ตอนแรกนิลจะไม่ไปละ แต่พี่ไททักมาบอกว่ามาก่อนละถ้า Social Energy หมดค่อยไปเดินสวนเล่นกัน นิลเลยไป (โดนล่อด้วยการเดินสวน 555555) พอไปถึงที่งานนิลก็ได้เจอกับพี่ไท ชุน และภูมิอีกครั้งนึง โดยพอนั่งในงานไปซักพักพี่ไทก็ชวนชุน ภูมิ นิลไปเดินสวนใกล้ ๆ งาน ก็ได้เดินไปคุยไปกินไป เป็น Session การคุยที่ยาวนานมากถึง 4 ชั่วโมงและเต็มไปด้วยการเรียนภาษาที่สุดมันส์ โคตรโหด โคตรอันตราย ไม่เกิน 3 ชั่วโมงพวกเราก็สามารถพูดภาษาจีนได้อย่างไม่น่าเชื่อ 555555 ประมาณตี 1 ครึ่งก็เดินไปส่งชุนที่โรงแรมและก็นั่ง Uber กลับโรงแรม จบวันเดินไป 20 โล บ้าพลังขั้นสุดยอด 55555 – จบ WordCamp Day 3 – --- โดยรวมนิลมองว่าการมาจอย WordCamp Asia ของนิลรอบนี้เป็นการเปิดโลกนิลมาก ตั้งแต่การมาต่างประเทศคนเดียวครั้งแรก การเข้าร่วม Contributor Day การไป Connect กับชาวไทย ชาวต่างชาติในงาน การเดินคุยกับ Sponsor หลาย ๆ อย่างมันดูใหม่สำหรับ Software Engineer คนนึงที่นั่งทำงานหงก ๆ ในออฟฟิศแล้วไม่ได้ออกไปงานไหนเลยแหละ ถ้าใครรู้สึกว่าอยากออกมาหาประสบการณ์ใหม่ ๆ การมางาน Conference อะไรแบบนี้ก็น่าสนใจดีนะครับ แต่อาจจะต้องมากับเพื่อนนิดนึง กันเหงา กันเคว้ง โดยรวมนิลว่ามันสนุกดีนะครับ นอกจากนี้ใครอยากดูไลฟ์ย้อนหลังของงานก็สามารถเข้าไปดูได้ที่ [Youtube: WordPress](https://www.youtube.com/@WordPress/streams) ได้เลยครับ มี Conference ย้อนหลังทุก Session เลยครับ หวังว่าการแชร์ประสบการณ์ครั้งนี้จะเป็นประโยชน์กับคนอ่านนะครับ ให้สมกับเป็น Content ราคาแพงที่ต่างแดนนะครับ ถ้าชอบก็สามารถมาพิมพ์ Comment ทิ้งไว้ที่เพจได้นะะ [เพจ:ตากล้องที่เขียนโค้ดได้นิดหน่อย](https://www.facebook.com/profile.php?id=61555700437640) สำหรับวันนี้ลาไปก่อน สวัสดีครับ ขอให้สนุกกับการไป Conference เย่ะ ๆ – นิล – --- # สรุป Session - The Future of Design Teams จากงาน UXTH2024 - URL: https://blog.ninprd.com/blog/uxth2024-summary-future-of-design-trends/ - Published: 2024-03-22 - Tags: conference, Y2024, uxth, ai, ux - Summary: สรุป Session: The Future of Design Teams ของพี่นน Senior Designer ที่ ทีม Beacon Interface ของ KBTG ในงาน UX Conference 2024 ## The Age of AI พอเราเข้าสู่ยุคคอมพิวเตอร์ ทุกสิ่งถูกแปลงข้อมูลเป็น Data และถูกนำไปให้ AI ในยุคปัจจุบันเรียนรู้ ซึ่งในตอนนี้ AI เปรียบเสมือนเด็กคนนึงที่กำลังเติบโตเป็นผู้ใหญ่ พี่นนพูดถึง AI หลัก ๆ 2 ตัวคือ Predictive AI ซึ่งจะเป็น AI ที่ใช้ในการ Predict สิ่งต่าง ๆ แต่ไม่มี UI หรือ Feedback กลับมาหาผู้ใช้ กับ Generative AI ที่เราใช้กันทุกวันนี้ เช่น ChatGPT ซึ่งมีเบื้องหลังของมันคือ Large Language Model (LLM) เรียกได้ว่าพวก LLM นี่เป็นผู้เชี่ยวชาญด้านภาษา ในยุคนี้ บริษัทยักษ์ใหญ่ต่าง ๆ พัฒนา AI ของตัวเองโดยแข่งกันด้วยแง่มุมของ Speed, Capability, Cost, Easy to use, Specialized และ Integrated ## Types of model - ข้อความ -> ข้อความ: LLMs เช่น ChatGPT, Gemini - ข้อความ -> ภาพ: เช่น Midjourney, Stable Diffusion, Bing - ภาพ -> ข้อความ: เช่น Midjourney - ข้อความ -> วิดีโอ: เช่น Sora โดย OpenAI - Multimodal Model -> การใช้หลายโมเดล AI ร่วมกัน เรียกว่า “CustomGPT” ## Mindset towards AI การมี Positive Mindset ต่อ AI เป็นสิ่งสำคัญ โดยควรมองว่า AI ช่วยให้เรามีประสิทธิผลมากขึ้น แทนที่จะมีทัศนคติที่ปฏิเสธหรือตื่นตระหนกว่า AI จะแย่งงานของเรา ## UX Use cases - การใช้ Perplexity แทนการ Search จาก Search Engine เพราะตัว AI มันเร็วและมีการบอกแหล่งที่มาข้อมูลเพื่อช่วยเพิ่มความน่าเชื่อถือ และแสดง Related Questions ที่ให้เราสามารถถาม Follow-Up Question ที่เกี่ยวข้องกับคำถามแรกที่เราถามไปได้ - อีกตัวอย่างคือแอป Sleep Cycle เมื่อจ่ายตังค์จะมี SleepGPT ซึ่งเราสามารถถามคำถามเกี่ยวกับการนอนของเราและตัว AI จะ Summarize และ ตอบให้ สิ่งนี้จะมีประโยชน์เมื่อเวลาแอปออกแบบมาแล้ว UI ใช้งานยาก กดหาข้อมูลยาก ข้อมูลเยอะและทำให้ดูยาก etc. ซึ่งในมุมพี่นนถือเป็นการ Value Added ให้กับแอป ## Design Guideline Google มีออก Guideline เพื่อช่วย Guide การพัฒนา Feature AI ภายใน Digital Product/Platform ของเรา ชื่อ [People + AI Guidebook](https://pair.withgoogle.com/guidebook/) อยู่ สามารถไปอ่านกันได้ ## ตัวอย่างการใช้งานจากทีม Beacon Interface - ตอนนี้ Communication Designer เริ่มมีการใช้ Midjourney เพราะลดปัญหาค่า License ได้ดี - ตอนนี้ User Researcher มีการใช้ ChatGPT + Gemini มาช่วยสรุปผล Research แต่ต้องระวัง Sensitive Data อย่าลืม Clean ก่อนเอาไปใช้งานกับ Generative AI - ถ้ามีสิทธิ์การใช้งาน Copilot ในรูปแบบขององค์กร สามารถเอา Sensitive Data ขึ้นไปใช้งานได้เลย โดยที่ Copilot จะใช้งานและแชร์ข้อมูลแค่ภายในองค์กรเท่านั้น นอกจากนี้ยังสามารถเก็บข้อมูล Train ในฐานข้อมูลของมันเพื่อเอาไปใช้งานภายหลังได้ด้วย - ส่วน UX/UI Designer ตอนนี้กระแส AI ยังเงียบ ๆ แต่ให้รอดูกลางปีเพราะว่า Figma เพิ่ง Acquire บริษัทชื่อ Diagram ไป ต้องรอดูว่าจะมีอะไรเจ๋ง ๆ มาไหม ## Speaker’s Prediction - AI จะย้ายการแข่งขันจาก On Cloud ไป On Device มากขึ้น aka. **EDGE AI** - คนจะไปค้นหากับ Generative AI มากขึ้น - คนที่ไม่สามารถส่งมอบงานที่เหนือกว่า AI Generate ขึ้นได้จะ**ตกงาน** - คนจะโหยหาและให้คุณค่ากับ Craftsmanship หรือผลงาน Craft โดยมนุษย์มากขึ้น สุดท้ายพี่นนฝาก Quote ทิ้งไว้ว่า > AI draft, Human craft > > Facebook: Chongo Visavayodhin แปลว่า AI นี่แหละที่จะมาช่วยเรา Draft งานในเกรด B หรือ B+ และเราก็จะเป็นคน Craft งานให้มันเป็นเกรด A ดังนั้นถ้าใครที่ Craft งานไม่ผ่านคุณภาพของ AI คุณก็จะตกงานนั่นเอง --- # ตามรอยชานมไต้หวัน 2024 - URL: https://blog.ninprd.com/blog/taiwan-boba-milk-tea-2024/ - Published: 2024-03-16 - Tags: experience-sharing, boba-milk-tea, Y2024 - Summary: เอาล่ะ วีคก่อนนิลไปไต้หวันมาครับแล้วก็มีโอกาสได้ไปกินชานมร้านต่าง ๆ ตาม Guide หลาย ๆ ที่มา นิลเลยอยากจะเขียนร่องรอยประวัติศาสตร์เอาไว้นิดนึงครับ ในนี้จะเป็นความเห็นส่วนตัวของนิลเรื่องชานมนะครับ ส่วนตัวแล้วนิลชอบทานหวานครับ ใครเห็นต่างหรือคิดยังไง Comment บอกกันได้ครับ ส่วนการตามรอยของนิลจะเป็นยังไงไปดูกันเลยครับ เอาล่ะ วีคที่ผ่านมานิลไปไต้หวันมาครับแล้วก็มีโอกาสได้ไปกินชานมร้านต่าง ๆ ตาม Guide หลาย ๆ ที่มา นิลเลยอยากจะเขียนร่องรอยประวัติศาสตร์เอาไว้นิดนึงครับ ในนี้จะเป็นความเห็นส่วนตัวของนิลเรื่องชานมนะครับ ส่วนตัวแล้วนิลชอบทานหวานครับ ใครเห็นต่างหรือคิดยังไง Comment บอกกันได้ครับ ส่วนการตามรอยของนิลจะเป็นยังไงไปดูกันเลยครับ ## 1. Xing Fu Tang ร้านนี้เป็นร้านแรกที่ได้ลองเลยครับ นิลได้ไปลองที่บริเวณ Ximending Night Market ซึ่งตอนแรกที่อ่านมาดูเหมือนคิวจะยาวครับ แต่นิลน่าจะโชคดี ไปวันที่คนน้อยพอดี นิลลองตัวชานมที่เป็นตัว Best Seller ของเขาเลยครับซึ่งก็คือ “**Brown Sugar Milk Tea**” ครับ รีวิวจากใจจริงนิลเลยคือรสชาติหวานกำลังดีแต่นิลแทบไม่ได้กลิ่นชาเลยครับ รู้สึกเหมือนนมล้วนมาก ๆ ตัดคะแนนตรงนี้แล้ว 1 ต่อไปส่วนของไข่มุก ตัวไข่มุกเป็นแบบลูกใหญ่ครับ ส่วนตัวนิลว่ามันนิ่มแปลก ๆ แต่ก็ไม่ได้นิ่มขนาดร้านถูก ๆ ในไทยนะครับ แต่ยังไงก็ดี รู้สึกว่ายังไม่โดน ผนวกกับ Layer ด้านบนที่นิลไม่มั่นใจว่ามันคืออะไร (แต่คล้าย ๆ ชีส) ซึ่งส่วนตัวแล้วนิลไม่ชอบอยู่แล้วครับ ดังนั้นการมาลองร้านนี้สำหรับนิลคือแอบผิดหวังนิดนึง แต่ยังไงก็ดี ถ้าใครชอบรสชาติหวานพอดี ไข่มุกไซส์ใหญ่และก็ Layer นัว ๆ ด้านบน ร้านนี้ก็เป็นตัวเลือกที่ดีครับ ![Picture of Xing Fu Tang, taken by Nin](assets/taiwan-boba-milk-tea-2024-xing-fu-tang.webp) ราคา: 120 NTD สถานที่ตั้ง: [https://maps.app.goo.gl/eacg1f22xb497mcE9](https://maps.app.goo.gl/eacg1f22xb497mcE9) ## 2. 50 Lan ร้านนี้เป็นร้านที่นิลเดิน ๆ อยู่แล้วก็เจอครับ นิลจำ Location ไม่ได้ละ แต่ว่าร้านนี้หาได้ตามทั่วไปเลยครับ คิวไม่ยาวด้วย นิลลองเป็นตัว OG ของเขาเลยครับ ตัว “**Milk Tea with Small & Large Bubble**” หวาน 100% Size M ครับ สั่งครั้งแรกก็ได้ Content เลยครับ นิลสั่ง M แต่ว่าได้ L แค่นั้นยังไม่พอ สั่งใส่ไข่มุก แต่ไม่ได้ไข่มุก นี่โกรธมาก 😡 แต่โดยรวมนิลมองว่ารสและกลิ่นของชาค่อนข้างเบาครับ ทานง่ายดี แนะนำถ้ากินชาแบบไม่ใส่ไข่มุกกิน M ก็พอครับ L นี่แอบเยอะไปนิดนึง ![Picture of 50 Lan for the first try, taken by Nin](assets/taiwan-boba-milk-tea-2024-50-lan-1.webp) ราคา: 50 NTD ## 3. 50 Lan (รอบ 2) หลังจากไปทำการบ้านมา นิลเจอว่ามีร้านนี้เปิดอยู่แถว ๆ ที่พักที่นิลไปอยู่ครับ นิลเลยรีบพุ่งตัวไปกินเลยครับ รอบนี้นิลก็ซ้ำเมนูเดิมครับ “**Milk Tea with Small & Large Bubble**” หวาน 100% Size M ด้วยความคาดหวังว่ารอบนี้จะมีไข่มุกมาให้ 555555 รอบนี้ค่อนข้างกลมกล่อมมากขึ้นครับ อย่างที่บอกไปว่าตัวชาก็ค่อนข้างเบาและตัวนมก็โอเค โดยรวมแล้วก็คือทานง่ายมาก และที่ชอบอีกอย่างคือไข่มุก 2 ขนาดที่ผสมกันอยู่ มันมีความ Dynamic อยู่ข้างในอะ นิลรู้สึกว่ามันมีลูกเล่นมาก ชอบมากกก 55555 ![Picture of 50 Lan for the second try, taken by Nin](assets/taiwan-boba-milk-tea-2024-50-lan-2.webp) ราคา: 50 NTD สถานที่ตั้ง: [https://maps.app.goo.gl/CRF1hwFzJVRPJRY16](https://maps.app.goo.gl/CRF1hwFzJVRPJRY16) ## 4. Chun Shui Tang ร้านนี้เป็นร้านสุดท้ายที่ได้ลองเพราะว่านิลวันก่อนกลับนิลรู้สึกท้องไส้ไม่ค่อยดี ทำให้นิลเลือกที่จะไม่กินนมเข้าไปเร่งปฏิกิริยาเพิ่มครับ ถ้าเอาในเชิงประวัติศาสตร์นิดนึง ร้านนี้เป็นร้านต้นตำรับชานมของโลกเลยนะครับ ตัวนิลแอบมีความคาดหวังกับการกินชานมที่นี่อย่างมากครับ นิลสั่งตัว “**Pearl Milk Tea**” และแน่นอนครับ หวาน 100% ครับ ส่วนตัวแอบผิดหวังเพราะมันไม่หวานเลย ตรง ๆ คือจืดเลยแหละครับ แต่ถ้าเอาในส่วนของชากับตัวไข่มุกนี่ดีเลยครับ ตัวชากับนมค่อนข้างเจ๋งแจ๋ว โคตรนัว ส่วนตัวไข่มุกก็มีความหนึบและไม่นิ่มเหมือนไข่มุกถูก ๆ ครับ รู้สึกว่ามีความมันความนัวที่ค่อนข้างดีเลย ยังไงใครมาไต้หวันก็แนะนำให้ลองครับ ด้วยประวัติศาสตร์เอย คุณภาพเอย นิลว่าโอเคเลยครับ ![Picture of Chun Shui Tang, taken by Nin](assets/taiwan-boba-milk-tea-2024-chun-shui-tang.webp) ราคา: 100 NTD (ยังไม่รวม VAT หรือ Service Charge อีก 10% นะ // นิลไม่ชัวร์ว่า VAT หรือ Service รู้แต่โดนเพิ่ม 10% ฮะ) สถานที่ตั้ง: [https://maps.app.goo.gl/tgCaQcmgoTxyskEj7](https://maps.app.goo.gl/tgCaQcmgoTxyskEj7) --- เย้ ๆ วันนี้มาเป็น Blogger สายท่องเที่ยวนิดนึงพอดีเพิ่งกลับจากไปเที่ยวมาครับ จริง ๆ แล้วยังขาดร้านชื่อดังอีกร้านนึงคือ Comebuy แหละ แต่พอท้องเสียไปวันนึงนิลก็ไม่กล้าไปกินเพิ่มเลยอดเลย สุดท้ายใครชอบหรือไม่ชอบอันไหนก็มาบอกกันได้นะครับ หรือใครไปตามรอยแล้วเป็นยังไงบ้างก็แชร์กันได้นะครับ นอกจาก Guide ชานมแล้วยังมี Content ท่องเที่ยวไต้หวันตามมาแน่นอน ติดตามกันได้เลยครับ ขอให้อร่อยกับการกินชานมไข่มุก – นิล – --- # ทุกงานสำคัญหมด แต่งานไหนสำคัญกว่า - URL: https://blog.ninprd.com/blog/prioritzing-tasks/ - Published: 2024-02-03 - Tags: experience-sharing - Summary: การตั้ง Priority เป็นสิ่งหนึ่งที่ควรค่าแก่การทำมากเพราะว่าเราจะสามารถ Manage งานได้ดีกว่าคนอื่น หากเรา Prioritize ของถูกว่าอันไหนควรเสร็จก่อน มาตามหาวิธีการจัด Priority ของแต่ละชิ้นกับนิลกัน! > นิลครับ พี่ขอ 5 นาทีได้ไหมครับ? > > – ทุกคนที่ทักนิลเรื่องงานมาช่วงนี้ คำพูดนี้ถูกยกเอามาอีกครั้ง เพราะคำพูดนี้ก็เป็นหนึ่งในชนวนที่ทำให้เกิด Blog นี้เหมือนกันครับ ช่วงนี้นิลจะเจอหลาย ๆ คนทักมาว่าขอเวลาซัก 5 นาที ช่วงแรก ๆ นิลก็ให้ 5 นาทีกับทุกคนไปครับ แต่มันก็เป็น 5 นาทีจอมปลอมกันหมดเลย เวลานิลหายไป 1 ชั่วโมงบ้าง 2 ชั่วโมงบ้าง จนสุดท้ายเวลาทำงานหลักของนิลหายหมดเลยครับ ทีนี้นิลเลยเริ่มมาคิดว่านิลน่าจะต้องมาตั้ง Priority ของการคุยกับแต่ละคนครับ ## แล้วทีนี้จะดูได้ไงว่างานไหน Priority มากกว่า? หลาย ๆ คนที่ทักเรามามักจะบอกว่าเรื่องของเขามันด่วนมากและให้รีบจัดการ หรืออาจจะให้เรารีบ Investigate ปัญหาที่เขาเจอ ถ้าเราจัดการให้กับทุกคนทีเดียว ตายแน่ครับ เพราะนิลทำมาแล้ว ตัวแทบระเบิด 5555 ดังนั้นจริง ๆ เราควรถามพวกเขาเหล่านั้นไปก่อนว่าแต่ละคนติดต่อมาด้วยเรื่องอะไร อาจจะให้เขาเล่ากันแบบคร่าว ๆ ซึ่งพอฟังบางคนที่เขาว่างานของตัวเองนั้นด่วน แท้จริงแล้วก็ไม่ได้ด่วนอะไรเลยครับ เป็นงานธรรมดาที่ต้องนำไปต่อคิวเข้า Backlog เท่านั้น แต่ในขณะเดียวกันบางคนที่ทักเรามานั้น เขาก็ทักมาด้วยความเร่งด่วนจริงครับ ## เมื่อกี้ยังไม่ตอบเลยว่าดูยังไงว่างานไหน Priority มากกว่า! ปกตินิลจะแบ่งงานในหัวตัวเองเป็น 3 ส่วนคือ งานที่เร่งด่วน งานที่ต้องทำแต่ไม่รีบ และงานที่ไม่ต้องทำ ซึ่งแน่นอนพอนิลเข้า Filter ในหัวไปแล้วว่างานนั้นมันไม่ต้องทำ นิลปฏิเสธและโยนทิ้งเลย ทีนี้ถ้ามันเป็นงานประเภทที่เหลือนิลก็เรียงตามที่นิลเขียนมาเลยครับและก็จะเอา Deadline มาประกอบอีกทีครับว่างานไหน Deadline ก่อน งานนั้นก็จะถูกหยิบมาก่อนแหละครับ ทั้งนี้ถ้าเราได้รับงานที่สำคัญมาแต่นิลประเมินแล้วว่า Manpower ของนิลทำไม่ทัน Deadline นิลก็จะไม่รับงานนั้น ๆ มาครับ หรือถ้าเป็นงานในบริษัทนิลก็ต้องแบ่งงานออกไปให้คนอื่นที่สามารถทำงานนั้น ๆ ได้เหมือนกันครับ ทีนี้ถ้ามาพูดในบริบทของบริษัทที่ทำงานกันแบบ Agile นิลว่าเราต้องมองย้อนกลับไปถึง Sprint’s Goal, Team’s Goal, รวมถึง Personal Responsiblities ครับว่างานที่เขาจะเข้ามาคุยกับเรานั้น มันตรงกับของที่นิลเขียนไปก่อนหน้านี้หรือเปล่า เช่น ถ้า Sprint นั้น ทีมคุยกันแล้วว่าจะทำ สมมติว่าเป็นการสร้างเมนูในการ Navigate ให้กับ User และเอาไปวางตามหน้าต่าง ๆ ในเว็บไซต์ ถ้าทีมคุยกันแล้วว่าใน Sprint นี้ Goal ของเราคือสิ่งเหล่านี้ แปลว่างานที่ทักมาที่ไม่เกี่ยวกับ Goal ก็ไม่ควรจะถูกยกเป็น Priority ขึ้นมาและควรเอาไปต่อตูดที่ด้านล่างของ Backlog ทั้งนี้ทั้งนั้น ถ้างานนั้น ๆ แทรกเข้ามาแล้วเราคุยกันในทีมว่างานที่เข้ามานั้น ต่อให้ไม่ตรงกับ Sprint Goal แต่เป็นเรื่องใหญ่และเป็นเรื่องที่ต้องรีบทำ ทีมก็อาจจะต้องยก Priority งานที่แทรกเข้ามาได้ แต่นิลว่ามันเป็น Case-By-Case ไปแหละเรื่องพวกนี้ ถ้าถามว่ามันมีพวก Framework หรือแนวคิดอะไรที่ช่วยให้เรา Manage Task ได้ง่ายขึ้นไหม นิลขอนำเสนอ Eisenhower Matrix ครับ ตัว Matrix นี้จะให้เราแบ่งงานออกเป็น 4 ประเภทคือ 1. งานที่สำคัญและเร่งรีบ (ต้องทำเลย) 2. งานที่สำคัญแต่ไม่รีบ (ไว้ทำทีหลังได้) 3. งานที่ไม่สำคัญแต่เร่งรีบ (แบ่งงานให้คนอื่นทำได้) 4. งานที่ไม่สำคัญและไม่รีบ (ช่างมันได้เลย) ซึ่งใครอยากจะเข้าใจตัว Matrix นี้เพิ่มเติมนะครับ สามารถไปลองอ่านได้ที่[ลิงก์นี้](https://www.eisenhower.me/eisenhower-matrix/)เลย ## Manage Task ที่เข้ามาทั้งหมดแล้ว ลืมอะไรไปหรือเปล่า? ต่อให้เรา Manage Task ทั้งหมดที่เข้ามาได้แล้ว สิ่งที่หลาย ๆ คนรวมถึงตัวนิลลืมคือการเหลือเวลาส่วนตัวให้กับตัวเองครับ ตัวนิลในช่วงธันวานี่ถือว่างานแทรกเยอะมากและนิลตั้งใจว่าจะทำทุกอย่างให้เสร็จ สรุปนิลทุ่มเวลาให้กับงานบริษัทอาทิตย์ละ 7 วันเลยครับ สุดท้ายสุขภาพก็พัง รู้สึกล้าง่ายและไม่ Fresh แบบ 100% เหมือนเมื่อก่อน ช่วงหลังปีใหม่มานี่นิลถึงได้เริ่มเอา Balance กลับมาด้วยการลดเวลางานให้กลับไปเหมือนปกติชนก่อนและไม่คิดเรื่องงานนอกเวลางานครับ ผลสรุปที่นิลได้ตอนนี้คือความ Fresh ถึงจะยังไม่เต็ม 100% แต่ว่าก็มากกว่าช่วงธันวามากครับ แต่ถ้าใครยังมองไม่เห็นความสำคัญของการดูแลและให้เวลาตัวเองตัวเองหรือว่ามองว่า Task ที่ต้อง Manage มันสำคัญกว่า ก็ให้ลองมองห้วงเวลาที่เราจะใช้กับตัวเองเป็น Task นึงแล้วโยนการให้เวลาตัวเองไปในขั้นตอนของการ Prioritizing ดูก็ได้ นิลหวังว่ามันจะกลายเป็น Task ที่ทุกคนเห็นความสำคัญนะครับ ## แนะนำ Tools ที่ปกตินิลใช้ดีกว่า ปกติเนี่ยนิลจะใช้ตัว Notion ในการ Manage Task ต่าง ๆ ครับ รวมถึงการทำ Documentation หรือการจด Note ต่าง ๆ เนี่ย นิลก็ใช้ Notion เป็นหลักเลยครับ ซึ่งนิลชอบ [Tutorial](https://youtu.be/bP8wTapHsbc?si=k3ba2Hee6Qmd57yf) ของคนนี้มาก ลองไปตามดูกันได้ครับ อีก Tool นึงท่ีนิลใช้คือ [Google Calendar](https://calendar.google.com/) ครับ ซึ่งสิ่งนี้ปกตินิลใช้ในการลงตารางการนัดหมายและ Block เวลาการทำงานให้ Focus เพื่อให้สิ่งที่สำคัญมันลุล่วงไปก่อนครับ แค่มีบัญชี Google ก็สามารถใช้งานได้แล้ว นิลว่าสะดวกมากเลยครับ นิลมีใช้อีกตัวนึงเพื่อใช้ในการ Capture Idea แบบเร็ว ๆ ด้วย ซึ่ง Tools นั้นก็คือ Todoist นั่นเองครับ นิลใช้ App ตัวนี้ในการจดเวลาเจออะไรเร็ว ๆ เช่น มีคนทักให้ทำสิ่งนึงให้แต่ไม่รีบ นิลก็จะจดไว้ใน Todoist ก่อนแล้วพอถึงที่ทำงานหรือเริ่มวันทำงานก็จะกาง Todoist ออกมาเพื่อดูว่ามี Issue เล็ก ๆ น้อย ๆ อันไหนบ้างที่นิลสามารถเก็บได้หรือมีงานอะไรเล็ก ๆ น้อย ๆ ที่คั่งค้างอยู่หรือเปล่า ![Tools Nin used to capture ideas and manage tasks](assets/tools-nin-used.png) --- จบไปแล้วนะครับ Blog นี้ นิลคิดว่าเป็นหนึ่งใน Blog ที่ยาวที่สุดในช่วงนี้เลย ตัว Blog นี้นอกจากอยากให้คนฝึก Prioritize งานที่เข้ามาแล้ว อยากให้ดูแลตัวเองกันด้วยครับ โหมงานกันหนัก ๆ ก็อย่าลืมแบ่งเวลาซักนิดนึงมาดูแลตัวเอง นิลคิดว่ามันอาจจะเป็นเรื่องที่หลาย ๆ คนมองข้ามมันไป แต่นิลไม่อยากให้ทุกคนมามองเห็นมันในวันที่สายไปแล้วนะครับ ยังไงก็ดูแลสุขภาพกันด้วย ช่วงนี้นิลเพิ่งป่วยเพิ่มเป็นบ่าอักเสบ พูดเสร็จแล้วก็ไปยืดร่างกายตามหมอสั่งก่อน 5555555 ขอให้ทุกคนสนุกกับการ Prioritize งานครับ – นิล – --- # มือใหม่หัด Estimate - URL: https://blog.ninprd.com/blog/estimation-newbie/ - Published: 2024-01-20 - Tags: experience-sharing - Summary: ช่วงนี้ในฐานะที่นิลเริ่มเติบโตขึ้นมา (นิดนึง) ในฐานะ Software Engineer คนนึง นิลเริ่มเห็นปัญหาใหญ่ ๆ ที่ Dev หลาย ๆ คนมักจะเจอนะครับ นั่นคือการ Estimate เวลาที่ใช้ทำ Task ใน Sprint นั่นเอง มาดูกันว่าทุกคนกำลังเจอปัญหาเดียวกันหรือเปล่า > นิลครับ พี่ขอคุยด้วยซัก 5 นาทีหน่อยได้ไหมครับ คำพูดนี้ช่วงนี้นิลได้ยินทีนี้สั่นซู่วขึ้นมาเลยครับ ช่วงนี้ในฐานะที่นิลเริ่มเติบโตขึ้นมา (นิดนึง) ในฐานะ Software Engineer คนนึง นิลเริ่มเห็นปัญหาใหญ่ ๆ ที่ Dev หลาย ๆ คนมักจะเจอนะครับ นั่นคือการ Estimate เวลาที่ใช้ทำ Task ใน Sprint นั่นเอง ปกติตอน Planning เหล่า PM ก็จะให้ Dev ลาก Card จาก Backlog เข้า Sprint พอเราลากเสร็จก็จะย้อนกลับมาถามเราว่าเราสามารถทำ Task เหล่านี้ให้เสร็จใน Sprint หรือเปล่า ตัวเรา ณ ตอนนั้นก็คิดแค่ว่า Task แต่ละใบน่าจะทำให้เสร็จในเท่านี้วัน เท่านี้ชั่วโมงแหละ แต่อาจจะลืมคิดถึงปัจจัยอื่น ๆ ไป วันนี้นิลจะมาลองยกตัวอย่างปัจจัยเหล่านั้นแล้วพาทุกคนคิดตามดูนะครับ ว่ากำลังเจอปัญหาเดียวกันอยู่หรือเปล่า ## Meeting ในโปรเจคที่นิลทำช่วงนี้ สิ่งนี้นับเป็นเกือบ ๆ 40% ของ Task ใน Sprint นึงเลยก็ว่าได้ ซึ่งมีทั้ง Meeting ที่เป็น Scheduled Meeting และ Unexpected Meeting ซึ่งในความเป็นจริงแล้วเราควรเอา Scheduled Meeting มาคำนวนในเวลาที่เราเหลือใน Sprint ด้วย และถ้าสมมติเราทำข้อมูลเก็บไว้ เราก็สามารถเอาข้อมูล Unexpected Meeting มาวิเคราะห์และ Buffer เผื่อไว้ให้เราสามารถคิดเวลาที่เหลือใน Sprint ได้อย่างใกล้เคียงความเป็นจริงมากที่สุดด้วย นอกจากนี้หาก Meeting นั้น ๆ มีความนานเกินไปหรือเราไม่มีความจำเป็นจะต้องอยู่ใน Meeting นั้นแล้ว อาจจะขอตัดจบเข้าการสรุปการประชุมหรือออกจากการประชุมได้เพื่อให้เราไป Focus งานใน Sprint ต่อได้ครับ ## Review PR สิ่งนี้เป็นสิ่งที่ Dev หลาย ๆ คนอาจจะลืมเผื่อกันเอาไว้ตอนที่วาง Task กัน ทุกคนก็จะคิดแต่งานตัวเองกัน แต่ยังไงก็ดี สิ่งนี้นิลคิดว่าเหล่า Dev น่าจะต้องเอาไปคิดเพื่อลบเวลาใน Sprint ด้วย เช่น เราเห็นแล้วว่าเพื่อน ๆ ลากการ์ดเข้ามา 4 ใบใน Sprint และเป็น Issue ที่เราต้องไปช่วย Review เราอาจจะต้องประเมินเผื่อหักลบตรงนี้ไปเพื่อให้เราไม่ต้องไป Review PR นอกเวลาหรือว่าทำงานของตัวเองไม่ทันเพราะไปนั่ง Review PR คนอื่นอยู่ ## Misestimation อันนี้อาจจะเป็นสิ่งที่ Subjective นิดนึงครับ อันนี้จากประสบการณ์ของนิลนะว่าหลาย ๆ ครั้งเราชอบคิดว่า Task มันง่าย อาจเป็นเพราะเราคิดว่ามันก็แค่นิดเดียวกับเราไม่มีความรู้มากพอที่จะประเมินเวลาที่แน่ชัดของมันได้ ทำให้สุดท้ายแล้วเราก็ Underestimate ไปยับ ๆ ซึ่งถ้าความผิดพลาดนั้นเกิดขึ้นในระดับชั่วโมงก็อาจจะโชคดีไป แต่ที่เกิดกับนิลล่าสุดคือด้วยความที่นิลไม่รู้เกี่ยวกับ WordPress เยอะมาก นิลคิดว่า Task ที่นิลต้องทำจะเสร็จใน 4 วันแต่ในความเป็นจริงแล้วนั้น… ใช้ไป 4 อาทิตย์แหนะ บ้าบอ แค่นี้ PM ก็ปาดเหงื่อแล้วครับ หรือบางทีนิลได้ Task นึงมา ด้วยความใหม่นิลก็รู้สึกว่ามันน่าจะยาก แต่ในความเป็นจริงอาจจะแบบดีดนิ้วเสร็จ ซึ่งในเคสเหล่านี้จริง ๆ ควรมี Senior/คนที่มีความรู้เกี่ยวกับเรื่องนี้มา Estimate เพื่อให้ค่าของการ Estimate มันไม่แกว่งมากเกินไปครับ ## Support หลาย ๆ ครั้งพอเราทำสิ่ง ๆ นึงเสร็จไป มักจะมีคนมาถามเรา ไม่ว่าจะเป็น PM Designer หรือลูกค้าก็ตาม ยกตัวอย่างเช่น เรา Release ของเสร็จปุ๊ป ทางลูกค้าอาจจะเจอ Bug หรือ Designer อาจจะอยากถามเรื่องของหน้าตาของที่เปลี่ยนไปบ้าง หรือแม้แต่ PM อาจจะต้องมาถามในเรื่องของการใช้ Feature นั้น ๆ ที่เราเพิ่ง Release ไป ซึ่งในความเป็นจริงแล้ว ควรจะต้อง Lock ไปเลยว่า Sprint นี้จะใช้ Resource เราในการ Support กี่วันเพื่อให้จำนวนวันที่เราเหลือใน Sprint นั้นเป็นตัวเลขที่ใกล้เคียงความเป็นจริงที่สุด ## งั้นแปลว่าใน Sprint นึงเราอาจจะมีเวลาทำงานน้อยมาก ๆ เลยล่ะสิ เป็นคำถามที่ดีครับ งั้นลองมายกตัวอย่างกันดีกว่า สมมติ 1 Sprint มี 10 mandays และนิลรู้ว่าต้องมีงานแทรกดังนี้ | **Activity** | **Time (mandays)** | | -------------------------------- | ------------------ | | Planning | 0.5 | | Review PR (6 Issues) | 0.5 | | Meeting With Client #1 | 0.3 | | Meeting With Client #2 | 0.2 | | Support After Release | 2 | | Sprint Review + Retro + Grooming | 1 | จากตารางนี้จะพบว่า 1 Sprint เราจะเสียเวลาไปทั้งสิ้น 4.5 mandays สำหรับงานอื่น ๆ ที่ไม่ใช่งานหลักใน Sprint ที่อยู่ใน Backlog เลย แปลว่าถ้า Sprint นึง มี 10 mandays เราก็จะเหลือเวลาทำ Task หลักใน Sprint อยู่ทั้งสิ้น 5.5 mandays นั่นเอง เย่ะ ๆ จากตอนแรก ถ้าสมมติเราไม่กางตัวเลขนี้มา เราอาจจะตีว่าเราจะมีอยู่ 10 mandays หรือบางคนอาจจะลบ Meeting ที่เป็น Planning กับ Review ไปอยู่แล้ว ก็อาจจะคิดว่าตัวเองมีอยู่ 9 mandays ใน Sprint ก็เป็นได้ครับ ซึ่งจากตารางที่ยกตัวอย่างมา ถามว่า 5.5 mandays ต่อ Sprint ในการเคลียร์ของน้อยไหม? ต้องตอบว่าดูน้อยครับ เพราะจริง ๆ อันนี้เรายังไม่ได้รวมเรื่องของการ Misestimate หรือ Unexpected Meeting ที่เป็นปัจจัยแปรผันและ Backlog ของบริษัทก็ไม่ได้น้อยนะครับ แต่ Resource ของ Dev ถูกเอาไปใช้ในงานอื่น ๆ ซะเยอะจนสุดท้าย Resource ของ Dev ก็ไม่ได้เอามาทำงานที่เป็น Development อย่างเต็มที่ครับ ## แล้วชีวิตจำเป็นต้องเป๊ะขนาดนี้ไหม? นิลตอบตรง ๆ ว่าไม่ครับ และก็ไม่ใช่ทุกครั้งที่เราจะทำให้ Estimate ใกล้เคียงกับความเป็นจริงครับ สุดท้าย Estimate ก็แค่ค่าประมาณครับ เวลาที่ใช้ทำ Task นั้นจริง ๆ ก็อาจจะขึ้นกับประสบการณ์หรือเวลาที่เราใช้เพื่อประมวลข้อมูลก็ได้ครับ ถ้าย้อนกลับไป นิลจะใช้คำว่า Estimate ได้แค่ “ใกล้เคียง” กับความเป็นจริง แต่ไม่ใช้คำว่า “ถูกต้อง” หรือ “ตรงเป๊ะ” ด้วยเหตุผลนี้แหละครับ ว่าสุดท้ายมันอาจจะไม่เป๊ะแหละ นิลแค่อยากมาชวนให้ทุกคนลองคิดว่าเจอปัญหาเหล่านี้อยู่หรือเปล่าครับ ## เราจะทำอย่างไรเพื่อลดปัญหาเหล่านี้? นิลว่ามันมีวิธีลดปัจจัยที่ควบคุมได้ เช่นพวก Scheduled Meeting หรือการ Estimate Task รวมถึงการ Dedicated Support ด้วย ซึ่งแต่ละหมวดก็มีวิธีการควบคุมและลดได้อยู่แล้ว เช่น Meeting ก็อาจจะสามารถตัด Meeting ที่วกไปวันมาเข้าสู่การสรุปประชุมเพื่อจบ Meeting ที่ไม่มีประโยชน์ในการคุยต่อ หรือในหมวด Misestimation ก็อาจจะต้องหา Senior มาคอยช่วยน้อง ๆ Junior ในการ Estimate นิดนึงเพื่อลดความแกว่งที่อาจจะเกิดขึ้นได้ --- จบไปแล้วนะครับ กับ Blog ที่มาแบบงง ๆ ตัว Blog นี้มันเริ่มมาเพราะช่วงนี้นิลเสียเวลากับการ Activity เหล่านี้ในอัตราส่วนที่ค่อนข้างเยอะแหละครับ และทำให้นิลต้องไปทำงานนอกเวลาเยอะมาก สุดท้ายก็ส่งผลเสียกับสุขภาพนิลครับ ตอนแรกก็ไม่ได้ Capture จริงจังว่าใช้เวลาไปแต่ละ Activity เท่าไหร่บ้าง แต่นิลก็แบบ ไม่ได้ละ ต้องหาตัวการละว่าอะไรที่ทำให้นิลทำงานเกินขนาดนี้ได้ ก็ไปเจอเข้ากับสาเหตุเหล่านี้แหละครับ เลยออกมาเป็นเนื้อหาของ Blog แบบนี้ ยังไงถ้าอ่านแล้วมี Feedback อะไรก็สามารถให้ Feedback ทาง DM ของ Instagram ได้เหมือนเดิมนะครับ จนกว่านิลจะเปิดช่องทางเพิ่ม 555555 ขอบคุณทุกคนที่อ่านมาถึงจุดนี้ด้วยครับ ขอให้สนุกกับการ Estimate Task – นิล – --- # 2023 Year In Review - URL: https://blog.ninprd.com/blog/2023-year-in-review/ - Published: 2023-12-31 - Tags: experience-sharing, year-in-review, Y2023 - Summary: เอาล่ะ จะปีใหม่แล้ว สิ่งที่ขาดไปไม่ได้เลยตอนสิ้นปีคือ “Year In Review” ยังไงล่ะ ในปีนี้นิลก็ขอขอบคุณทุกคนที่ติดตาม Blog ของนิลมาตลอด รวมถึงคนที่ Support นิลด้วยนะครับ วันนี้ที่นิลจะมาเล่าสิ่งที่เป็น Highlight ที่เกิดขึ้นกับนิลใน 1 ปีที่ผ่านมานะครับ จะเป็นยังไง ไปดูกันเล้ย! เอาล่ะ จะปีใหม่แล้ว สิ่งที่ขาดไปไม่ได้เลยตอนสิ้นปีคือ “Year In Review” ยังไงล่ะ ในปีนี้นิลก็ขอขอบคุณทุกคนที่ติดตาม Blog ของนิลมาตลอด รวมถึงคนที่ Support นิลด้วยนะครับ วันนี้ที่นิลจะมาเล่าสิ่งที่เป็น Highlight ที่เกิดขึ้นกับนิลใน 1 ปีที่ผ่านมานะครับ จะเป็นยังไง ไปดูกันเล้ย! ## รับ Freelance ครั้งแรก เปิดปีด้วยการรับ Freelance ครั้งแรก เป็นสิ่งที่นิลไม่เคยกล้าทำเลย เพราะนิลไม่มั่นใจในตัวเองเลยว่าจะทำมันได้ แต่พอตอนนั้นตกลงทำก็รู้สึกสนุกดีนะ รู้สึกเลยว่าเราก็ทำได้นี่นา ไม่ได้ยากชิบหายอย่างที่คิด แต่ผลที่ตามมาคือการแบ่งเวลาที่ไม่ดีจนสุดท้ายก็ป่วยรัว ๆ เลย รอบหน้าถ้ารับงาน นิลได้บทเรียนมาละต้องประเมินเวลาให้ดีกว่านี้และต้องไม่ให้เวลาทำงานทับเวลานอนไปครับ ## ไปงาน Networking ครั้งแรก ในปีนี้นิลได้ไปงาน UX Day ที่ทาง Gangs Connector เป็นคนจัดฮะ เป็นครั้งแรกเหมือนกันที่นิลกล้าที่จะไป Networking เพราะรู้ทั้งรู้ว่าตัวเองแบบ Social Akward มากเวลาไปกับคนที่ไม่รู้จักเลย แต่ยังไงก็ดีพี่ ๆ ในงานน่ารักมาก ช่วยมาดึงนิลจากมุม ๆ นึงเข้าไปคุยกับคนอื่น ๆ ทำให้สุดท้ายก็เปิดใจกับงาน Networking ว่าจริง ๆ ก็ไม่ได้น่ากลัวอย่างที่คิด แอบกระซิบว่าตอนนี้เขากำลังขายตั๋วงาน UX Conference ของปีหน้านะ ไปกดตั๋วกันได้ที่[นี่เลย](https://uxth.co/) ## แข่ง Hackathon อันนี้ไม่ใช่ครั้งแรกที่ลงแข่ง Hackathon แต่รอบนี้เป็นการไปแข่ง Hackathon ในนามบริษัทแหละ ปีนี้ได้ลงแข่งรายการ [Hack For Growth](https://www.etda.or.th/th/hackforgrowth) เป็นรายการที่จัดโดย ETDA เพื่อเฟ้นหา Solution ที่จะมาส่งเสริมในหมวดการท่องเที่ยว ซึ่งมันรู้สึกคนละ Scale กับ Hackathon ที่เคยแข่งก่อนหน้านี้เลย แต่ทั้งนี้ทั้งนั้นก็มั่นใจในทีมเพราะพี่ ๆ ในทีมนี่ระดับตัวตึงบริษัททั้งนั้น 😂 นอกจากนี้ยังได้มาเรียนรู้ Skills ต่าง ๆ ผ่าน Workshop (ที่มีทั้งรู้เรื่องและไม่รู้เรื่อง 5555) ได้ออกมาเปิดโลกว่าจริง ๆ ในโลกกว้างข้างนอกตอนนี้เขาทำอะไรกันบ้างนะ มีอะไรที่สามารถไปส่งเสริมการท่องเที่ยวตามโจทย์บ้าง ได้เห็นเลยว่าแต่ละทีมโหดมาก ถึงจะไม่ชนะ แต่ก็ได้อะไรกลับไปเยอะมาก และก็ตั้งเป้าว่าอยากลงแข่ง Hackathon อีก ps. อยากใช้พื้นที่ตรงนี้ขอบคุณพี่ ๆ ในทีมทุกคนอีกครั้งด้วยนะครับ พี่ ๆ เก่งมาก 💪 ## ได้มีโอกาสไป Public Speaking ในฐานะ Software Engineer เป็นครั้งแรก นิลได้รับโอกาสจาก Manager ให้ไปพูดเหมือนแนะแนวน้อง ๆ วิศวะปี 1 ภาคคอมเรื่องของการเรียนรู้เพื่อจะเป็น Software Engineer ที่ดีครับ เป็นครั้งแรกที่พูดและตื่นเต้นมาก แล้วก็ทำสไลด์ไม่ทันด้วย แต่ก็เป็นประสบการณ์ที่ดีมาก ขอบคุณน้อง ๆ หลายคนที่ตั้งใจฟัง (และก็แอบอยากหยุมหัวน้อง ๆ ที่แค่เริ่มคาบยังไม่ทันพูดก็ไม่ฟังกันเลย 5555) แต่ก็อาจจะเป็นว่า Skill การพูดของนิลยังไม่ดีพอแหละ เป็นเรื่องที่ต้องฝึกฝนไปเรื่อย ๆ ยังไงก็ขอบคุณพี่ Manager ด้วยนะครับ สำหรับโอกาสดี ๆ แบบนี้ ## เริ่มทำ Blog.nprd อันนี้เป็นสิ่งที่อยากทำมานานมากกกกแล้ว แต่ว่าสุดท้ายโดนพับไปหลายครั้งมาก รอบนี้กลับมาแบบจริงจัง ที่เริ่มกลับมาทำเพราะเห็นพี่ที่ออฟฟิศคนนึงทำ เลยไปคุยกับพี่เขามาแบบอารมณ์ว่าทำไมถึงทำ หนึ่งในเหตุผลที่รู้สึกว่าเป็นสิ่งที่อาจจะเป็นประโยชน์ในอนาคตคือเรื่องของ “Branding” นิลเลยคิดว่าก็น่าสนใจเพราะนิลก็อยากแชร์อยู่แล้วเป็นทุนเดิมและถ้ามันสร้าง “Branding” ของการเป็นนิลทิ้งไว้ได้ มันก็เป็นเรื่องที่ดี รวมกับว่าถ้าใครอยู่กับนิลเยอะ ๆ จะรู้ว่านิลพูดไม่รู้เรื่องหรือมีปัญหาเรื่องการเรียงประโยคซึ่งนิลคิดว่าถ้าเขียนไปเรื่อย ๆ นิลอาจจะลดปัญหาตรงนี้ได้ด้วย ## นอนป่วยที่โรงบาลครั้งแรก หลังจากบาปกรรมที่ทำกับร่างกายมาในพาร์ทแรก ๆ ทั้งหมด จะเห็นได้ว่านิลน่าจะนอนน้อยและไม่ได้ออกกำลังกายเลย อันนี้เป็นสาเหตุของ Time Management ที่ไม่ดี สุดท้ายนิลก็ป่วยเป็นไข้หวัดใหญ่ครับ นอน Admit อยู่โรงบาล 3 คืน ต้องพักงานไปร่วม ๆ 9 วันเพื่อพักการใช้ความคิด + นอนให้พอ + Social Isolate ครับ เป็นการนอนโรงบาลครั้งแรกที่รู้สึกเคว้งคว้างมาก ไม่เคยอยู่คนเดียวแล้วรู้สึกวังเวงขนาดอยู่โรงบาลมาก่อนเลย มันเป็นความรู้สึกที่แปลกมาก และค่าใช้จ่ายอ่วมมาก ถ้าไม่มีประกันบริษัทนี่กลายเป็นยาจกได้เลยนะ 55555 เป็นประสบการณ์แปลกใหม่ในปี 2023 แต่ 2024 ไม่เอาแล้วนะ 😂 ## โดนจับลง Project WordPress นี่อาจจะเป็นสิ่งที่หนักหน่วงที่สุดของปีนี้ก็ได้ เป็นการถูกย้ายจากการจับ Stack TypeScript เป็น php ในการทำงานครั้งแรก ถือว่าเป็นช่วงเวลาที่ยากที่สุดของปีเลย เพราะในบริษัทไม่ได้มี WordPress Expert ด้วย รวมกับว่าในตอนแรกมี Dev คนเดียวในทีมด้วย ตอนแรกตอนที่ไม่รู้ Scale Project + ยังไม่เห็น Design นี่คิดว่าไหวชิวนะ แต่พอผ่านมาครึ่งทาง อุทานได้คำเดียว “เxี้ยแล้ววว” จะทันไหมว่านี่ สุดท้ายก็ต้องมีน้องในทีมเพิ่มคนนึง กลายเป็น Junior Software Engineer ชุบแป้งทอด (ยังเป็น Junior แต่มีงานดูแลน้องเพิ่มเข้ามา 55555) อยากใช้พื้นที่ตรงนี้ขอบคุณที่ทำงานหนักและขอโทษน้องด้วยที่ดูแลน้องได้ไม่ดีเท่าที่ควร และก็ขอบคุณทีม Designers และทีม Product Manager (PM) ด้วย ทุกคนในทีมเก่งมาก ทีมนี้เป็นทีมที่ช่วยเหลือกันดีมากและเป็นสิ่งที่ฉุดรั้งไม่ให้นิลอยากโดดตึกตาย 555555 นอกเหนือจากการที่เป็น Project ที่ยากแล้ว อีกอย่างนึงเลยคือ เป็น Project ที่ได้ทำงานกับ PM กับ Designers อย่างใกล้ชิดและเห็นเส้นแบ่ง Role อย่างค่อนข้างชัดเจน เพราะตอนนิลอยู่ทีม POC ตอนนั้นทุกคนถือกัน 2 Roles กันหมดเลย เส้นแบ่ง Role มันเลยไม่ชัดและก็ไม่ได้สัมผัสประสบการณ์การทำงานร่วมกับทุกฝ่ายแบบใกล้ชิดด้วย นอกจากการที่มันเป็นช่วงเวลาที่หนักหน่วงแล้ว (หนักจนไม่มีเวลามาเขียน Blog) มันก็สอนอะไรนิลเยอะมาก ๆ เหมือนกันนะ ยังไงก็ต้องอยู่กับ Project นี้ในปีหน้าด้วย ขอให้งานใจดีกับฉันด้วย ฮืออ ps. กำลังคิดว่าจะเริ่มทำ Service ที่รับทำ Landing Page/Blog Website ด้วย WordPress นะครับ ใครสนใจทักนิลมาได้ที่ Inbox ของ Instagram เลย หรือถ้าไม่ได้อ่านเรื่องนี้จากในไอจีก็สามารถติดต่อได้ที่ [ppeeranat.d@gmail.com](mailto:ppeeranat.d@gmail.com) ได้เล้ย! --- จบไปแล้วกับ Year In Review ของ 2023 เป็นปีที่ถ้าใครขอ 3 คำจากนิลก็จะเป็นคำว่า “ทำงาน ทำงาน ทำงาน” เพราะไม่ได้ทำอะไรเลยนอกจากงานจริง มีไปเที่ยวบ้าง สังสรรค์บ้าง แต่น้อยมาก ต้องพาวันลาข้ามปีไปเยอะมาก พอกลับมาตกผลึกความคิดกับตัวเองก็รู้สึกค่อนข้างผิดหวังกับตัวเองครับ และก็รู้สึกว่าต่อให้ต้นปีทำมาดีแค่ไหน แต่ปลายปีเจองานแย่ ๆ ไปก็รู้สึกซึมครับ แบบไม่ได้รู้สึกดีเหมือนช่วงต้นปีเท่าไหร่ ยังไงปีหน้าเอาใหม่ครับ อย่าไปหยอง ต่อให้เราไม่รู้ว่าชีวิตจะอยู่ได้อีกนานเท่าไหร่แต่ก็ต้องไปต่อเรื่อย ๆ ครับ 2024 สัญญากับตัวเองไว้แล้วว่าจะไปเที่ยวให้มากขึ้น ทำงานให้น้อยลง และช่างแม่งให้มากขึ้นครับ ขอบคุณทุก ๆ คนที่ตามอ่าน Blog ของนิลมากเลยนะครับ เป็นกำลังใจที่ดีมากเลยครับ ยังน้อมรับ Feedback อยู่เรื่อย ๆ นะครับ พร้อมรับเสมอ ในปีหน้าจะเป็น Blog เรื่องอะไรรอติดตามกันได้ครับ ขอให้ 2024 เป็นปีที่ดีสำหรับทุกคน นิล --- # เงินกับสุขภาพ เลือกอะไร? - URL: https://blog.ninprd.com/blog/health-vs-money/ - Published: 2023-11-08 - Tags: experience-sharing - Summary: นิลจะมาแชร์ประสบการณ์การทำ Freelance ครั้งแรก ซึ่งในตอนที่นิลเลือกทำนั้น จากคำถามข้างบน นิลเลือกเงินครับ แต่พอทำถึงจุด ๆ นึงมันก็มีจุดที่เรากลับมามองตัวเองว่าสุขภาพเราพังเบอร์นี้เลยหรอ หรือแบบ เราเข้าโรงบาลบ่อยไปไหมนะ ซึ่งนิลจะมาเล่าการเดินทางกับสิ่งที่นิลได้จากการตัดสินใจของนิลครับ ฮั่นแน่ เข้ามาอ่านนี่คาดหวังคำตอบของคำถามตามหัวข้ออยู่หรือเปล่านะ จริง ๆ Blog นี้นิลจะมาแชร์ประสบการณ์การทำ Freelance ครั้งแรก ซึ่งในตอนที่นิลเลือกทำนั้น จากคำถามข้างบน นิลเลือกเงินครับ แต่พอทำถึงจุด ๆ นึงมันก็มีจุดที่เรากลับมามองตัวเองว่าสุขภาพเราพังเบอร์นี้เลยหรอ หรือแบบ เราเข้าโรงบาลบ่อยไปไหมนะ ซึ่งนิลจะมาเล่าการเดินทางกับสิ่งที่นิลได้จากการตัดสินใจของนิลครับ จะเป็นยังไง ไปดูกันเล้ย ## ทำไมถึงเลือกทำงานเสริมนอกเวลา? ต้องเกริ่นก่อนว่านิลก็เป็นเด็กติดเกมส์คนนึงครับ และหนึ่งในเกมส์ที่นิลติดคือ Genshin Impact ครับ การจะเล่นเกมส์นี้ได้อย่างลื่นไหลนั้น ต้องใช้อุปกรณ์ที่ Spec ที่ค่อนข้างสูงครับ ตอนนั้นอยู่ดี ๆ นิลก็เกิดกิเลสในการซื้อ iPad Pro M2 มาเพื่อเล่น Genshin Impact อย่างลื่นไหลที่สุดแบบ 120 fps และก็ซื้อมาในที่สุด พอซื้อมาเท่านั้นแหละครับ มันก็เกิดความคิดว่า **”ชิบหายละ เงินที่จ่ายไปนี่เราไม่ได้วางแผนนี่หว่า น่าจะต้องหาเงินมาทบก้อนที่เราใช้จ่ายด้วยความวู่วามของเราไป”** และจังหวะนั้นเอง เพื่อนนิลก็ทักมาว่ากำลังหา Dev ที่จะมาพัฒนาระบบของที่บ้านเพื่อนให้หน่อย นิลเลยลองคุยกับเพื่อนดูครับ ว่ารายละเอียดงานเป็นยังไง เรทราคาเป็นยังไง สุดท้ายนิลก็ตัดสินใจรับมาและก็คิดในใจว่า “รอดแล้วโว้ยย” ## การบริหารเวลาเป็นยังไงบ้าง? นั่นแหละครับ ความชิบหายมาเยือน ช่วงแรก ๆ ก็เหมือนยัง Balance ไม่ค่อยได้ งานประจำให้ 8 ชมละ งานนอกจะกี่ชั่วโมงดี จะ Manage ยังไงให้งานหลักไม่เสีย งานนอกก็ต้องผ่านพ้นไปให้ได้ แน่นอนครับ สิ่งที่เราทิ้งไปคือออ… **เวลาพักผ่อน** หายไปแบบย๊าบบบบ เหลือแบบ 3-5 ชั่วโมง จากที่นอน 8-10 ชั่วโมงมาตลอด พังเรียบในช่วงนั้นเลยครับ ช่วงเดือนแรกของงานนอกนี่สภาพก็ยังโอเคอยู่ ยังไหว แต่พอมาถึงเดือนถัด ๆ ไปนั้น สภาพทุกวันอย่างกับซากเลยครับ แถมแทนที่ชีวิตจะพอแค่นี้ยังทำ Side Project อื่นอีก (ตอนนั้นทำอีก Project ชื่อ [Pomoration](https://pomoration.ninprd.com/) ด้วยความอินเรื่อง Productivity กับอยากลองใช้ Supabase แต่ตอนนี้ไม่ได้กลับไปแตะมันเลย 5555) รวมกับอีกเรื่องนึงคือเรา Underestimated งานไป คิดว่ามันจะเสร็จเร็วและง่ายแต่มันใช้เวลามากกว่าที่คิดไว้ เลยต้องใช้เวลาช่วงวันเสาร์อาทิตย์อีก บอกเลยว่ายับเยินมาก ๆ เกมส์ที่วางแผนว่าจะเล่นนั้น บอกเลยว่าไม่ได้เล่นเลย 55555 ## แล้วตอนไหนถึงรู้ว่าสุขภาพของตัวเองชิบหายแล้ว? เอาล่ะ มันมาสู่ Part ที่ชิบหายมากตอนที่นิลเริ่มเข้าโรงบาลและเริ่มรู้สึกว่า เราป่วยบ่อยไปหรือเปล่านะ เราเริ่มรู้สึกว่าไปทำงานทุกวันมันล้าหรือเปล่านะ คำถามต่าง ๆ เริ่มโถมมาที่เราและก็อย่างที่เคยพูดในบทความเรื่อง “[ลาพักผ่อน ลาทำไมนะ](why-we-should-take-a-leave.md)” นั่นแหละว่าเรารู้สึกได้เลยว่า Output ที่เรา Deliver ให้ทุก ๆ ฝั่งนั้น น้อยลงอย่างที่นิลสัมผัสได้เลย ผนวกกับความที่แอบรู้สึกไม่สนุกในงานมากขึ้น สุดท้ายเลยตกผลึกทางความคิดได้ว่าเราใช้ร่ายกายแบบชิบหายมาก ๆ ไปแล้ว ## ค่าโง่จากการไม่สนใจสุขภาพ ตอนนั้นนิลต้องเบิกประกัน 2 รอบเพราะว่าเป็นตาอักเสบรอบนึงกับเป็นหวัดไปอีกรอบ และผลกระทบจากการทำงานแบบไม่รู้จักเดือนไม่รู้จักตะวันก็คือครึ่งปีหลังนิลป่วยรัว ๆ แบบเบิกประกันไปหลายรอบมาก (ขอบคุณบริษัทที่มีประกันกลุ่ม 🙇🏻) ใช้ Sick Leave บ่อย แหละทำให้ต้องมา Recap หลังจากกลับมาหลังจากลาบ่อยครั้ง มันแอบมีความหงุดหงิดตัวเองแหละ เช่น ป่วยอีกและ วีคนี้เป็นหวัด วีคถัดไปก็เป็นอีก อะไรประมาณนี้ และก็ด้วยความที่ทำงานที่ใช้ Mouse กับ Keyboard เยอะแล้วไม่ยอมพัก ทำงานต่อเนื่องยาว ๆ ก็เลยทำให้เกิดอาการข้อมืออักเสบ Trigger Point ที่แขนเจ็บต่อเนื่อง ต้องพักตีแบต ถ่ายรูป เล่นเกมส์และห้ามนั่งทำงานนาน ๆ อีก ปัญหาสุขภาพตามมาเพียบ ## ถ้าย้อนกลับไป จะยังเลือกเงินอยู่ไหม? ถ้ามองย้อนไป สิ่งที่นิลพลาดคือเรื่องการ Estimate ความยากของงาน คิดว่างานง่าย ๆ และ Commit ไปว่าไม่เกิน 3 เดือนเสร็จ ซึ่งอันที่จริงมันใช้เวลาเยอะกว่านั้น ทำให้นิลต้องมาเบียดเวลาพักผ่อนส่วนตัว อ่านมาถึงตรงนี้แล้วนิลอาจจะต้องบอกว่านิลยังเลือกเงินอยู่ แต่!!!! ต้องมีการปรับระยะเวลาในการส่งมอบงานให้เหมาะสมกว่านี้เพื่อ Balance ทั้งเงินที่ได้รับกับการดูแลสุขภาพของเรา รวมทั้งการ Balance ความสุขในการทำงานอีกด้วย ซึ่งเรื่องนี้ก็เป็นเรื่องที่ต้องคุยกับลูกค้าด้วยเพื่อ manage expectation ของงานให้ตรงกัน ## สิ่งที่นิลได้รับจากการทำงานนอกนี้ 1. นิลเห็นความสำคัญของสุขภาพมากขึ้นละกัน จากตอนแรกที่แบบ จะนอนกี่โมงก็ได้ ตื่นไปทำงานได้คือโอเค ก็กลายเป็นนอนให้พอเพื่อ Refresh ร่างกายให้ได้พักผ่อนอย่างเต็มที่ 2. การรับงานมาแต่ละครั้ง อย่าคิดว่างานง่าย ๆ เด็ดขาด ถ้ามันง่ายจริง ๆ เขาไม่จ้างเราหรอก เขาทำเองก็ได้ ควรจะระมัดระวังในการประเมินส่วนต่าง ๆ ของงานว่าจะใช้เวลาเท่าไหร่และอาจจะต้องมีการเผื่อในส่วนของ Safety Factor ด้วย 3. คำตอบของคำถามต้น Blog อาจจะไม่มีคำตอบที่ตายตัวอยู่จริง ๆ ครับ หรือบางทีมันอาจจะเป็นคำตอบ ณ ช่วงเวลานั้น ๆ ของชีวิตว่าอะไรสามารถตอบโจทย์เราได้ ณ ตอนนั้น แต่อย่างไรก็ดีเราควรที่จะ Balance ระหว่างการหาเงินกับการรักษาสุขภาพให้ดีเพื่อที่จะได้ยืนระยะในการทำงานและได้ใช้ชีวิตกับคนที่เรารักอย่างมีความสุขครับ --- จบไปแล้วนะครับ อีกบทความที่เป็น Experience Sharing ช่วงนี้นิลไม่ได้เขียน Blog เลยเพราะหมดแรงกับงานของออฟฟิศนิดนึงครับ จบ Blog นี้ไปอาจจะขอพักยาว ๆ ถึงปลายธันวาเลย น่าจะเป็นเกี่ยวกับการ Reflect ตัวเองในครึ่งปีหลังนี้ครับ ยังไงก็สามารถรอติดตามกันได้ ถ้าใครมี Feedback ตรงไหนสามารถทักมาบอกกันได้เลยนะครับ ยังน้อมรับ Feedback อยู่ตลอด หรือถ้ามี Topic ที่น่าสนใจก็ทักมาบอกกันได้ครับ ตอนนี้ Stock เริ่มวนแต่เรื่องงานแล้ว 🥲 มา Balance การทำงานกับสุขภาพกันเถอะ นิล --- # ย้ายสายมาได้ยังไง - URL: https://blog.ninprd.com/blog/how-i-enter-software-engineer-path/ - Published: 2023-10-14 - Tags: experience-sharing, software-engineer - Summary: วันนี้มาสู่หัวข้อที่มีคน request เข้ามาประมาณนึงเลยว่า “ย้ายสายมาได้ยังไง” วันนี้นิลจะมาเล่าประสบการณ์คร่าว ๆ ครับ ไม่พูดพร่ำทำเพลงดีกว่า ไปลุยกันเล้ย! วันนี้มาสู่หัวข้อที่มีคน request เข้ามาประมาณนึงเลยว่า **“ย้ายสายมาได้ยังไง**” วันนี้นิลจะมาเล่าประสบการณ์คร่าว ๆ ครับ ไม่พูดพร่ำทำเพลงดีกว่า ไปลุยกันเล้ย! ต้องเล่าย้อนไปสมัยตอนขึ้นปี 3 ครับ ตอนนั้นนิลก็ยังสมองโล่งอยู่ว่าจบไปแล้วจะทำอะไรดี เพราะการเรียนในภาค IE นั้นมันกว้างและสร้างทางเลือกอาชีพให้เราได้เยอะมาก (แต่ก็ทำให้คนหลงทางได้หลาย ๆ คนเลย) แต่พอดีเทอมนั้นมีวิชาเรียนวิชานึงชื่อว่า **Computer And Information Technology for Industrial Engineer (COMP IT/IE)** ซึ่งในวิชานี้จะได้เรียนอะไรเยอะมาก ๆ ทั้งเรื่องของ Diagram ต่าง ๆ (Use case, 3-NF, etc.), Network Layer รวมไปถึงการสร้างเว็บไซต์ด้วย HTML, php และการเขียน SQL เพื่อดึงข้อมูลออกมาจากฐานข้อมูล เรียกได้ว่าเรียนมันเกือบทุกอย่างเลยแหละ (แต่ไม่ลึกซักอย่าง) ด้วยความที่อาจารย์เขาอยากให้นิสิตเข้าใจวิชากันมากขึ้น อาจารย์ก็สั่งโปรเจคกลุ่มเป็นให้ทำเว็บไซต์ที่ต้องมีการใช้สิ่งที่เรียนมาทั้งหมด โดยมีเวลาให้ 2 อาทิตย์นิด ๆ ตัวนิลและเพื่อนในกลุ่มก็มาคุยกันเพื่อจะแบ่งงานกันไปทำ จังหวะนี้แหละครับ จุดพลิกชีวิตเลย พอเพื่อน ๆ เห็นว่านิลพอเขียนได้ เพื่อน ๆ นิลบอกว่า _“ไอนิล มึงทำวิชานี้ไปเลยนะ เดี๋ยวพวกกูไปช่วยวิชาอื่นให้มึงแทน”_ ใช่ครับ เพื่อน ๆ ผมไม่อยากมาเรียนรู้ Code กันเลยให้นิลจัดการทั้งโปรเจคคนเดียวเลย จากนั้นนิลก็เริ่มต้องศึกษาศาสตร์นี้ทั้งหมดเลยเพื่อปั้นโปรเจคนี้ให้รอดใน 2 อาทิตย์ด้วยตัวคนเดียวให้ได้ โชคดีที่คุณพ่อของนิลทำงานในสายงานนี้พอดี นิลเลยเอาของที่นิลสงสัยไปถามคุณพ่อแล้วก็สามารถพัฒนาโปรเจคเสร็จภายใน 2 อาทิตย์ได้โดยสวัสดิภาพ จนช่วงจบปี 3 นิลไปฝึกงานแบบสหกิจศึกษา (ฝึกงาน 6 เดือนช่วง Summer ปี 3 ถึงปี 4 เทอม 1 และทำ Senior Project ร่วมกับทางบริษัท) ที่ True Digital Group ซึ่งจริง ๆ ต้องเข้าไปเป็น Data Scientist แต่ว่าพอตอนจะถึงวันที่ฝึกงานแล้ว ทางทีมที่รับไปเห็นว่าตอนที่นิลจะเข้าไปฝึกเข้าจะไม่มี Resource เวลามา Babysit ในเรื่อง Data ขนาดนั้น ด้วยความที่ทีมเขาเป็นทีมที่ทำ Web กับ App และมีแผนที่จะทำเว็บไซต์แพลตฟอร์มใหม่อยู่และก็เห็นนิลมี Profile เคยเขียนเว็บมาอยู่บ้าง เขาเลย Offer ให้เปลี่ยนตำแหน่งเป็น Dev ไป ทีนี้ไอเราก็ชอบตอบรับทุกโอกาสที่เข้ามาซะด้วยสิ ทีนี้ก็ว้าวุ่นเลย ก็รับ Offer โดยที่ตอนนั้นยังไม่รู้ด้วยซ้ำว่า Dev คืออะไรด้วยซ้ำ 555555 เขาก็บอกให้เราไปเรียนมา 1 2 3 4 อย่าง นิลก็ตอบรับและกลับไปก้มหน้าก้มตาเรียนมาครับ สุดท้ายก็ได้ไปเขียนเว็บไซต์ที่ใช้ [Nuxt 2](https://v2.nuxt.com/) เป็น Frontend และใช้ Node.js + [Express](https://expressjs.com/) เป็น Backend (ขอไม่พูดถึงรายละเอียดของโปรเจคมาก) ทำเป็นโปรเจคระยะเวลา 6 เดือนที่ระหว่างทำก็ยิ่งตอกย้ำความชอบการได้แก้ไขปัญหาและการฝึกวิธีคิดมากขึ้น ด้วยสิ่งที่ประสบมาทั้งหมดทำให้นิลเลือกอยากที่จะทำงานในสายนี้ครับ หลังจากจบฝึกงาน นิลก็เข้าสู่โค้งสุดท้ายของชีวิตมหาลัย (ปี 4 เทอม 2) เป็นเทอมที่ชิวมาก และด้วยความชิวทำให้นิลมีเวลาที่จะไปนั่งไถ LinkedIn, JobsDB หรือ Platform หางานอื่น ๆ เพื่อหางานในตำแหน่ง Software Engineer ได้มากกว่าคนอื่นเขา และก็ทำให้รู้ความจริงของโลกใบนี้ว่า บริษัทในไทยส่วนใหญ่จะรับคนที่ใช้ React เป็นหรือมีประสบการณ์ในการใช้ React ทีนี้ก็ว้าวุ่นอีกทีเลย เรียน Vue + Nuxt มาตลอด 55555 นิลก็เลยใช้ช่วงเวลาที่เหลืออยู่ในระบบการศึกษานั่งเรียนพื้นฐาน React (ด้วยความที่มีและเริ่มทำเว็บไซต์ด้วย React แบบงู ๆ ปลา ๆ เสร็จไปเว็บนึง (ตอนนี้เว็บนั้นสูญสลายไปละ ไม่เหลือซากอารยธรรมให้ดูละอะสิ 555) แล้วพอเริ่มมีความมั่นใจก็เริ่มยื่นสมัครไปหลายที่ จนสุดท้ายได้มีโอกาสมาร่วมงานกับ Skooldio ครับ ## สิ่งที่อยากชี้ให้เห็นคือ 1. การวางแผนที่ดีย่อมทำให้เรามีโอกาสมากกว่าคนอื่น จากในที่นิลเล่าไป จริง ๆ นิลวางแผนว่าจะฝึกงานแบบสหกิจศึกษาตั้งแต่เข้าไปในภาค IE แล้ว ทำให้พอนิลฝึกงานเสร็จ นิลมีเวลาในเทอม 2 เพื่อพุ่งไปยังเป้าหมายอาชีพที่ต้องการมากกว่าคนอื่น ๆ อยู่นิดนึงครับ 2. การศึกษาตลาดแรงงานเป็นเรื่องสำคัญมาก ถ้าตอนนั้นนิลคิดแค่ว่านิลเรียน Nuxt มาแล้วและนิลเอาประสบการณ์ Nuxt ไปหว่านหางานโดยที่ไม่ Skim ดูก่อนว่าส่วนใหญ่เขารับคนที่มีประสบการณ์ใน Framework/Library อะไร นิลอาจจะไม่ได้มานั่งเล่าเรื่องแบบนี้อยู่ก็ได้ 3. ทุกวิกฤต มีวิกฤตอยู่เสมอ และก็มีโอกาสอยู่เช่นกัน เช่นอย่างตอนที่เพื่อน ๆ นิลส่งงานวิชานี้มาให้นิลทั้งหมดแล้ว วิกฤตก็เกิดทันที และมันก็มีวิกฤตอยู่ในนั้นตลอดนะ 555 แต่ทั้งนี้ทั้งนั้นในช่วงเวลาที่นิลปั่นงานวิชานี้ เพื่อน ๆ ก็ช่วยวิชาที่เหลือให้นิลและก็ชวนนิลเข้ากลุ่มติวแบบ One Night Miracle และนิลก็รอดมาได้ด้วยแหละ 4. ความสม่ำเสมอเป็นสิ่งที่สำคัญมาก การที่นิลสามารถทำงานสายที่นิลไม่เคยทำมาก่อนได้อย่างราบรื่น อาจจะเป็นเพราะพี่เลี้ยงฝึกงานดี โปรเจคไม่มีความซับซ้อนขนาดนั้น แต่อีกอย่างนึงแน่ ๆ คือความสม่ำเสมอในการฝึกการเขียน/การพัฒนา Logic ให้ใช้บ่อย ๆ จนเราสามารถทำงานได้ และทำได้เร็วขึ้นเรื่อย ๆ ด้วย การเล่าเรื่องทั้งหมดมันเป็นไปด้วยการเล่าเพียงมุมเดียว แต่จริง ๆ นิลก็เป็นเด็กธรรมดาคนนึงที่ชื่นชอบการเล่นเกมส์ ดูการ์ตูนแหละ นิลก็ไม่ได้ใช้เวลาแบบ Productive แบบ 100% 200% 300% ขนาดนั้น เวลาที่นิลเล่านิลก็เล่าส่วนที่มันเกี่ยวกับตัวเรื่อง ไม่ได้เล่าแบบ เวลา 100% นิลแบ่งไปทำอะไรบ้าง (เพราะจริง ๆ นิลก็ไม่ได้ Track ไว้เหมือนกัน) แต่ยังไงก็ดี ไม่อยากให้คนอ่านแล้วแบบเครียดว่าชั้นเตรียมตัวไม่ดีจัง ชั้นไม่เก่ง ทำไมนิลบริหารเวลาดี วางแผนดี จริง ๆ มันไม่เป็นแบบนั้น 100% นะครับ นิลก็เหลวแหลกประมาณนึงเหมือนกันแหละ --- # ลาพักผ่อน ลาทำไมนะ? - URL: https://blog.ninprd.com/blog/why-we-should-take-a-leave/ - Published: 2023-10-01 - Tags: experience-sharing - Summary: คำถามนี้อาจจะได้ยินกับพนักงานบริษัทหลาย ๆ คนที่กำลังนั่งทำงานแล้วก็กำวันลาในมือโดยที่ยังไม่มีเป้าหมายในการลาขนาดนั้นนะครับ แล้วพอเกิดคำถามนี้แล้วไม่ได้ใช้วันลาครับ อาจจะถามว่าแล้วลาไปทำไม? เราไปดูกันเลยดีกว่าครับ > ลาพักร้อน ลาไปทำไม? คำถามนี้อาจจะได้ยินกับพนักงานบริษัทหลาย ๆ คนที่กำลังนั่งทำงานแล้วก็กำวันลาในมือโดยที่ยังไม่มีเป้าหมายในการลาขนาดนั้นนะครับ แล้วพอเกิดคำถามนี้แล้วไม่ได้ใช้วันลาครับ อาจจะถามว่าแล้วลาไปทำไม? เราไปดูกันเลยดีกว่าครับ สวัสดีครับ นิลนะครับ ห่างหายจากการเขียนไปซักพักนึง ช่วงก่อนหน้านี้นิลเป็นไข้หวัดใหญ่ไปแล้วก็เป็นหวัดต่อ รวมกับการที่งานช่วงนี้ก็ท่วมท้นจนหาช่องว่างเวลามาเขียนได้น้อยครับ แต่ยังไงก็ดี เรากลับมาที่หัวข้อเราดีกว่า ทำไมเราต้องลาพัก ทำไมเราถึงไม่ทำงานไปเรื่อย ๆ ล่ะ ลาไปก็ไม่ได้ทำอะไรอยู่แล้วหนิ บางทีเราอาจจะรู้สึกว่าการที่เราอยู่ทำงานนั้นมัน Impact กว่า หรือสนุกกว่า เพราะลาไปก็เหมือนเอาเวลาไปทิ้ง ไม่ได้ทำตัวเองให้รู้สึกมีประโยชน์เท่าการนั่งทำงาน ใด ๆ คือไม่รู้สึกอยากใช้วันลานั่นแหละ นิลอาจจะยกตัวอย่างตัวเอง (อีกแล้ว) นิลเคยแบบบ้างานหนักมาก ๆ ช่วงนึงครับ แบบทำงานประจำ 5 วัน งานนอกอีก 2 วัน แล้วก็เขียนเว็บเล่นในเวลาว่างไปอีก คือแทบจะเรียกว่าทำงานทุกวันและทุกชั่วโมงเลยก็ว่าได้ ตอนนั้นนิลรู้สึกว่ามันสนุกครับ แบบ โห ได้เขียนและออกแบบเว็บแบบ 7/24 แม่งโคตรสนุกเลย แต่วันนึงนิลก็พบว่าในความสนุกนั้นจริง ๆ มันล้ามากเลยครับ แบบตอนนั้นรู้สึกว่า พอทำไปเรื่อย ๆ แล้ว Output งานที่ Deliver ให้ทุกฝั่งนั้นน้อยลง อาจจะไม่เยอะจนคนอื่นรู้สึกได้ แต่เป็นตัวเราเองที่รู้สึกได้ว่ามันน้อยลง และทำให้เราเริ่มไม่สนุก รู้สึกเหนื่อยมาก จนสุดท้ายช่วงที่นิลส่งมอบงานนอกเสร็จ นิลก็ป่วยและได้ใช้ Sick Leave หลายวันครับ เอ้า! แล้วมันเกี่ยวอะไรกับการลาล่ะ นิลจะบอกว่าหลังจากที่ Sick Leave ไป แล้วกลับมามันเหมือนการ Refresh ตัวเองอะครับ ช่วงที่เราลาไปเราก็อาจจะมีแตะ ๆ งานนิดหน่อย แต่โดยรวมคือเราได้ Clear สมองเรื่องงานออกไปเยอะมาก ทำให้สุดท้ายเราก็กลับมา Fresh อีกครั้งและกลับมาแบบโคตรโหด โคตรอันตราย โคตรไร้เทียมทานอีกครั้งนึงครับ เราจะรู้สึกว่าเรากลับมาใช้เวลารื้อฟื้นแป๊ปนึง แล้วก็กลับมาสามารถทำงานได้อย่างต่อเนื่องเลยครับ ซึ่งในจุดนี้แหละครับที่นิลอยากจะบอกไว้ว่าบางทีเราทำงานไปเรื่อย ๆ มันเกิดความล้า ความเหนื่อยสะสม โดยที่เราไม่รู้ตัว แล้วเราอาจจะผูกตัวเองกับงานมากเกินไปและสุดท้ายอารมณ์ของเราจะผูกกับงานไปด้วยในที่สุด ซึ่งถ้างานออกมาราบรื่นไปเรื่อย ๆ เลย ชีวิตก็จะ Happy มาก ๆ แต่ในวันที่งานเริ่มเนือย เราก็อาจจะเริ่มไม่มีความสุขและส่งผลถึงหลาย ๆ อย่างในชีวิตมากขึ้น จริง ๆ ตอนเรียนนิลเคยมีบทเรียนนึงในซักวิชานึง (ที่นิลจำวิชาไม่ได้) ที่เป็นเรื่องของ Learning Curve ด้วย แต่ด้วยความที่นิลก็จบมาปีนึงแล้ว นิลก็หลงลืมไปบ้างนิดนึง 55555555 แต่คร่าว ๆ เป็นเกี่ยวกับว่าการที่เราทำ Repetitive Task นึงไปเรื่อย ๆ โดยที่มีเวลาพักที่เหมาะสมจะส่งผลให้สามารถทำ Task ได้เร็วกว่าการที่ทำ Task นั้น ๆ ไปเรื่อย ๆ โดยไม่พัก ซึ่งมันก็อาจจะไม่ได้ตรงกับ Case เรื่องของงานฝั่ง Tech ขนาดนั้นหรอก แต่นิลคิดว่ามันก็ค่อนข้างเอามาปรับใช้กับงานฝั่ง Tech ในส่วนที่ว่าถ้าเราพักในปริมาณที่เหมาะสม เราอาจจะสามารถทำงานได้อย่างมี Productivity ที่สูงขึ้นกว่าการที่เรานั่งทำงานไปเรื่อย ๆ ก็เป็นได้ --- จบไปแล้วนะครับกับบทความเรื่องการพักผ่อน Blog โดยรวมของนิลอาจจะมีแต่งาน งาน งาน จนคนอ่านเอียนแล้วมั้ง แต่เพราะนิลเอาชีวิตผูกกับงานประมาณนึงแหละครับ นั่นเลยเป็นสาเหตุว่า Blog ของนิลถึงมีแต่พูดเรื่องงานอย่างเดียว หลังจากนี้นิลคงพยายาม Balance เวลาในการทำทุก ๆ อย่างมากขึ้นครับ เพื่อให้มีหัวข้ออื่น ๆ มาแชร์กันใน Blog กับเพื่อให้ไม่ป่วยอีก ช่วงนี้ป่วยบ่อยไป รับไม่ได้ 5555TT5555 ยังไงก็ขอบคุณทุกคนที่อ่านมาถึงตรงนี้นะครับ ยังทักมา Feedback กันได้เหมือนเดิมนะครับ พร้อมรับคำติชมเสมอครับ 💪💪 ขอให้ทุกคนได้พักผ่อนอย่างมีประสิทธิภาพครับ นิล ### Part รั่ว จริง ๆ มีได้ชื่อ Blog นี้จากเพื่อนมาชอบอันนี้มาก แต่นิลเขียนชื่อกับส่วนเปิดไปแล้ว สุดท้ายเลยไม่ได้ใช้ชื่อนั้น แต่ยังไงก็ชอบชื่อนั้นมากเลยขอเอามาเขียนไว้ Part นี้ 55555 ซึ่งชื่อหัวข้อก็คือออออ > ลาพักร้อนแล้วดียังไง สมองฉับไว ร่างกายแข็งแรง --- # แค่เริ่มก็ชนะแล้ว - URL: https://blog.ninprd.com/blog/start-to-win/ - Published: 2023-09-09 - Tags: experience-sharing - Summary: คำพูดนี้นิลได้มาจากพี่ที่นิลไปปรึกษาเรื่องการเขียน Blog มานะครับ ได้ยินครั้งแรกมันรู้สึกทรงพลังมากเลยครับ แบบเอาว่ะ แค่เริ่มก็ชนะแล้ว แต่นิลค่อนข้างแปลกใจที่หลังจากที่นิลได้รับคำพูดนี้มานั้น ในวันต่อมานิลก็ได้รับคำพูดนี้จากพี่อีกคนนึง แล้วแค่เริ่มก็ชนะจริงไหม เรามาดูกันดีกว่าครับ > _แค่เริ่มก็ชนะแล้ว_ คำพูดนี้นิลได้มาจากพี่ที่นิลไปปรึกษาเรื่องการเขียน Blog มานะครับ ได้ยินครั้งแรกมันรู้สึกทรงพลังมากเลยครับ แบบเอาว่ะ แค่เริ่มก็ชนะแล้ว แต่นิลค่อนข้างแปลกใจที่หลังจากที่นิลได้รับคำพูดนี้มานั้น ในวันต่อมานิลก็ได้รับคำพูดนี้จากพี่อีกคนนึง แล้วแค่เริ่มก็ชนะจริงไหม เรามาดูกันดีกว่าครับ ตอนนิลได้ยินครั้งแรกนิลรู้สึกว่ามันเท่นะ แต่ก็แอบประหลาดใจนิด ๆ แบบงงว่าคำนี้มันมาจากไหน แล้วรู้สึกว่ามันเหมือนเป็นคำพูดที่ให้กำลังใจเฉย ๆ หรือเปล่านะ หรือว่าแค่แบบคำพูดติดปากเฉย ๆ นิลเลยกลับมาลองคิดว่าที่นิลลองเริ่มเขียนมาทั้งหมดนั้น มันชนะอะไรบ้าง นิลลอง List เล่น ๆ ออกมาดูได้ประมาณนี้ครับ 1. ชนะความกลัวของตัวเอง: ได้ลองเขียนบทความจากที่ตอนแรกกล้า ๆ กลัว ๆ ในเรื่องของการสื่อสาร กลัวว่าจะพิมพ์ให้คนอื่นอ่านไม่รู้เรื่อง กลัวการแสดงทัศนะของตัวเองออกไป หลังจากเขียนไปเรื่อย ๆ ก็มีความกล้าที่จะสื่อสารมากขึ้น 2. ชนะความขี้เกียจ: ตอนนี้หลังจากที่ตั้งปณิธานกับตัวเองแล้วว่าจะทำออกมาเป็น Bi-weekly content นิลก็สามารถทำให้มันเสร็จในเวลาได้ โดยที่มันไม่ใช่การทำชุ่ย ๆ หรือส่งเดชให้เสร็จแต่มันยังเป็นความรู้สึกที่อยาก Share ให้คนอื่น ๆ จริง ๆ บางทีคนอ่านมาตรงนี้อาจจะแบบรู้สึกว่า โห่ ชนะแค่เนี้ย โคตรจิ๊บจ๊อยเลย แต่ว่าในความเป็นจริงแล้วบางทีเราอาจจะต้องการการชนะทีละนิดไปเรื่อย ๆ มากกว่าการรอ Huge Win ที่ไม่รู้ว่าจะมาถึงเราเมื่อไหร่นะครับ สิ่งนี้อาจจะคล้าย ๆ กับตอนที่นิลเขียนเรื่องความกลัวกับเวลาและโอกาสนะครับ ว่าการที่เราประวิงเวลาไปเรื่อย ๆ โดยที่มันเป็นการรอสิ่งที่มันอาจจะไม่มาถึงเนี่ย เราเสียเวลาไปมากเลยนะครับ และสุดท้ายคนที่เลือกที่จะชนะจิ๊บจ๊อยอย่างที่คุณว่า เขาอาจจะรู้สึกว่าเขาประสบความสำเร็จหรือมีความสุขมากกว่าคนที่รอ Huge Win ก้อนโตก็ได้ครับ นอกจากนี้การที่เราชนะไปเรื่อย ๆ มันเหมือนเรามี Progress ไปเรื่อย ๆ อะครับ เราอาจจะกำลัง Approach เส้นชัยหรือสิ่งที่คนที่เขารอ Huge Win ปรารถนาอยู่ก็ได้ครับ สุดท้ายนิลอาจจะมา Share อีกซักเล็กน้อยนะครับว่าจากการที่นิลลองเขียนบทความมา 4-5 บทความเนี่ย นิลได้อะไรจากการทำบ้าง 1. ได้สร้างเสริมวินัย: อย่างที่บอกว่านิลได้ Commit กับตัวเองไว้ว่าจะเขียนบทความเป็น Bi-Weekly นิลก็สามารถ Stock หัวข้อบทความและเอาแต่ละหัวข้อมาเขียนในกรอบเวลาที่กำหนดได้ // ทำหน้าภูมิใจเล็กน้อย <(˶ᵔᵕᵔ˶)> 2. ฝึกการคิดอย่างเป็นกระบวนการ: นิลเชื่อว่าถ้านิลสามารถเขียน Blog แบบยาวลงมาเป็นพรืดได้โดยที่หัวข้อกับเรื่องราวที่จะสื่อมันถูกต้องหมด กระบวนการการคิดของนิลน่าจะถูกต้องและสามารถสื่อสารกับคนอื่น ๆ ได้อย่างรู้เรื่องและถูกต้อง 3. ฝึกการเขียนในภาษาเขียน: นิลรู้สึกว่ามีน้อยครั้งมากที่คนเราจะโดน Assign ให้เขียนภาษาเขียนและเมื่อถูก Assign มาก็จะรู้สึกกระอักกระอ่วนใจที่จะทำเพราะเราไม่ได้เขียนภาษาในเชิง/แง่มุม/ระดับภาษาการเขียนบ่อยครับ ซึ่งนิลคิดว่าถ้าเขียนบ่อย ๆ ก็น่าจะทำให้เราได้ฝึกตรงนี้ไป 4. ได้ลอง Share มุมมอง/แง่คิด/ประสบการณ์ในมุมมองของตัวเอง: หลาย ๆ คนอาจจะมีความรู้สึกว่าอยาก Share แต่ไม่มีพื้นที่/ความกล้าพอที่จะ Share นิลรู้สึกว่านิลแค่มาลอง Share และหวังว่ามันจะเป็นประโยชน์กับคนที่มาอ่านไม่มากก็น้อยแหละ นอกจากฝั่ง Blog ที่เป็นบทความ ในส่วนเว็บไซต์นิลก็มีโอกาสได้ลองเล่น Libraries/Tools ใหม่ ๆ ที่อยากจะไปลองเล่นแต่อาจจะไม่มีโอกาสใน Project ของบริษัท ก็ได้เอามาลองเล่นบ้าง เช่น [@shadcn/ui](https://ui.shadcn.com/), [Astro](https://astro.build/), [trpc](https://trpc.io/) และอื่น ๆ ที่อาจจะเอามาใส่ในอนาคต ซึ่งถ้านิลไม่คิดอุตริเขียน Blog เนี่ย นิลอาจจะไม่ได้มีโอกาสเหล่านี้ --- จบไปอีก Blog ครับ ช่วงนี้นิลเหมือนชีวิตติด Loop นิดนึง หลังจากที่ Blog เป็น Bi-Weekly แล้วมีความอยากลองเล่น Libraries/Tools ต่าง ๆ ก็จะใช้เวลาประมาณ 1 อาทิตย์ในการเพิ่ม Feature และอีก 1 อาทิตย์ในการเขียนและ Proof Read อาจจะต้องหาเวลาหรือทำ Time Blocking ให้ดีกว่านี้ละ เพื่อให้ไม่รู้สึกว่ามัน Loop จนเกินไป ยังไงก็ขอบคุณทุกคนที่อ่านมาถึงตรงนี้นะครับ มี Feedback อะไรก็สามารถทักมาได้ IG, LinkedIn ทักมาได้หมดเลยครับ อยากได้ Feedback เยอะ ๆ จะได้นำไปพัฒนาและปรับปรุงให้ดีขึ้นครับ ครบ 10 บทความแล้วเดี๋ยวมา Redesign Web นะครับ ตอนนี้เอาง่ายไว้ก่อน ยังไงก็ขอบคุณทุกคนมากครับ ขอให้สนุกกับการเริ่มต้นทำสิ่งใหม่ ๆ นะครับ นิล --- # โยกย้าย บ๊ายบาย Medium - URL: https://blog.ninprd.com/blog/moved-from-medium-to-personal-site/ - Published: 2023-08-26 - Tags: experience-sharing - Summary: วันนี้มาคุยกันว่าด้วยเรื่องการย้ายจาก Medium มาเป็น Blog Post ที่เป็น Website อีกตัวนะครับ ซึ่งเป็นการเขียน Code เพื่อดึงข้อมูลจาก Notion มาแสดงผลยังหน้า Website ของตัวเองนะครับ เหตุผลที่ผมย้ายมาคืออะไร เดี๋ยวไปดูกันเลยครับ > ⚠️ นิลไม่ได้รับ Sponsor จาก Product ที่นิลพูดถึงใน Blog Post นี้นะครับ แต่ถ้าอยาก Sponsor ก็ติดต่อมาได้ครับ 🙂 สวัสดีครับทุกคน วันนี้นิลอาจจะมาใน Topic ที่มีการผสานเรื่องของ Technical เข้ามาในสัดส่วนที่ค่อนข้างมาก ยังไงเดี๋ยวจะเล่าเป็น General ไปก่อน ถ้าถึงจุดที่เป็น Technical นิลจะคั่นเอาไว้นะครับ เผื่อใครที่ไม่ได้อยากอ่าน Part ที่เป็น Technical จะได้อ่านส่วนที่เป็น General แล้วข้ามไปตอนจบเลยครับ วันนี้มาคุยกันว่าด้วยเรื่องการย้ายจาก Medium มาเป็น Blog Post ที่เป็น Website อีกตัวนะครับ ซึ่งเป็นการเขียน Code เพื่อดึงข้อมูลจาก Notion มาแสดงผลยังหน้า Website ของตัวเองนะครับ เหตุผลที่ผมย้ายมาคืออะไร เดี๋ยวไปดูกันเลยครับ ต้องเท้าความไปถึงตอนแรกที่นิลเขียน Blog นะครับว่าทำไมถึงเลือก Medium เป็น Platform ในการเขียนและเผยแพร่ Blog ซึ่งเหตุผลของนิลมีอยู่หลายข้อเลยคือ 1. เป็น Platform ที่ใช้กันอย่างแพร่หลายอยู่แล้ว ทุกคนเข้าถึงง่าย ไม่น่าอันตรธานหายไปง่าย ๆ 2. มีการทำ SEO ที่ดี สามารถทำให้เราถูกค้นหาจาก Google ได้ง่าย (มั้ง) 3. มีการเก็บสถิติจากการเข้าชมให้ สามารถนำมาวิเคราะห์เป็นตัวเลขได้ 4. (สำคัญที่สุด) Free to use ทั้งฝั่งผู้ใช้งานกับผู้สร้าง Content และพอนิลคิดจะทำจริงจังขึ้นมา นิลเลยไป Manage content ใน [Notion](https://notion.so/) โดยแบ่ง Content ออกเป็น Platform ที่จะปล่อย (เผื่อการปล่อยในหลาย ๆ Platform ในอนาคต 👀) และการแบ่งเป็น Status ของ Content นั้น ๆ ซึ่ง Workflow สำหรับการปล่อยบทความของนิลก็กลายเป็น ซึ่งในตอนแรกก็ไม่มีปัญหาอะไรหรอกครับ จนกระทั่งวันนึงผมพิมพ์ข้อความใน Blog ผิด ทำให้ผมต้องแก้ทั้งใน Medium และ Notion นี่แหละครับ จุดที่ทำให้นิลเริ่มคิดที่จะหาวิธีแก้ เพราะว่านิลไม่อยากจะ Double Work เวลาแก้งานแล้วก็ต้องทำ 2 ที่ นิลเลยเริ่มคิดว่าอยากทำให้ซักที่เป็น Single Source of Truth เพื่อที่จะได้แก้ที่เดียวและส่งผลให้ทั้ง 2 ที่มีหน้าตาข้อมูลที่เหมือนกัน พอมาถึงตรงนี้นิลเลยไปหาตัวเลือกว่ามีตัวเลือกไหนบ้างที่เป็นทั้ง Content Management System (CMS) และสามารถ Publish Content ในรูปแบบ Website ได้ซึ่งนิลเจอหลายตัวที่สามารถ Management Content ได้ แต่สุดท้ายก็จะมาติดปัญหาเรื่อง Pricing อยู่ดี ด้วยความที่หลาย ๆ Platform จะมี Free tier ที่ไม่ได้สูงขนาดที่เรามั่นใจว่าช่วงแรกเราจะไม่ไปชนจุดนั้นได้ สุดท้ายด้วยความที่มีพื้นฐานด้านการเขียน Code เลยเลือกที่จะใช้ Notion เป็น Platform ที่เก็บข้อมูลและเขียน Website เพื่อดึงข้อมูลจาก Notion ไปแสดงผลครับ — เข้า Part Technical แล้วจ้า ✨ — ## เลือกจะเขียน Web แล้ว เลือก Framework/Library อะไร? โอเค ถ้าจะเริ่มตรงนี้ต้องย้อนกลับไปที่เขียนไปข้างต้นถึงจุดที่ทำไมนิลเลือก Medium นะครับ ถ้าไม่นับเรื่องของความเป็น Platform ของ Medium ก็จะเป็นเรื่องการที่ทำ SEO ดี มี Analytics และ Free to use ครับ พอมามองจุดนี้ นิลคิดว่าเรื่องของ Analytics กับ SEO ในช่วงแรกนั้นอาจจะไม่จำเป็นเท่าไหร่ เพราะว่าคนที่เข้ามาอ่านน่าจะเป็นคนรู้จักนิลอยู่แล้ว ที่จะเห็นผ่านจากการแชร์ใน Instagram ส่วนตัวหรือ LinkedIn เพราะงั้นนิลเลยยังไม่อยากได้ Analytics ขนาดนั้นครับ แต่อาจจะต้องคิดเผื่อ SEO นิดนึงครับ พอเป็นเรื่องของ SEO เนี่ย ก็แปลว่านิลต้องหา Library/Framework ที่สามารถทำ Server-side Rendering (SSR) หรือ Static Site Generation (SSG) เพื่อให้ตัวหน้าเว็บถูก Render และมี Content ที่จะทำ SEO ได้อยู่ฝั่ง Server นิลเลยตัด Library/Framework ที่เป็น Client-side Rendering ไปก่อนครับ ด้วยความที่สุดท้ายนิลมองว่าอยากได้ Performance และเรื่องของการเป็นแค่เหมือนเว็บที่เอาไว้อ่านบทความนิลเลยเลือก [Astro](https://astro.build/) มาทำเป็น Server-side Rendering ด้วยเหตุผลดังนี้ครับ 1. เป็น Framework ที่มี Integrations กับ Frontend Library/Framework หลายตัว เช่น React, Preact, Vue, Svelte, Solid, etc. ทำให้สามารถเขียน Component ด้วย Syntax ของ Frontend Library/Framework ต่าง ๆ ได้ โดยใน Project นี้นิลใช้เป็น Astro + React ซึ่งปกติก่อนหน้านี้นิลเขียน React อยู่แล้ว การเขียน React ใน Astro ก็ทำให้ Feel Homie มาก ๆ ครับ 2. เราสามารถเลือกได้ว่าเราจะทำ SSR SSG หรือ Hybrid Rendering โดยเลือกได้ว่าหน้าไหนเราจะทำ SSR หรือ SSG 3. ไม่โหลด JavaScript ไปยัง Browser (ถ้าเราไม่ทำให้มันเรียก JavaScript) ทำให้หน้า Website โหลดเร็ว Performance ดีมาก 4. มี Integration กับ TailwindCSS ซึ่งปกตินิลใช้ TailwindCSS ในการทำ Styling อยู่แล้ว ข้อนี้เป็น 1 ในปัจจัยตัดสินใจหลักเลยครับ 5. ตอนนี้นิลยังคงสับสนกับการ cache ของ NextJS ตัว app directory และก็ยังงง ๆ เรื่องของ data fetching ของ Version ใหม่ของมันอยู่ + Library บางตัวก็เหมือนจะยังไม่ support Next Version ใหม่ นิลเลยมาลองใช้ของที่ใกล้เคียงกันครับ 6. สามารถเขียน Server Endpoint ได้ จริง ๆ ก็คือสามารถเขียน API Route ข้างใน Frontend Repo ได้เลย ซึ่งอาจจะทำให้นิล Extend ของเพิ่มในอนาคตได้ครับ ![landing page of astro js framework](assets/astro-landing.webp) ## โอเค ได้ Framework ที่จะใช้แล้ว ไปต่อที่ CMS กัน อย่างที่บอกไปตอนแรกว่านิลใช้ Notion ในการ Manage Content แต่ตอนที่เลือกตอนแรกก็มีความไปหาตัวเลือก Headless CMS เจ้าอื่น ๆ เช่น Strapi, Storyblok, WordPress, Webflow, etc. แต่ CMS ส่วนใหญ่จะมาติดปัญหาที่ Pricing ที่ค่อนข้างสูงหรือถ้าไม่อยากจ่ายราคาแพงก็ต้อง Self-Hosted เอง หรืออีกปัญหาคือ Free tier ที่นิลไม่รู้ว่าจะชนเมื่อไหร่ กลัวต้องมาลำบาก Migrate ของถ้ามันชนเร็ว นิลเลยกลับมามอง Notion ที่เคย Setup ไว้อยู่เพื่อ Manage Content อยู่แล้ว รวมทั้ง Notion เองก็มี SDK ของ JavaScript ที่ใช้งานไม่ยากมาก (ติดความยากที่การประกาศ Type นิดนึง) ทำให้นิลเลือกจะใช้ Notion ที่ตัวเองเคย Setup ไว้มาใช้ต่อครับ ![notion landing page](assets/notion-landing.webp) ## ว่าด้วยเรื่อง Deployment นิลเลือกที่จะ Deploy ที่ Vercel ด้วยเหตุผลที่ว่า 1. Vercel มี Deployment CI คือเราไม่จำเป็นต้อง Setup CI เอง ประหยัดเวลาได้เยอะเลย 2. รองรับการ Deploy Serverless Function อยู่แล้ว 3. User Interface ของ Website สวย และ User Experience ก็ใช้งานง่าย 4. (สำคัญที่สุด) Free 555555555555 ![vercel landing page](assets/vercel-landing.webp) ## Feature(s)/Enhancement(s) ที่อยากเพิ่มในอนาคต - คิดว่าอยากเพิ่มทางให้สามารถกด Like/Comment ได้เหมือนใน Medium หรือ Application อื่น ๆ - อยากเพิ่ม Analytics เข้ามาเพื่อนำตัวเลขมาวิเคราะห์ (อันนี้อาจจะเป็นอนาคตอันไกลหน่อย) - อยาก Redesign หน้าเว็บหมดเลย ตอนนี้ทำมาแบบเร็ว ๆ คิดว่าจริง ๆ น่าจะต้องปรับเยอะเลย - ตอนนี้นิลใช้วิธีเขียน API ด้วย Astro แล้ว host ในอีก Project นึง เพื่อเอามาใช้งานเป็น API แบบไว ๆ นิลเลยคิดว่าในอนาคตน่าจะต้องปรับในส่วนนี้ด้วยครับ ตอนนี้ชุ่ยด้วยกรอบเวลาที่วางไว้กับตัวเองด้วย --- จบไปแล้วนะครับกับ Blog ว่าด้วยเรื่องการย้ายถิ่นฐานของ Blog ครั้งแรก อาจจะไม่ใช่ทุกครั้ง แต่นิลคิดว่าการที่เราจะประดิษฐ์หรือสร้างอะไรขึ้นมาอย่างนึง อาจจะมาจากความที่เราทำงานซ้ำซ้อนจนทำให้รู้สึกว่า ถ้าเราลดความซ้ำซ้อนตรงนี้ได้ก็คงดีนะ เป็น Blog แรกที่นิลลองเขียนเกี่ยวกับ Technical ครั้งแรก แต่กว่าจะคลอดมาได้ก็ใช้เวลานานมาก ด้วยความที่ในสัปดาห์ที่ผ่านมานิลจัดการเวลาไม่ดีเองนะครับ จะปรับปรุงแล้วว่ากันใหม่สำหรับ Blog หน้าครับ ส่วนเรื่องเนื้อหาใครอ่านแล้วเอ้ะตรงไหน ลองทักมาคุยหรือ Feedback กันหลังไมค์ได้ครับ ขอให้สนุกกับการสร้างของกันครับ นิล --- # ความกลัวกับเวลาและโอกาส - URL: https://blog.ninprd.com/blog/what-are-you-scared-of/ - Published: 2023-08-11 - Tags: experience-sharing - Summary: ก่อนที่เราจะทำอะไร เรามักจะกลัวถึงผลลัพธ์ที่จะตามมา กลัวความผิดพลาด กลัวหลาย ๆ อย่างจนเราพลาดโอกาสหลาย ๆ ครั้ง แล้วก็กลับมาคิดกับตัวเองว่า “ทำไมไม่ทำอย่างงี้วะ” “รู้งี้ทำแบบนี้ไปแล้ว” เพื่อไม่ให้ความรู้สึกแบบนี้ค้างคาในใจเราเยอะ เรามาดูกันดีกว่าว่าเราจะสูญเสียอะไรไปเมื่อเรากลัว และถ้าเราไม่กลัว เราจะได้อะไรกลับมามั่ง ก่อนที่เราจะทำอะไร เรามักจะกลัวถึงผลลัพธ์ที่จะตามมา กลัวความผิดพลาด กลัวหลาย ๆ อย่างจนเราพลาดโอกาสหลาย ๆ ครั้ง แล้วก็กลับมาคิดกับตัวเองว่า “_ทำไมไม่ทำอย่างงี้วะ” “รู้งี้ทำแบบนี้ไปแล้ว”_ เพื่อไม่ให้ความรู้สึกแบบนี้ค้างคาในใจเราเยอะ เรามาดูกันดีกว่าว่าเราจะสูญเสียอะไรไปเมื่อเรากลัว และถ้าเราไม่กลัว เราจะได้อะไรกลับมามั่ง สวัสดีครับ รอบนี้อาจจะเปิดบทความงง ๆ หน่อย ตัว Inspiration ของบทความนี้นิลได้มาจากการคุยกับพี่ ๆ หลาย ๆ คนในออฟฟิศครับ ซึ่งนิลก็ไปปรึกษาเรื่อง Blog นี่แหละ แต่ว่าก็พูดความกลัว ความไม่แน่ใจหลาย ๆ อย่างไปกับพี่ ๆ ซึ่งสิ่งที่ตอบกลับมาก็ทำให้นิลรู้สึกมั่นใจขึ้นและกล้ามาแชร์มากขึ้นครับ เวลาที่เรากลัวหรือไม่กล้าทำอะไรเนี่ย มันอาจจะเกิดขึ้นได้ในหลาย ๆ สถานการณ์นะครับ ไม่ว่าจะเป็นการที่เราได้ถูกเชิญชวนไปทำอะไรซักอย่างนึงหรือได้รับงานมาชิ้นนึง เราก็อาจจะเกิดอาการกลัวว่า เราจะทำได้หรือเปล่า เราจะทำได้ดีไหม ให้คนอื่นที่เก่งเจ๋งกว่าทำดีกว่าไหมนะ แล้วพอเรากลัวนี่แหละครับ มันก็จะทำให้เกิดการลังเลว่าจะทำดีไหมนะ ตามมาด้วยเวลาที่ต้องนั่งคิด และจบด้วยบางทีอาจจะปฏิเสธงานนั้น ๆ ไปเพียงเพราะว่าเรากลัวที่จะพลาดหรือเรากลัวที่จะทำไม่ได้ อันนี้นิลลอง visualize ออกมา (อีกแล้ว 5555) ว่าถ้าเรามัวแต่กลัวที่จะทำสิ่งใดสิ่งหนึ่งแล้ว เวลาที่เรากลัวมันจะส่งผลกับเวลาที่เราจะใช้เพื่อไปทำสิ่งใดสิ่งหนึ่ง นอกจากที่เราจะรอ จะกลัวแล้ว เรายังต้องมานั่งทำความเข้าใจ วางแผน แล้วก็ทำอีก ไหนจะรอ Feedback จากการทำ โว้ะ! หมดเวลากันพอดี สุดท้ายอาจจะส่งผลไปถึงการพลาดโอกาสหลาย ๆ อย่างที่สำคัญซึ่งบางทีอาจจะเป็นบันไดที่นำพาเราไปสู่ความสำเร็จในภายภาคหน้าก็ได้ ![Image generated by AI](assets/what-are-you-scared-of-image-1.webp) ทีนี้ถ้าสมมติเราไม่กลัวแล้วทำสิ่งนั้นไป เราจะได้อะไรกลับมามั่ง นิลขอย้อนจากที่นิลบอกว่านิลไปปรึกษาพี่ ๆ ที่ออฟฟิศนะเรื่องความกลัวนี่แหละครับ ซึ่งในตอนนั้นสิ่งที่นิลกลัวคือกลัวว่าจะเขียนไม่รู้เรื่องกับกลัวการที่จะ Express ความคิดตัวเองออกไปทั้งหมดแล้วคนอื่นจะรู้สึกยังไงนะ เสียเวลานั่งคิด นอนคิด พินิจพิจารณา จนสุดท้ายความกลัวเหล่านี้ร่วมกับความขี้เกียจและอาการป่วยของนิลเมื่อเดือนที่แล้ว ทำให้ใช้เวลาร่วมเดือนในการปล่อยบทความที่แล้วออกมาทั้งที่จริง ๆ วางแผนเอาไว้ว่าจะใช้เวลาน้อยกว่านั้น จะสังเกตว่าจริง ๆ แล้วถ้าไม่คิดเยอะ หรือไม่กลัวโดยใช่เหตุเนี่ย จริง ๆ นิลก็อาจจะใช้เวลาน้อยกว่านี้ในการทำบทความนึงขึ้นมา แต่ด้วยปัจจัยหลาย ๆ อย่างเนี่ย มันทำให้นิลใช้เวลามากกว่าที่คิดซึ่งเวลาที่เหลือนี้จริง ๆ นิลอาจจะเอาไปทำอะไรอย่างอื่นที่มีประโยชน์มากกว่านี้ ไม่ว่าจะเป็นการออกไปออกกำลังหรือว่าพักผ่อนให้เพียงพอก็ตาม อีกคำถามก็อาจจะตามมาว่า แล้วถ้าไม่ได้เขียน Blog ล่ะ เท่าที่ดูในย่อหน้าก่อนหน้า หลายคนอาจจะคิดว่า “เอ้า! ก็กลัวเพราะว่าเขียน Blog หนิ” หรือว่า “ถ้าไม่ทำ Blog ก็คงไม่เกิดความกลัวแล้ว” อะไรประมาณนี้ซึ่งนั่นก็จริงส่วนหนึ่งครับ แต่หนึ่งในปัจจัยที่นิลมาเขียน Blog คือการฝึกการสื่อสารกับคนในรูปแบบของตัวอักษรให้รู้เรื่องมากขึ้นครับ ดังนั้นในจุดนี้นิลคิดว่าเรื่องความกลัวการสื่อสารไม่รู้เรื่องเนี่ย เป็นสิ่งที่นิลจะต้องข้ามผ่านมันไปให้ได้ครับ --- จบไปอีกแล้วววว บทความนี้อาจจะดูตึง ๆ นิดนึง เพราะตอนเขียนก็ตึงจริง 5555 อาจจะเพราะว่ามันมาจากประสบการณ์ตรง ๆ ที่เพิ่งเกิดและเอามาเขียน ก็เลยมีอารมณ์ร่วมค่อนข้างเยอะ ยังไงก็ขอบคุณทุกคนที่ทักมา Comment หรือให้ Feedback กันด้วยนะครับ รวมทั้งทุกคนที่ให้คำปรึกษาด้วยครับ ได้เอามาเป็นเนื้อหาบทความหลาย ๆ อันเลย 5555 ปล. มาพิมพ์ดักไว้ก่อนว่าทำไมในเมื่อถามพี่ ๆ เขาแล้วไม่เอาคำตอบมากางกันเลยล่ะ ว่าพี่ ๆ เขาตอบว่าอะไร เผื่อจะเป็นประโยชน์กับผู้อ่านมากขึ้น อันนี้ตอบแบบตรงไปตรงมาคือคำตอบของพี่ ๆ มันทำให้นิลเขียนได้เยอะมากกกกก อาจจะเอาไปแทรก ๆ ไว้ตามบทความอื่น ๆ ยังไงก็ติดตามกันในอนาคตได้ครับ ขอให้ทุกคนกล้าออกไปลุยกับสิ่งใหม่ ๆ นะครับ นิล --- # การ Set Expectation ในการทำงาน - URL: https://blog.ninprd.com/blog/clear-expectation-at-work/ - Published: 2023-07-28 - Tags: experience-sharing - Summary: ความคาดหวัง น่าจะเป็นสิ่งที่คนทำงานหลาย ๆ คนละเลยมันไป บางคนคิดว่าก็ทำงานให้เสร็จ ๆ ไปพี่ ๆ Senior ก็น่าจะพอใจแล้วไม่ใช่หรอ หรือบางคนก็คิดว่าต้องพัฒนางานระดับ Premium ออกมา ใช้เวลานานมาก แต่ Senior หรือ PM ไม่พอใจ สิ่งเหล่านี้ทั้งหมดขับเคลื่อนด้วยสิ่งที่เรียกว่า ”ความคาดหวัง” ครับ ความคาดหวัง น่าจะเป็นสิ่งที่คนทำงานหลาย ๆ คนละเลยมันไป บางคนคิดว่าก็ทำงานให้เสร็จ ๆ ไปพี่ ๆ Senior ก็น่าจะพอใจแล้วไม่ใช่หรอ หรือบางคนก็คิดว่าต้องพัฒนางานระดับ Premium ออกมา ใช้เวลานานมาก แต่ Senior หรือ PM ไม่พอใจ สิ่งเหล่านี้ทั้งหมดขับเคลื่อนด้วยสิ่งที่เรียกว่า ”ความคาดหวัง” ครับ สวัสดีทุกคนที่อ่านด้วยนะครับ แล้วก็ขอโทษที่หายไปเกือบเดือน พอดีนิลป่วยบ่อย เนื้อหาของบทความนี้นิลได้แรงบันดาลใจจากการคุยกับ Direct Manager ของนิลนะครับ ตอนช่วงแรก ๆ ที่นิลทำงาน ร่วมกับตอนที่นิลทำงานได้ซักพักและเริ่มสังเกตว่า “ความคาดหวัง” มันสำคัญขนาดนั้นจริง ๆ หรอ ## อะ ลองยกตัวอย่างให้เห็นภาพซักหน่อย นิลอาจจะยกตัวอย่างในมุม Dev นะครับ บางทีเวลาที่เราได้รับงานจาก Product Manager (PM) หรือว่า Senior เนี่ย เราจะคิดว่าจะใช้เวลากี่วัน มันจะทันกับ Timeline ที่เขาให้มาไหม แล้วเราก็ไปทำตามที่เราคิดมา ซึ่งบางทีเราอาจจะไม่ได้ถามกลับไปหาคนที่มอบงานให้เราเลยว่าเขาคิดว่าเราจะใช้เวลากี่วัน เราอาจจะบอกเขาว่าเราจะใช้ประมาณ 4 วัน พี่เขาก็ Say Yes มา เราก็ไปทำมา จะใช้เวลากี่วันก็แล้วแต่แหละ แต่สุดท้ายเราก็จะรู้สึกว่างานเสร็จ แต่ทางคนที่มอบหมายงานมาอาจจะมีความรู้สึกประหลาดใจที่งานเสร็จเร็วกว่าที่คิด หรืออาจจะหงุดหงิดที่งานเสร็จช้ากว่าที่คิดก็ได้ จากตรงนี้คนอาจจะแบบ เอ้า! ก็ทางคนมอบหมายงานไม่ได้บอกความคาดหวังของตัวเองนี่นา คนทำงานก็ไม่มีทางรู้หรอก แต่ในความเป็นจริงแล้ว ถ้าเราสามารถถามเพื่อดูความคาดหวังของคนมอบงานแล้วทำให้เรากับเขาเห็นภาพเดียวกัน เราจะสามารถสร้างความพึงพอใจให้กับทั้งผู้มอบงานและตัวเราด้วยครับ ทีนี้ถ้าลองเอาสิ่งที่นิลพูดมาทั้งหมดมาลองวาดเป็น Chart ดู สุดท้ายแล้วนิลได้ภาพประมาณนี้ ไม่รู้ว่าคนอื่นจะพอเข้าใจไหมนะ ![graph-summarizing-expectation-bar](assets/expectation-at-work-image-2.webp) ## สรุป จริง ๆ ที่เล่ามานี้อาจจะไม่ Cover ใน Case อื่น ๆ แต่อย่างไรก็ดี จากภาพก็แสดงให้เห็นแล้วว่าแค่เราทำให้ภาพของคนที่มอบงานให้เรากับเรานั้นตรงกันก็สามารถทำให้ทั้ง 2 ฝ่ายสามารถทำงานกันได้อย่างตรงเป้าประสงค์ของตนเอง รวมทั้งที่เล่ามาทั้งหมดไม่ได้มีความอยากให้คนชุ่ยหรือขยันจนเกินไปนะครับ แต่อยากให้ทุกคน set clear expectation ระหว่างเรากับผู้มอบหมายงานเพื่อให้รู้สึกคุ้มค่ากับความพยายามและเวลาที่เราลงแรงไปกับงานนั้นนะครับ 🙂 --- จบไปอีกบทความแล้ว ขอบคุณสำหรับ Comment และ Feedback ที่มีให้ในบทความที่แล้วนะครับ ก่อนหน้านี้ผมพยายามจะทำ Content เป็นรายอาทิตย์แต่ก็ยังติดหล่มความขี้เกียจกับป่วยอยู่บ่อยครั้งครับ ยังไงจะพยายามหา Pace ที่เหมาะสมและมาเขียนอะไรให้ทุกคนอ่านเรื่อย ๆ นะครับ ถ้ามี Topic ไหนที่อยากอ่านกันเป็นพิเศษก็สามารถ Comment กันมาได้เลยนะครับ อยากรู้เหมือนกันว่าอยากอ่านอะไรกัน หรือถ้ามีอะไรอยากจะบอกก็ Comment มาก็ได้นะครับ ขอให้ทุกคนมีความสุขกับการทำงานกันนะครับ นิล --- # สีเหลืองเยลโล่ว 1 ปีกับ Skooldio - URL: https://blog.ninprd.com/blog/1-year-at-skooldio/ - Published: 2023-06-17 - Tags: experience-sharing - Summary: รู้สึกแปลก ๆ กับการมาเล่าเรื่องแบบนี้แฮะ ก่อนอื่นขอแนะนำตัวก่อนนะ ชื่อนิลนะครับ ตอนนี้เป็น Software Engineer ที่ Skooldio และก็อย่างที่ชื่อบทความเขียนไว้เลย ผมเพิ่งทำงานครบ 1 ปีพอดีเลยอยากมาแชร์ประสบการณ์การทำงานของตัวเอง แต่อาจจะเกริ่น Background ตัวเองซักนิดนึงนะครับ รู้สึกแปลก ๆ กับการมาเล่าเรื่องแบบนี้แฮะ ก่อนอื่นขอแนะนำตัวก่อนนะ ชื่อนิลนะครับ ตอนนี้เป็น Software Engineer ที่ Skooldio และก็อย่างที่ชื่อบทความเขียนไว้เลย ผมเพิ่งทำงานครบ 1 ปีพอดีเลยอยากมาแชร์ประสบการณ์การทำงานของตัวเอง แต่อาจจะเกริ่น Background ตัวเองซักนิดนึงนะครับ ## **เล่า Background คร่าว ๆ** นิลจบ Industrial Engineering (IE) จุฬาฯ ระหว่างเรียนตอนจบปี 3 ได้มีโอกาสไปฝึกงานแบบสหกิจศึกษา (ฝึกงาน 6 เดือน โดยจะเป็นการทำ Senior Project ร่วมกับทางบริษัท) ที่ True Digital Group ในตำแหน่ง Full Stack Developer ตอนนั้นได้ทำโปรเจคเป็นระบบ Telemedicine ขนาดย่อมโดยใช้ NuxtJS กับ NodeJS + Express แล้วรู้สึกว่าสนุกกว่าสิ่งที่ตัวเองเรียนมามาก นิลเลยตัดสินใจเบนสายไปทาง Software Engineer เลย หลังจากนั้นก็ได้สมัครเข้าทำงานและตัดสินใจมาทำที่ Skooldio ในตำแหน่ง Software Engineer ครับ ### **ทำไม Skooldio?** จริง ๆ นิลติดตามเพจ Skooldio ตั้งแต่นิลอยู่ปี 1 แล้ว ตอนนั้นนิลยังเห็น Skooldio เป็นแค่เพจขายคอร์ส (ที่ค่อนข้างมีราคาประมาณนึง 555) กับเพจที่แนะนำ Tips และ Tricks ต่าง ๆ ในการทำงานเท่านั้นเอง แต่นิลก็คิดว่าเป็นเพจที่ดีนิลเลยติดตามมาเรื่อย ๆ และสัมผัสได้ถึงพลังงานที่สนุกสนานจากคอนเทนต์ต่าง ๆ ในหน้าเว็บ ประกอบกับการที่ที่บริษัททำเกี่ยวกับการศึกษาที่เป็นส่วน Reskill Upskill ทำให้นิลรู้สึกว่าที่นี่น่าจะมี Environment การทำงานที่สนุกและท้าทายแน่ ๆ เลย เลยสนใจที่นี่มากครับ ### **เข้ามาทำงานเป็นยังไงบ้าง?** ต้องบอกก่อนว่านิลได้เข้ามาทำในทีม PoC (Proof of Concept) ของบริษัทซึ่งเป็นทีมขนาดเล็ก (ในทีมมี Dev 2 คน) โดยเป้าประสงค์ของ Team เราคือการสร้างของไว ๆ (ทุก Product ที่ทำไปมี Roadmap วางไว้นะไม่ได้ทำอะไรพร่ำเพรื่อ) เพื่อออกไปลองตลาดว่ามันขายได้หรือไม่ได้ เพราะงั้นเวลาเราได้พัฒนาของใหม่ ๆ ออกไปเนี่ย มันสนุกมากเลย ได้ลองเล่น Library ใหม่ ๆ ลอง Tech Stack อื่น ๆ ที่อาจจะไม่ได้ใช้ในบริษัทก่อนหน้านี้แล้วก็เอามาคุยกับพี่ใน Team ว่าเราจะลองใช้อันนี้ไหม ใช้อันนู้นใน Project เราไหม และก็ได้รู้ Process ตั้งแต่ขึ้น Repository ใหม่อีกด้วย นอกจากนี้เรายังได้มีโอกาสไปทำงานกับทีมอื่น ๆ เพื่อร่วมพัฒนาของที่มีอยู่ หรือไปช่วยเขา Research ของอะไรเร็ว ๆ ด้วยครับ พี่ใน Team ก็คอยช่วยเหลือกันตลอด รู้สึกว่าโชคดีมากได้อยู่ใน Team ที่ท้าทายและสนุกมากครับ รู้สึกว่าได้เรียนรู้อะไรใหม่ ๆ ตลอด โคตรมันส์ โคตรโหด โคตรอันตราย 💪 ![image-generated-by-ai](assets/1-year-at-skooldio-image-2.webp) ### **ข้ามสายมา ทำงานเป็นยังไงบ้าง?** อันนี้หลายคนก็ถามนะว่าข้ามจาก IE มาทำ Dev เนี่ย มึนหรือเปล่า หรือว่าตามคนอื่นไม่ทันหรือเปล่า? อันนี้นิลตอบตรง ๆ ว่าตอนแรกนิลรู้สึกว่านิลตามคนอื่นไม่ทันเลย รู้สึกว่าต้องไปหาอะไรมาเรียนรู้เพิ่มจนกว่าจะตาม Dev คนอื่นให้ทัน สุดท้ายตอนที่คุยกับพี่ Manager พี่เขาก็ Reflect กลับมาว่าจริง ๆ แล้วนิลก็ทำงานได้ตามที่ Senior/Manager เขาคาดหวังแล้วนะ แบบอาจจะไม่ต้องกดดันตัวเองขนาดนั้น ตอนนี้ก็เลยรู้สึกผ่อนคลายมากขึ้น แต่เราก็ต้อง Upskill เราไปเรื่อย ๆ แหละ 🔥 ### **ทำงานมา 1 ปีมี Burn out บ้างไหม?** ไม่ถึงขั้นหมดไฟขนาดนั้น รู้สึกแค่ไม่มีความสุขเป็นบางช่วงครับ อาจจะเพราะว่านิล Dev เป็นงานหลัก Hobby และ Freelance ด้วย นิลเลยรู้สึกหมดสนุกหรือเบื่อในบางครั้ง แต่ทุก ๆ ครั้ง แค่ไปนั่งผ่อนคลายซักวัน 2 วัน นั่งเรียนอะไรชิว ๆ ไป ปรึกษา Manager หรือไปนั่งดูเว็บอื่น ๆ แล้วเห็นอะไรที่น่าสนใจก็จะกลับมาลุยต่อได้ตลอดครับ ยังไม่รู้สึก Completely Burn Out ขนาดนั้น ### **ทำไมต้องสีเหลืองเยลโล่ว?** โอเค อ่านกันมาถึงตรงนี้แล้วหลาย ๆ คนอาจจะงงการตั้งชื่อบทความของผมว่าสีเหลืองเยลโล่วมันไปอยู่บนนั้นได้ยังไง ต้องเล่าไปถึงตอนที่นิลสมัครมาทำงานที่นี่ นิลสมัครผ่านโครงการ Skooldio Day Zero ที่จะมี Form ให้กรอกและพอนิลได้กรอกไป นิลก็ไปสะดุดกับหัวข้อนึงที่เขียนอารมณ์ประมาณว่า _“กรุณาแนะนำตัวเองที่นอกเหนือจากใน Resume”_ นิลก็เขียนไปเรื่อย ๆ ซักพักพอจะจบ นิลจบไม่ลง และก็คิดขึ้นมาได้ว่านิลอยาก Express ความตลกและสนุกของตัวเองไปด้วย นิลเลยเขียนประโยคท้ายลงไปว่า “ผมชอบดูมุขตลกครับ เช่น สีเหลืองเยลโล่ว บริษัทที่อยากเข้า Skooldio ผ่ามมม” นั่นละฮะ นิลเลยเอาข้อความตรงนั้นมาตั้งเป็นชื่อของบทความนี้ (อย่าเอาเป็นเยี่ยงอย่างนะ แหะ ๆ) ### **สุดท้ายละ มา Part ขอบคุณดีกว่า** ขอบคุณเพื่อนร่วมงานทุกคน พี่ ๆ Manager และพี่ ๆ ในบริษัททุกคนมากครับ ทุกคนใจดีมากเลย ขอบคุณที่ Support นิลในหลาย ๆ เรื่อง โดยเฉพาะ Direct Manager ของนิลที่คอยเป็นที่ปรึกษาให้ตลอด เป็น 1 ปีที่ยอดเยี่ยมครับ 555 หวังว่าเราจะได้ลุยไปด้วยกันต่อในปีถัด ๆ ไปนะครับทุกคน (ถ้ามีคนในบริษัทมาอ่านอะนะ 5555) 🌟 --- จบไปแล้วกับบทความแรกนะครับ บทความนี้เหมือนเป็นการเริ่มที่จะเปลี่ยนบางอย่างของนิล และก็เป็นการอยากแชร์ประสบการณ์ครั้งแรกจากคนที่รู้สึกว่าตัวเองพูดไม่รู้เรื่อง 555 ยังไงถ้าใครรู้สึกยังไงก็สามารถมา Comment ติชมกันได้นะครับ จริง ๆ ตอนแรกบทความมันยาวกว่านี้เลยตัดออกไปเยอะอยู่ อยากเล่าแต่กลัวตัวเองพูดไม่รู้เรื่อง ถ้า Comment มาบอกกันก็จะช่วยและเป็นกำลังใจในการเริ่มที่ดีมากเลยครับ ขอบคุณทุกคนที่อ่านกันมาถึงตรงนี้ครับ 🙂 นิล